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版的基础消息收发功能,涵盖实例创建、Topic、Group资源创建以及消息收发体验等基础功能模块。
消息队列 MNS 入门课程
1、消息队列MNS简介 本节课介绍消息队列的MNS的基础概念 2、消息队列MNS特性 本节课介绍消息队列的MNS的主要特性 3、MNS的最佳实践及场景应用 本节课介绍消息队列的MNS的最佳实践及场景应用案例 4、手把手系列:消息队列MNS实操讲 本节课介绍消息队列的MNS的实际操作演示 5、动手实验:基于MNS,0基础轻松构建 Web Client 本节课带您一起基于MNS,0基础轻松构建 Web Client
目录
相关文章
|
1月前
|
传感器 数据采集 移动开发
基于STM32的智能手环wifi连接手机APP(下)
基于STM32的智能手环wifi连接手机APP(下)
76 0
|
1月前
|
IDE 网络安全 开发工具
IDE之vscode:连接远程服务器代码(亲测OK),与pycharm链接服务器做对比(亲自使用过了),打开文件夹后切换文件夹。
本文介绍了如何使用VS Code通过Remote-SSH插件连接远程服务器进行代码开发,并与PyCharm进行了对比。作者认为VS Code在连接和配置多个服务器时更为简单,推荐使用VS Code。文章详细说明了VS Code的安装、远程插件安装、SSH配置文件编写、服务器连接以及如何在连接后切换文件夹。此外,还提供了使用密钥进行免密登录的方法和解决权限问题的步骤。
434 0
IDE之vscode:连接远程服务器代码(亲测OK),与pycharm链接服务器做对比(亲自使用过了),打开文件夹后切换文件夹。
|
1月前
|
IDE 网络安全 开发工具
IDE之pycharm:专业版本连接远程服务器代码,并配置远程python环境解释器(亲测OK)。
本文介绍了如何在PyCharm专业版中连接远程服务器并配置远程Python环境解释器,以便在服务器上运行代码。
316 0
IDE之pycharm:专业版本连接远程服务器代码,并配置远程python环境解释器(亲测OK)。
|
1月前
|
存储 网络协议 Java
【网络】UDP回显服务器和客户端的构造,以及连接流程
【网络】UDP回显服务器和客户端的构造,以及连接流程
52 2
|
1月前
|
Apache 数据中心 Windows
将网站迁移到阿里云Windows系统云服务器,访问该站点提示连接被拒绝,如何处理?
将网站迁移到阿里云Windows系统云服务器,访问该站点提示连接被拒绝,如何处理?
|
1月前
|
传感器 存储 编解码
基于STM32的智能手环wifi连接手机APP(上)
基于STM32的智能手环wifi连接手机APP(上)
62 0
|
1月前
|
弹性计算 安全 Windows
通过远程桌面连接Windows服务器提示“由于协议错误,会话将被中断,请重新连接到远程计算机”错误怎么办?
通过远程桌面连接Windows服务器提示“由于协议错误,会话将被中断,请重新连接到远程计算机”错误怎么办?
|
28天前
|
消息中间件 JSON Java
开发者如何使用轻量消息队列MNS
【10月更文挑战第19天】开发者如何使用轻量消息队列MNS
68 4
|
22天前
|
消息中间件 存储 Kafka
MQ 消息队列核心原理,12 条最全面总结!
本文总结了消息队列的12个核心原理,涵盖消息顺序性、ACK机制、持久化及高可用性等内容。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
|
26天前
|
消息中间件
解决方案 | 云消息队列RabbitMQ实践获奖名单公布!
云消息队列RabbitMQ实践获奖名单公布!
下一篇
无影云桌面