一、环境介绍
编程软件: keil5
主控MCU: STM32F103C8T6
WIFI: ESP8266
协议: MQTT
完整项目源码下载地址:https://download.csdn.net/download/xiaolong1126626497/19137788
二、前言
这里的 WIFI型号不重要、主控MCU不重要,连接的物联网平台也不重要。
要完成本章节的内容,只要会熟悉某款单片机的编程、了解基本的网络编程,明白MQTT协议、能读懂每个物联网云平台的帮助文档都可以完成最终的效果。
三、功能介绍
前面有几篇内容都介绍了如何使用在腾讯物联网平台创建设备,完成微信小程序与设备进行交互;这些设备代码里的连接的WIFI名称和密码都是固定,只能通过每次修改程序、编译、下载才能更改。一个正常的物联网智能设备,这样操作肯定是不合理的,所以这篇内容就完成如何使用微信小程序一键配网,完成设备的WIFI切换、连接。
现在我们购买的智能设备都有自己的配网方式,比如: 小米的很多设备,小爱音箱,摄像头,扫地机器人等。这些设备买回来之后,用户可以参考说明书,完成对设备的配置,让设备连接上家里的WIFI,完成网络连接。
本次我以智能锁为产品模型,在腾讯物联网平台创建一个设备,使用STM32F103系统板+ESP8266+LED灯完成智能锁产品的模拟开发;用户设备端可以按下指定的按键进入配网模式,打开腾讯官方的微信小程序,扫描产品二维码,根据步骤完成对设备的配网操作。
腾讯物联网支持了好几种配网模式,我这里选择的是“softAP”模式来完成配网操作。
softAP 模式配网的原理介绍: 正常情况下我们买回来的新设备内部是没有我们自己家WIFI的信息的,也就是说这个设备上电之后自己不知道该连接哪一个WIFI;这时我们就需要想办法把我们自己家里的WIFI名称、WIFI密码告诉这个设备,这个设备就可以去连接了。 那问题是怎么去告诉设备这些信息? 设备一般都有进入配网模式的按钮,进入配网模式之后,会将设备内部的WIFI设置成“softAP”模式,也就是设备自己会创建一个WIFI热点出来并创建UDP服务器监听连接,这时我们打开腾讯官方的微信小程序,按照指引去连接这个WIFI,连上之后,微信小程序会通过UDP协议将WIFI的配置信息传输给设备WIFI,设备WIFI收到之后,再切换模式为STA模式,去连接目标WIFI,连接成功之后,登录云平台,绑定设备,完成配网。 这其中的交互协议,后面再细说。
四、在腾讯云平台上创建智能锁
本章节只会展示几个关键步骤,如果之前没有使用过腾讯物联网云平台可以参考这里学习一遍:https://blog.csdn.net/xiaolong1126626497/article/details/116902653
这里可以配置微信小程序的详细参数,配网的设置也这个页面上:
下面进行配网设置:
选择配网模式:
这个页面比较重要,需要将设备进入配网的方法告诉用户,引导用户去操作,完成进入配网模式:
保存之后,打开微信小程序“腾讯连连”,扫描右下角的这个二维码,进行配网,完成设备添加。(一般正常产品,会将这个二维码打印出来,贴在设备上,方便用户扫描)
(提示: 做这一步,要先设计好设备端的程序,设备上电能正常的运行,才能做)
下面是手机上的截图: (根据页面上的提示操作设备)
按下开发板子上的S2进入配网模式:
在串口上也可以看到提示信息。
这时继续操作微信小程序上的步骤,选择设备的WIFI进行连接: 之后在下一个页面会自动等待配网成功(没有截图),设备配网成功之后会出现提示,这时设备就已经在线了
打开控制台已经看到设备上线了:
这时进入小程序页面,就可以对智能锁进行操作了:
到此,配网已经完成,接下来就介绍设备端的代码。
关于配网的流程,在腾讯官网有详细介绍,看这里:https://cloud.tencent.com/document/product/1081/48404
由于关联代码较多,这里只提供主要的逻辑代码,其他的代码可以自己下载完整源码查看:https://download.csdn.net/download/xiaolong1126626497/19137788
main.c 代码:
#include "stm32f10x.h" #include "led.h" #include "delay.h" #include "key.h" #include "usart.h" #include <string.h> #include "timer.h" #include "bluetooth.h" #include "esp8266.h" #include "mqtt.h" /* 智能锁(自己的设备) MQTT服务器地址: 106.55.124.154 MQTT服务器端口: 1883 MQTT客户端ID: 3XM7FNOG4Llock MQTT用户名: 3XM7FNOG4Llock;12010126;F8Q4P;1624710719 MQTT登录密码: 5d87e9a5bf8ae6295493c263b91aaebc4311f3e95763efe7f31be76c8578f9ec;hmacsha256 订阅主题: $thing/down/property/3XM7FNOG4L/lock 发布主题: $thing/up/property/3XM7FNOG4L/lock 发布消息: {"method":"report","clientToken":"123","params":{"lock":1}} */ #define SERVER_IP "106.55.124.154"//服务器IP #define SERVER_PORT 1883 //端口号 #define CONNECT_WIFI "_CMCC-Cqvn" //将要连接的路由器名称 --不要出现中文、空格等特殊字符 #define CONNECT_PASS "_99pu58cb" //将要连接的路由器密码 //腾讯物联网服务器的设备信息 #define MQTT_ClientID "3XM7FNOG4Llock" #define MQTT_UserName "3XM7FNOG4Llock;12010126;F8Q4P;1624710719" #define MQTT_PassWord "5d87e9a5bf8ae6295493c263b91aaebc4311f3e95763efe7f31be76c8578f9ec;hmacsha256" //订阅与发布的主题 #define SET_TOPIC "$thing/down/property/3XM7FNOG4L/lock" //订阅 #define POST_TOPIC "$thing/up/property/3XM7FNOG4L/lock" //发布 //微信小程序配网数据订阅与发布 #define SET_WEIXIN_TOPIC "$thing/down/service/3XM7FNOG4L/lock"//订阅 #define POST_WEIXIN_TOPIC "$thing/up/service/3XM7FNOG4L/lock"//发布 char mqtt_message[200];//上报数据缓存区 int main() { u32 time_cnt=0; u32 i; u8 key; u8 stat=0; //1.初始化需要使用的硬件 LED_Init(); BEEP_Init(); KEY_Init(); //2. 初始化串口1(打印调试信息)与串口3(与WIFI通信) USART1_Init(115200); TIMER1_Init(72,20000); //超时时间20ms USART3_Init(115200);//串口-WIFI TIMER3_Init(72,20000); //超时时间20ms USART1_Printf("正在初始化WIFI请稍等.\n"); //3. 检测WIFI硬件 while(1) { //如果硬件有问题. 蜂鸣器以300ms的频率报警 if(ESP8266_Init()) { delay_ms(300); BEEP=!BEEP; USART1_Printf("ESP8266硬件检测错误.\n"); } else { BEEP=0; //关闭蜂鸣器 break; //硬件没有问题. 退出检测 } } //4. 上电如果检测到S2按键按下就表示需要进入配网状态 if(KEY_S2) { delay_ms(100); if(KEY_S2) { while(1)//连接服务器 { printf("进入配网模式.....\n"); BEEP=1; delay_ms(100); BEEP=0; //清除之前的WIFI连接信息(连接个无效的WIFI),防止默认连接上 上次的WIFI,导致配网错误 ESP8266_SendCmd("AT+CWJAP=\"666\",\"12345678\"\r\n"); delay_ms(200); stat=Esp8266_STA_TCPclinet_Init((u8 *)SERVER_IP,SERVER_PORT); if(stat==0 || stat==0x80)break; delay_ms(500); printf("stat=%d\r\n",stat); } } else { stat=0xFF; } } else { stat=0xFF; } //连接默认WIFI if(stat==0xFF) { printf("连接默认的WIFI.\n"); //非加密端口 USART1_Printf("WIFI:%d\n",ESP8266_STA_TCP_Client_Mode(CONNECT_WIFI,CONNECT_PASS,SERVER_IP,SERVER_PORT,1)); } //2. MQTT协议初始化 MQTT_Init(); //3. 连接OneNet服务器 while(MQTT_Connect(MQTT_ClientID,MQTT_UserName,MQTT_PassWord)) { USART1_Printf("服务器连接失败,正在重试...\n"); delay_ms(500); } USART1_Printf("服务器连接成功.\n"); //3. 订阅主题 if(MQTT_SubscribeTopic(SET_TOPIC,0,1)) { USART1_Printf("主题订阅失败.\n"); } else { USART1_Printf("主题订阅成功.\n"); } if(stat==0x80)//进入配网模式需要给微信小程序返回token值 { //订阅微信topic if(MQTT_SubscribeTopic(SET_WEIXIN_TOPIC,0,1))printf("订阅失败\r\n"); //返回平台数据,告知微信连连连接服务器成功 snprintf(mqtt_message,sizeof(mqtt_message),"{\"method\":\"app_bind_token\",\"clientToken\":\"client-1234\",\"params\": {\"token\":\"%s\"}}",esp8266_info.token); MQTT_PublishData(POST_WEIXIN_TOPIC,mqtt_message,0); //Smart_home{"method":"app_bind_token_reply","clientToken":"client-1234","code":0,"status":"success"} 配网成功后微信小程序返回数据 } while(1) { key=KEY_Scan(0); if(key==2) { time_cnt=0; sprintf(mqtt_message,"{\"method\":\"report\",\"clientToken\":\"123\",\"params\":{\"lock\":1}}"); MQTT_PublishData(POST_TOPIC,mqtt_message,0); USART1_Printf("开锁.\r\n"); } else if(key==3) { time_cnt=0; sprintf(mqtt_message,"{\"method\":\"report\",\"clientToken\":\"123\",\"params\":{\"lock\":0}}"); MQTT_PublishData(POST_TOPIC,mqtt_message,0); USART1_Printf("关锁\r\n"); } if(USART3_RX_FLAG) { USART3_RX_BUFFER[USART3_RX_CNT]='\0'; for(i=0;i<USART3_RX_CNT;i++) { USART1_Printf("%c",USART3_RX_BUFFER[i]); } //关锁 if(strstr((char*)USART3_RX_BUFFER,"\"lock\":0")) { LED4=1; } //开锁 else if(strstr((char*)USART3_RX_BUFFER,"\"lock\":1")) { LED4=0; } USART3_RX_CNT=0; USART3_RX_FLAG=0; } //定时发送心跳包,保持连接 delay_ms(10); time_cnt++; if(time_cnt==500) { LED1=!LED1; MQTT_SentHeart();//发送心跳包 time_cnt=0; } } }
ESP8266的核心代码: