STM32海创电子物联网项目一

C语言基础:

格式说明符:

printf 函数的格式说明符:

  • %d:用于打印一个十进制的整数。

  • %i:与 %d 相同,用于打印一个十进制的整数。

  • %u:用于打印一个十进制的无符号整数。

  • %x:用于打印一个十六进制的整数(小写字母)。

  • %X:用于打印一个十六进制的整数(大写字母)。

  • %o:用于打印一个八进制的整数。

  • %f:用于打印一个浮点数(小数)。

  • %e 或 %E:用于打印一个科学计数法表示的浮点数。

  • %g 或 %G:用于打印一个浮点数,根据数值的大小自动选择 %f 或 %e 格式。

  • %s:用于打印一个字符串。

  • %c:用于打印一个字符。

  • %p:用于打印一个指针的值。

  • %%:用于打印 % 符号本身。

scanf 函数的格式说明符:

  • %d:用于读取一个十进制的整数。
  • %i:与 %d 相同,用于读取一个十进制的整数。
  • %u:用于读取一个十进制的无符号整数。
  • %x:用于读取一个十六进制的整数。
  • %o:用于读取一个八进制的整数。
  • %f:用于读取一个浮点数。
  • %s:用于读取一个字符串。
  • %c:用于读取一个字符。
  • %p:用于读取一个指针的值(通常不推荐使用)。

附加说明:

  • %n:用于 printf 和 scanf%n 会将到目前为止输出/输入的字符数赋值给 n 所指向的变量。
  • %*[格式]* 表示忽略对应的输入/输出,不存储。
  • %[范围]c[范围] 表示读取字符直到遇到指定的字符范围之外的字符。
  • %[范围]s[范围] 表示读取字符串直到遇到指定的字符范围之外的字符。
  • 例如:

  • %05d:打印一个至少5位的整数,不足部分用0填充。
  • %6.2f:打印一个浮点数,总宽度至少为6位,小数点后保留2位。
  • %10s:打印一个字符串,宽度至少为10位,如果字符串长度不足10位,则左侧用空格填充。

指针操作:

地址:类比于一个房间

数据:类比于一个房间的椅子

数组与指针:

在 C 语言中,指针和数组紧密相关。当有一个指向数组第一个元素的指针时,可以通过下标来访问数组的元素,就像使用数组名一样。

例如:

unsigned char mqtt_TxBuff[7][400];
unsigned char *mqtt_TxInPtr;

mqtt_TxInPtr=mqtt_TxBuff[0]时,那么可以使用mqtt_TxInPtr[0]来表示mqtt_TxBuff[0][0],mqtt_TxInPtr[1]来表示mqtt_TxBuff[0][1].

相当于mqtt_TxInPtr[0]表示的是mqtt_TxBuff[0][0]内元素的值,而不是地址。但只能把mqtt_TxInPtr[0]和mqtt_TxBuff[0][0]互换使用,不能当作完全相同的东西

 指针和二维数组:

在一维数组中,例如b[12],b是一个数组名,可以代表数组的首地址,之后的地址b+1,b+2

在二维数组中,例如a[3][4],三行四列,每一行地址用a[0]、a[1]、a[2]表示,每行内元素的地址为

a[0]+1、a[0]+2...

 枚举类型enum:

定义一个枚举类型,它会自动赋予(默认从0开始)每个常量分配了自定义的整数值,依次递增(也可以自定义需要自己全部写出来)。

Strlen和Sizeof的区别:

memcpy:

printf和sprintf的区别:

 memset函数和strstr函数:

strcopy是将每个字符存放在数组中,str[0]=h,str[1]=a...

memset主要用于清零和初始化的作用

 1、STM32基础

对寄存器的操作:

以配置GPIO为例

1、打开端口对应的时钟;

2、配置输出模式;

3、输出电平。

每一步都是:查找基地址+偏移地址,再进行配置。

例子:打开PC13,配置成低电平。

第一步:配置PC13的时钟

因为GPIOC_PC13属于APB2,选择端口C的时钟

首先找到地址:基地址为:0x40021000+偏移地址:0x18=实际地址:0x40021018

再对地址中具体的位进行操作:

打开端口C的时钟,首先将0x40021018转换为单片机能识别的地址

(unsigned int*)0x40021018

将地址里面的值取出来

*(unsigned int*)0x40021018

再改变里面的第四位(配置时钟完成)

*(unsigned int*)0x40021018|=(1<<4);

第二步:配置输出、输出模式

3、输出低电平

最终的代码:

对结构体的操作:

最终:

模块化:

编写.C文件

再编写.h文件

编写完成后一定要添加相应的抬头

库函数初始化函数的分析:

1、配置RCC

2、配置结构体

GPIO_InitStruct为结构体指针类型,需要对里面的成员进行赋值;结构体对引脚、引脚功能进行配置(都属于配置引脚),类型不同,所以需要在初始化时加上"&"的符号。

GPIOx为结构体类型,成员类型相同,只需要赋予结构体的地址,他的每个成员就有明确的地址,但它本身就是一个地址,所以不用取地址&的符号。

用标准库点亮一个LED灯:

配置的函数不能弄错(犯的第一个出错误)

模块化的步骤:

1、在USER文件夹添加.c和.h文件

不能自己在项目里添加,不然文件会保存到工程文件夹下。

2、3添加头文件路径

4、编写.C和.H文件

5、完成主函数

软件仿真和硬件仿真的设置:

首先点击Flie→Device database找到所使用的单片机类型

将DLL、Parameter复制到对应位置

点击ST_Link Debugger设置

调试过程:

打开对应的设置,查看相应程序的运行顺序

打开软件的示波器,可以观察对应波形的变化

STM32的中断:

中断用前四个位来表示优先级,两个为抢占优先级、两个为响应优先级

中断需要先考虑抢占优先级、再考虑响应优先级

SYSTICK定时器:

原理:

一般选用9M的频率(1s  9*10^6次)的时钟,首先赋值重装载寄存器,清空递减计数器并赋值。

所用到的寄存器:

STK_VAL控制寄存器:

STK_LOAD重装寄存器:

STK_VAL递减计数器:

编程思路(延时1s):

使用库函数延时(1s):

VAL寄存器以及LOAD寄存器都是24位的,它的最大值是1111 1111 1111 1111 1111 1111,转化乘十进制后是16777215。即装载的最大十周周期个数为16777215。

TIM定时器:

基本介绍:

PSC+1的原因:预分频器的工作方式是,每当定时器时钟源(比如内部时钟)“tick”一次,预分频器计数器的值就会增加1,直到达到预分频器设定的值(PSC值),然后计数器会再“tick”一次后归零,同时计数器(CNT)的值增加1。因此,为了得到实际的分频系数,需要在PSC的设定值上加1。

预分频器的作用:

1、降低时钟频率,以满足慢需求;

2、提高定时器的精度;

3、减小计数器的溢出

4、节能、提高兼容性、灵活性

定时器配置:

功能实现:

写定时器必须要写对应的中断

UART串口相关理论:

相关理论:

功能实现:

TXE标志位:

TC标志位:

因为状态寄存器(USART_SR)的复位值为0x00C0,TC在最开始就被置1了,所以在执行过程中,造成发送的第一个数据丢失。

实验代码和现象:

修改程序:清除TC位

发送一个字符串:

代码实现和实验现象:

接收一个字符串:

2、DH11模块

基本介绍:

传输过程:

 总体过程:

DHT11的初始化,在MCU复位完成后,单片机与DH11进行输入输出切换。 

发送数据:

结束:

代码部分:

MCU复位配置:

DH11初始化:

DH11为从机,初始化需要受到主机的监控,这样初始化主机才认为你的响应是成功的

单片机接受1位:

单片机接受一个字节:

单片机接受五个字节:

巧用printf函数:

执行printf函数需要几十us的时间,所以在时间精确到us的函数里面,不适合使用printf。

温湿度传感器中printf设置的delay时间一般间隔时间设置为1.1s。

3、IIC通信协议

相关理论:

注意:要读取(输入或者输出)SDA上的数据(SDA保持稳定),SCL必须是高电平

代码部分:

起始信号:

数据传输:

OLED的第一个位包括地址、读写位等信息,由于IIC通信上的从机是与的关系,需要主机发送一个地址和读写信号,让对应的从机识别并操作。

代码和现象:

OLED引脚初始化:

产生IIC起始信号:

要先配置引脚的状态

产生IIC终止信号:

写入一个字节:

验证从机是否存在:

IIC上的每一个设备都会有一个固定的地址(查看参考手册),当主机在总线上发送一个地址,对应的从机识别后,会发送一个应答信号给主机(也就是这里的IIC_Write函数的功能中最后返回的应答位)

主函数:

实验现象:

4、OLED液晶屏

基本知识:

单片机通过控制SSD1306芯片控制OLED,通过IIC接口通信。

显示字符、汉字:

理论部分:

程序部分:

显示数字:

最终效果:

5、ESP8266WIFI

基本介绍:

6、MQTT理论

基本概念:

MQTT是一个云服务平台的协议,可以与不同的地方进行通信。

物联网平台下的名字解释:

具体操作:

1、创建阿里云平台

CONNECT报文-固定报头:

??表示最后CONNECT报文后面还有多少个字符,将字符数量化为16进制就是??的值。

CONNECT报文-可变报头:

CONNECT报文-有效载荷:

MQTT---CONNECT连接_mqtt--- connect连接-优快云博客

剩余长度:

服务质量:

订阅主题和订阅确认:

操作与CONNECT报文一致:

订阅确认:

返回0A是因为订阅主题的可变报头是0A

取消订阅与取消订阅确认:

发布消息与发布确认:

7、C语言实现CONNECT报文:

固定报头和可变报头部分:

固定的直接用数组存储即可,剩余长度为可变部分,用函数计算出长度即可。

当剩余长度超过128时,进行判断:

对remaining_len进行判断,低字节在前面,高字节在后面

例如:当remaining_len=256时。(如果超过128,低位中,要将第八位置1所以要与上0x80)

有效载荷部分:

客户端标识符:

【00+客户端标识符+客户端】

用户名:

【00+用户名标识符+用户名】

密码:

【00+28+密码】

代码部分:

while中的代码有错

应该是len=remaining_size%128;

remaining_size=remaining_size/128。

这里应该是

len=remaining_size%128;

remaining_size=remaining_size/128.

8、数据发送机制

通过WIFI端口,更改TCP和端口连接阿里云服务器。

模型部分:

容器的介绍:

发送的思路:

1、单片机发送数据给容器;

2、容器再发送数据给单片机;

判断是否有新命令的思路:

首先在一开始定义mqtt_TxInPtr=mqtt_TxOutPtr;

当单片机发送数据给容器时,执行命令mqtt_TxInPtr+=400,使得mqtt_TxInPtr会移到下一行,使得mqtt_TxInPtr≠mqtt_TxOutPtr(表明有新数据),再通过mqtt_TxOutPtr指针把数据发送出去;

发送完成后,mqtt_TxOutPtr也会移到下一行数据,从而又使得mqtt_TxInPtr=mqtt_TxOutPtr,为下一次数据做准备。

 每行数据的前两位表示数据的长度,从第三位开始才是真正的数据

代码实现部分:

初始化容器与指针:

单片机发送数据到容器:

容器发送数据到阿里云:

主函数进行判断是否新数据和数据发送的功能是什么

总体代码:

9、数据接收机制

将发送WiFi模块的每个指令返回一个值用于判断是否连接成功,主函数的主题部分分为

if 连接上WiFi模块做什么

else 没连接上要做什么

模型部分:

 数据接收过程:

代码部分:

1、首先建立一个接收容器

2、通过USAT2接收数据

首先在连接上阿里云服务器之前,主要用于WiFi接收数据;

USAT2的中断函数:当USAT2接收到数据时,会触发中断;将接收到的数据存放在USAT2_Buff[]容器中(缓冲区),并通过USAT2_RxCounter统计接收的字节数。

其次在连接上阿里云服务器之后;

用TIM4定时器判断是否一组数据,(函数if部分为未连接上阿里云服务器之前的USAT2执行的中断,else为连接上之后USAT2执行的中断)。

首次在接收到第一个数据后,开启TIM4定时器,然后继续接收数据,由于每接收一个字节都会对TIM4定时器进行清零,直到接收到下一组数据中,间隔时间超过40ms,触发TIM4定时器的中断。

数据被存在USART2_RxBuff[]中,数据的字节个数被存在USART2_RxCounter中。

TIM4定时器中断:

将USART2_RxBuff[]数据发送到容器中,同数据发送机制一样

3、主函数对接收容器中的数据进行判断

判断接收到的数据是否有对应的字节,输出相应的响应

10、订阅报文的发送

模型部分:

通过标志位来依次发送:

1、WiFi连接成功后,将Connect_flag置1;

2、Connect_flag为1时,发送Connect报文,成功后将ConnectPack_flag置1;

2、ConnectPack_flag为1时,发送SUBCRIBE报文,成功后将Subcribe_flag置1。

代码部分:

编写订阅报文部分:

主函数部分:

11、Ping报文

模型部分:

在订阅成功后,将Subcribe_flag置1,然后发送Ping报文,利用TIM3定时器三实现每隔30秒发送一次Ping报文。

代码部分:

Ping代码的优化部分:

使用一个标志位Ping_Flag去进行判断,产生中断后对Ping_Flag++,然后接收响应后在主函数置零。

如果没有响应,则间隔发送或者重新将WIFI标志位置零,重新连接。

12、Publish报文功能实现

模型描述:

程序部分:

主体函数思路:

Publish报文:

实验结束20241205

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值