STM32通过esp8266连接WiFi接入MQTT服务器

简介: STM32通过esp8266连接WiFi接入MQTT服务器

上文我们讲到如何搭建本地MQTT服务器,现在介绍如何通过stm32连接MQTT

一.首先我们初始化esp8266这里我们使用的是USART4与其通信代码如下

1. void UART4_Init(uint32_t bound)
2. {
3.  GPIO_InitTypeDef GPIO_InitStructure;
4.  USART_InitTypeDef USART_InitStructure;
5. 
6. 
7.  RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE); //使能UART4,GPIOA时钟
8.  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
9. 
10.   USART_DeInit(UART4);  //复位串口4
11. 
12.   //UART4_TX   PC.10 
13.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; 
14.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
15.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
16.   GPIO_Init(GPIOC, &GPIO_InitStructure); //初始化PC10
17. 
18.   //UART4_RX    PC.11
19.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
20.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
21.   GPIO_Init(GPIOC, &GPIO_InitStructure);  //初始化PC11
22. 
23.   //USART 初始化设置
24.   USART_InitStructure.USART_BaudRate = bound; //设置波特率,一般设置为9600;
25.   USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字长为8位数据格式
26.   USART_InitStructure.USART_StopBits = USART_StopBits_1;  //一个停止位
27.   USART_InitStructure.USART_Parity = USART_Parity_No; //无奇偶校验位
28.   USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无硬件数据流控制
29.   USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
30. 
31.   USART_Init(UART4, &USART_InitStructure); //初始化串口
32.   USART_ITConfig(UART4, USART_IT_RXNE, ENABLE);//开启中断
33.   USART_Cmd(UART4, ENABLE);                    //使能串口 
34. 
35. 
36.   TIM7_Int_Init(100-1,7200-1);    //10ms 为了判断是不是一串数据后文有解释
37. 
38.   TIM_Cmd(TIM7,ENABLE);     //
39. }

二.通过数据间隔时间来判断是否是一串数据如果间隔时间大于30ms则判定为不是一串数据,接收缓冲器清零。 代码如下!

1. //定时器7中断服务程序       
2. void TIM7_IRQHandler(void)
3. {  
4.  if (TIM_GetITStatus(TIM7, TIM_IT_Update) != RESET)//是更新中断
5.  {
6. 
7.    TIM_ClearITPendingBit(TIM7, TIM_IT_Update  );  //清除TIM7更新中断标志    
8.      if(F_UART4_RX_RECEIVING)//正在接收串口数据
9.    {
10.       UART4_RX_TIMEOUT_COUNT++;//串口超时计数
11.       if(UART4_RX_TIMEOUT_COUNT>3)//数据接收间隔超过30ms
12.       {//串口接收完成或结束
13.         F_UART4_RX_RECEIVING=0;
14.         UART4_RX_TIMEOUT_COUNT=0;
15.         F_UART4_RX_FINISH=1;
16.       }
17.     }
18.   }     
19. }
20. 
21. 
22. //定时器溢出时间计算方法:Tout=((arr+1)*(psc+1))/Ft us.
23. //Ft=定时器工作频率,单位:Mhz 
24. //通用定时器中断初始化
25. //这里始终选择为APB1的2倍,而APB1为36M
26. //arr:自动重装值。
27. //psc:时钟预分频数     
28. void TIM7_Int_Init(u16 arr,u16 psc)
29. { 
30.   NVIC_InitTypeDef NVIC_InitStructure;
31.   TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
32. 
33.   RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE);//TIM7时钟使能    
34. 
35.   //定时器TIM7初始化
36.   TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值 
37.   TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
38.   TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
39.   TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
40.   TIM_TimeBaseInit(TIM7, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位
41. 
42.   TIM_ITConfig(TIM7,TIM_IT_Update,ENABLE ); //使能指定的TIM7中断,允许更新中断
43. 
44.   TIM_Cmd(TIM7,ENABLE);//开启定时器7
45. 
46.   NVIC_InitStructure.NVIC_IRQChannel = TIM7_IRQn;
47.   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0 ;//抢占优先级0
48.   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;    //子优先级2
49.   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;     //IRQ通道使能
50.   NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
51. 
52. }

三.初始化esp8266后我们就可以连接WiFi及mqtt了

首先我们将esp8266设置为station模式,如果返回ok则设置成功

代码如下:

1. #define AT_CWMODE  "AT+CWMODE=1" //设置为“station”模式
2. int8_t ESP8266_SetStation(void)
3. {
4.  ClrAtRxBuf();//清空缓存
5.  SendAtCmd((uint8_t *)AT_CWMODE,strlen(AT_CWMODE));
6.  delay_ms(100);
7.  if(strstr((const char *)AT_RX_BUF, (const char *)"OK") == NULL)
8.  {
9.    return -1;
10.   }
11.   return 0;
12. }

四.设置成功之后就可以连接WiFi(可以是路由器也可以是手机或电脑开热点)

代码如下:

1. /*******************************************************************
2. *函数:int8_t ESP8266_SetAP(void)
3. *功能:设置ESP8266要连接的热点名称和密码
4. *输入:char *wifi-热点名称 char *pwd-热点密码
5. *输出:
6.    return = 0 ,sucess
7.    return < 0 ,error
8. *特殊说明:
9. *******************************************************************/
10. #define WIFI_AP   "dmx"//WiFi热点名称       
11. #define WIFI_PWD  "88888888"  //WiFi密码
12. 
13. int8_t ESP8266_SetAP(void)
14. {
15.   uint8_t AtCwjap[MAX_AT_TX_LEN];
16.   memset(AtCwjap, 0x00, MAX_AT_TX_LEN);//清空缓存
17.   ClrAtRxBuf();//清空缓存
18.   sprintf((char *)AtCwjap,"AT+CWJAP=\"%s\",\"%s\"",WIFI_AP, WIFI_PWD  );
19.   SendAtCmd((uint8_t *)AtCwjap,strlen((const char *)AtCwjap));
20.   delay_ms(5500);
21.   if(strstr((const char *)AT_RX_BUF, (const char *)"OK") == NULL)
22.   {
23.     return -1;
24.   }
25.   return 0;
26. }

五.现在就已经成功连接WiFi了下一步连接本地mqtt服务器(上篇博客我教大家如何搭建的)

1. #define SERVER_PC_IP "172.16.40.36"  //服务器IP地址
2. #define SERVER_PC_PORT 1883      //服务器端口号   
3. int8_t ESP8266_IpStart(void)
4. {
5.  uint8_t IpStart[MAX_AT_TX_LEN];
6.  memset(IpStart, 0x00, MAX_AT_TX_LEN);//清空缓存
7.  ClrAtRxBuf();//清空缓存
8. 
9.  /**************配置MQTT_USER信息***************/
10.   //AT+MQTTUSERCFG=0,1,"用户ID","账号","密码",0,0,""
11.                          //AT+MQTTUSERCFG=0,1,\"M3\",\"\",\"\",0,0,\"\"
12.   sprintf((char *)IpStart,"AT+MQTTUSERCFG=0,1,\"M3\",\"\",\"\",0,0,\"\"");
13.   SendAtCmd((uint8_t *)IpStart,strlen((const char *)IpStart));
14.   delay_ms(1500);
15.   printf("IpStart-USER_Config: %s\r\n", (char *)AT_RX_BUF);
16.   if(strstr((const char *)AT_RX_BUF, (const char *)"OK") == NULL)
17.   {
18.     /******断开连接*****/
19.     memset(IpStart, 0x00, MAX_AT_TX_LEN);//清空缓存
20.     ClrAtRxBuf();//清空缓存
21. 
22.     //AT+MQTTCLEAN=0
23.     sprintf((char *)IpStart,"AT+MQTTCLEAN=0");
24. 
25.     SendAtCmd((uint8_t *)IpStart,strlen((const char *)IpStart));
26. 
27.     return -1;
28.   }
29. 
30.   /**************建立MQTT连接***************/
31.   memset(IpStart, 0x00, MAX_AT_TX_LEN);//清空缓存
32.   ClrAtRxBuf();//清空缓存
33. 
34.   //AT+MQTTCONN=0,"服务器IP",1883,0
35.   //AT+MQTTCONN=0,"172.16.40.36",1883,0
36.   sprintf((char *)IpStart,"AT+MQTTCONN=0,\"%s\",%d,0",SERVER_PC_IP, SERVER_PC_PORT  );
37. 
38.   SendAtCmd((uint8_t *)IpStart,strlen((const char *)IpStart));
39.   delay_ms(1500);
40.   printf("IpStart-MQTT_Connect: %s\r\n", (char *)AT_RX_BUF);
41.   if(strstr((const char *)AT_RX_BUF, (const char *)"OK") == NULL)
42.   {
43.     return -2;
44.   }
45. 
46.   return 0;
47. }

六.经过以上五步就已经成功连接mqtt服务器了。现在通过命令设置自己为订阅者

1. int8_t ESP8266_MQTT_Sub(char *topic) //主题自己设置
2. {
3.  int8_t error = 0;
4.  uint8_t IpSend[MAX_AT_TX_LEN];
5.  memset(IpSend, 0x00, MAX_AT_TX_LEN);//清空缓存
6.  ClrAtRxBuf();//清空缓存
7. 
8. 
9.  //AT+MQTTSUB=0,M3",0
10.   sprintf((char *)IpSend,"AT+MQTTSUB=0,\"%s\",1", topic);
11.   SendAtCmd((uint8_t *)IpSend,strlen((const char *)IpSend));
12.   delay_ms(1500);
13.   printf("MQTT_Sub_Ack: %s\r\n",AT_RX_BUF);
14.   if(strstr((const char *)AT_RX_BUF, (const char *)"OK") == NULL)
15.   {
16.     return -4;
17.   }
18. 
19.   return error;
20. }

在这里我们通过mqtt.fx同样连接本地搭建的服务器,作为一个发布者发送消息stm32就能收到了。不过此处还没写收到信息的代码

七.stm32作为发布者者代码,这边你可以开一个mqtt.fx订阅相同的主题就能收到消息了

1. int8_t ESP8266_MQTT_Pub(char *IpBuf, uint8_t len, uint8_t qos)//信息 消息长度 以及qos(百度)
2. {
3.  uint8_t TryGo = 0;
4.  int8_t error = 0;
5.  uint8_t IpSend[MAX_AT_TX_LEN];
6.  memset(IpSend, 0x00, MAX_AT_TX_LEN);//清空缓存
7.  ClrAtRxBuf();//清空缓存
8.  /************设置为MQTT_Binary发送模式************/
9. /*   注意----------dmx为发布的主题-----------*/
10.   sprintf((char *)IpSend,"AT+MQTTPUBRAW=0,\"dmx\",%d,%d,0", len, qos);
11.   //printf("%s\r\n",IpSend);
12.   SendAtCmd((uint8_t *)IpSend,strlen((const char *)IpSend));
13.   delay_ms(100);
14.   //注意--如果断开连接或者怎么样,这一步ESP8266就会返回ERROR
15.   if(strstr((const char *)AT_RX_BUF, (const char *)"OK") == NULL)
16.   {
17.     printf("MQTT_Pub Fail:%s\r\n", AT_RX_BUF);
18.     MQTTSendErrorTimes++;
19.     return -1;
20.   }
21. 
22.   ClrAtRxBuf();//清空缓存
23. 
24.   //以二进制数据形式发送字符串
25.   SendAtCmd((uint8_t *)IpBuf, len);
26.   printf("MQTT_Pub: %s\r\n", IpBuf);
27.   if(qos == 0){
28.     return 0;
29.   }
30. 
31.   //等待qos回执处理
32.   delay_ms(100);
33.   if(strstr((const char *)AT_RX_BUF, (const char *)"OK") == NULL)
34.   {
35.     MQTTSendErrorTimes++;
36.     return -2;
37.   }
38.   return error;
39. }

八.到这里,完成的步骤已经完成,由于篇幅有限,很多细节也讲不完,如果有什么问题可以评论区留言,最后我附一个搭建好的mqtt的一个简易智能家居!可以读取各种传感器器数据,如温湿度,光照,烟雾溶度等上传给服务器,风扇 PWM灯也可以被服务器传来的数据控制。

相关实践学习
快速体验阿里云云消息队列RocketMQ版
本实验将带您快速体验使用云消息队列RocketMQ版Serverless系列实例进行获取接入点、创建Topic、创建订阅组、收发消息、查看消息轨迹和仪表盘。
消息队列 MNS 入门课程
1、消息队列MNS简介 本节课介绍消息队列的MNS的基础概念 2、消息队列MNS特性 本节课介绍消息队列的MNS的主要特性 3、MNS的最佳实践及场景应用 本节课介绍消息队列的MNS的最佳实践及场景应用案例 4、手把手系列:消息队列MNS实操讲 本节课介绍消息队列的MNS的实际操作演示 5、动手实验:基于MNS,0基础轻松构建 Web Client 本节课带您一起基于MNS,0基础轻松构建 Web Client
目录
相关文章
|
9月前
|
安全
基于Reactor模式的高性能服务器之Acceptor组件(处理连接)
本节介绍了对底层 Socket 进行封装的设计与实现,通过 `Socket` 类隐藏系统调用细节,提供简洁、安全、可读性强的接口。重点包括 `Socket` 类的核心作用(管理 `sockfd_`)、成员函数的功能(如绑定地址、监听、接受连接等),以及 `Acceptor` 组件的职责:监听连接、接收新客户端连接并分发给上层处理。同时说明了 `Acceptor` 与 `EventLoop` 和 `TcpServer` 的协作关系,并展示了其成员变量和关键函数的工作机制。
207 2
|
8月前
|
SQL Oracle 关系型数据库
【赵渝强老师】Oracle客户端与服务器端连接建立的过程
Oracle数据库采用客户端-服务器架构,客户端通过其网络环境与服务器通信,实现数据库访问。监听程序负责建立连接,通过命令lsnrctl可启动、停止及查看监听状态。本文介绍了监听器的作用及相关基础管理操作。
336 0
|
IDE 网络安全 开发工具
IDE之vscode:连接远程服务器代码(亲测OK),与pycharm链接服务器做对比(亲自使用过了),打开文件夹后切换文件夹。
本文介绍了如何使用VS Code通过Remote-SSH插件连接远程服务器进行代码开发,并与PyCharm进行了对比。作者认为VS Code在连接和配置多个服务器时更为简单,推荐使用VS Code。文章详细说明了VS Code的安装、远程插件安装、SSH配置文件编写、服务器连接以及如何在连接后切换文件夹。此外,还提供了使用密钥进行免密登录的方法和解决权限问题的步骤。
10114 0
IDE之vscode:连接远程服务器代码(亲测OK),与pycharm链接服务器做对比(亲自使用过了),打开文件夹后切换文件夹。
|
Apache 数据中心 Windows
将网站迁移到阿里云Windows系统云服务器,访问该站点提示连接被拒绝,如何处理?
将网站迁移到阿里云Windows系统云服务器,访问该站点提示连接被拒绝,如何处理?
|
弹性计算 安全 Windows
通过远程桌面连接Windows服务器提示“由于协议错误,会话将被中断,请重新连接到远程计算机”错误怎么办?
通过远程桌面连接Windows服务器提示“由于协议错误,会话将被中断,请重新连接到远程计算机”错误怎么办?
使用STM32F103标准库实现定时器控制LED点亮和关闭
通过这篇博客,我们学习了如何使用STM32F103标准库,通过定时器来控制LED的点亮和关闭。我们配置了定时器中断,并在中断处理函数中实现了LED状态的切换。这是一个基础且实用的例子,适合初学者了解STM32定时器和中断的使用。 希望这篇博客对你有所帮助。如果有任何问题或建议,欢迎在评论区留言。
1722 2
stm32f407探索者开发板(十七)——串口寄存器库函数配置方法
stm32f407探索者开发板(十七)——串口寄存器库函数配置方法
2011 0
|
缓存 网络协议 算法
[蓝桥杯嵌入式]hal库 stm32 PWM的使用(随时修改占空比,随时修改频率)
[蓝桥杯嵌入式]hal库 stm32 PWM的使用(随时修改占空比,随时修改频率)