一、环境介绍 编程软件: keil5
主控mcu: stm32f103c8t6
wifi: esp8266
协议: mqtt
二、前言 这里的 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,连接成功之后,登录云平台,绑定设备,完成配网。 这其中的交互协议,后面再细说。
四、在腾讯云平台上创建智能锁 本章节只会展示几个关键步骤,如果之前没有使用过腾讯物联网云平台可以参考这里学习一遍:stm32+esp8266+mqtt协议连接腾讯物联网开发平台_ds小龙哥的博客-csdn博客
功能很简单,只有一个属性,就是锁的开关状态。
这里可以配置微信小程序的详细参数,配网的设置也这个页面上:
下面进行配网设置:
选择配网模式:
这个页面比较重要,需要将设备进入配网的方法告诉用户,引导用户去操作,完成进入配网模式:
保存之后,打开微信小程序“腾讯连连”,扫描右下角的这个二维码,进行配网,完成设备添加。(一般正常产品,会将这个二维码打印出来,贴在设备上,方便用户扫描)
(提示: 做这一步,要先设计好设备端的程序,设备上电能正常的运行,才能做)
下面是手机上的截图: (根据页面上的提示操作设备)
按下开发板子上的s2进入配网模式:
在串口上也可以看到提示信息。
这时继续操作微信小程序上的步骤,选择设备的wifi进行连接: 之后在下一个页面会自动等待配网成功(没有截图),设备配网成功之后会出现提示,这时设备就已经在线了
打开控制台已经看到设备上线了:
这时进入小程序页面,就可以对智能锁进行操作了:
到此,配网已经完成,接下来就介绍设备端的代码。
五、stm32设备端代码--这才是核心 关于配网的流程,在腾讯官网有详细介绍,看这里:物联网开发平台 softap 配网开发 - 设备端开发指南 - 文档中心 - 腾讯云
由于关联代码较多,这里只提供主要的逻辑代码,其他的代码可以自己下载完整源码查看:基于stm32+esp8266设计智能锁(支持微信小程序一键配网连接腾讯云平台).7z_stm32+esp8266-嵌入式文档类资源-csdn下载
完整项目源码下载地址: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 #include timer.h#include bluetooth.h#include esp8266.h#include mqtt.h/*智能锁(自己的设备)mqtt服务器地址: 106.55.124.154mqtt服务器端口: 1883mqtt客户端id: 3xm7fnog4llockmqtt用户名: 3xm7fnog4llock;12010126;f8q4p;1624710719mqtt登录密码: 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 esp8266的核心代码:
//存放esp8266的详细信息struct esp8266 esp8266_info;/*softap配网*/u8 esp8266_softap_mode(void){ u8 token[]={\cmdtype\:2,\productid\:\3xm7fnog4l\,\devicename\:\lock\,\protoversion\:\2.0\}\r\n;//连接状态信息 char *p=null; char data[256]; char buff[100]; u8 i=0; u32 time1=0,time2=0; usart3_rx_cnt=0; usart3_rx_flag=0; while(1) { if(usart3_rx_flag) { usart3_rx_buffer[usart3_rx_cnt]='\0'; printf(rx=%s,usart3_rx_buffer); //+ipd,97,192.168.4.2,52021:{cmdtype:1,ssid:wbyq_wifi,password:12345678,token:df4a4c90abee98c9a443ae8ffd8cc16b p=strstr((char *)usart3_rx_buffer,+ipd); if(p) { strcpy(data,p);//将接收到的数据拷贝一份保存 p+=strlen(+ipd); p+=1; while(*p!=',' && *p!='\0')p++; p++;//跳过字符',',获取到ip地址起始位置 i=0; //ip地址解析 while(*p!=',' && *p!='\0') { buff[i++]=*p++; } buff[i]='\0'; strcpy((char *)esp8266_info.esp8266_ip,buff); //端口号解析 p++; i=0; while(*p!=':' && *p!='\0') { buff[i++]=*p++; } buff[i]='\0'; esp8266_info.esp8266_prot=atoi(buff);//字符串转整数 //printf(ip=%s:%d\r\n,esp8266_info.esp8266_ip,esp8266_info.esp8266_prot); printf(ret:%d\r\n,esp8266_udp_senddata((u8*)esp8266_info.esp8266_ip,esp8266_info.esp8266_prot,token));//上报连接状态 } esp8266_getdata(data,(char *)esp8266_info.esp8266_name,ssid);//wifi名 esp8266_getdata(data,(char *)esp8266_info.esp8266_key,password);//密码 esp8266_getdata(data,(char *)esp8266_info.token,token);//token数据,需要返回给平台 printf(wifi_name:%s\r\n,esp8266_info.esp8266_name); printf(wifi_key:%s\r\n,esp8266_info.esp8266_key); printf(wifi_token:%s\r\n,esp8266_info.token); led1=1; return 0; } delay_ms(1); time1++; time2++; if(time2>=100) { time2=0; led1=!led1; } if(time1>=1000*300) { led1=1; break;//超时退出 } } return 1;}/*********************************************************************************************************************形参: wifi_name --wifi名** password --密码** remote_ip --远端ip地址(255.255.255.255为广播地址)** remote_prot --远端端口号** localhost ---本地端口号**返回值:0 --成功,** 其它值 --失败**示例:esp8266_udp_sta_mode(360wifi_123,12345678,172.20.7.2,10500,8080);*********************************************************************************************************************/u8 esp8266_udp_sta_mode(u8 *wifi_name,u8 *password,u8 *remote_ip,u16 remote_prot,u16 localprot){ char buff[100]; usartx_stringsend(usart3,+++); //退出透传模式 delay_ms(1000); printf(重启模块.......\r\n); usartx_stringsend(usart3,at+rst\r\n); delay_ms(1000); delay_ms(1000); printf(关回显.......\r\n); if(esp8266_sendcmd(ate0\r\n))return 2; printf(设置为sta模式.......\r\n); if(esp8266_sendcmd(at+cwmode=1\r\n))return 3; printf(连接wifi.......\r\n); snprintf(buff,sizeof(buff),at+cwjap=\%s\,\%s\\r\n,wifi_name,password); if(esp8266_sendcmd(buff))return 5; printf(查询ip.......\r\n); if(esp8266_sendcmd(at+cifsr\r\n))return 6; printf(建立udp连接.....\r\n); snprintf(buff,sizeof(buff),at+cipstart=\udp\,\%s\,%d,%d,0\r\n,remote_ip,remote_prot,localprot); if(esp8266_sendcmd(buff))return 7; printf(设置透传.......\r\n); if(esp8266_sendcmd(at+cipmode=1\r\n))return 8; printf(发送数据.......\r\n); usartx_stringsend(usart3,at+cipsend\r\n); return 0;}/****************sta+tcpclinet初始化*****************const char *sta_tcpclinet[]={ at\r\n,//测试指令 ate0\r\n,//关回显 at+cwmode=1\r\n,//设置sta模式 at+rst\r\n,//模块复位 ate0\r\n,//关回显 at+cwjap=\huaweishui\,\asdfghjkl12\\r\n,//连接wifi at+cipmux=0\r\n,//设置单连接 at+cifsr\r\n,//查询ip at+cipstart=\tcp\,\192.168.43.204\,8080\r\n,//连接服务器 at+cipmode=1\r\n,//设置透传模式 at+cipsend\r\n,//开始发送数据};返回值: 0x7f --退出透传模式失败** 0x80 --进入配网模式正常退出** 0 --未进入配网模式正常退出** 其他值 --异常退出*****************************************************/u8 esp8266_sta_tcpclinet_init(u8 *server_ip,u16 server_port){ char buff[100]; /*退出透传模式*/ u8 i=0; u8 stat=0; u32 id; for(i=0;i))return 15; if(stat)return 0x80;//进入配网模式并且正常退出 else return 0;//未进入配网模式,正常退出}/**************************获取wifi连接状态信息***************************/u8 esp8266_getwifi_stat(void){ u16 i=0; u16 time=0; u16 time2=0; usart3_rx_cnt=0; usart3_rx_flag=0; usartx_stringsend(usart3,at+cwjap?\r\n);//查询wifi连接状态 while(1) { if(usart3_rx_flag) { usart3_rx_buffer[usart3_rx_cnt]='\0'; printf(rx=%s\r\n,usart3_rx_buffer); if(strstr((char *)usart3_rx_buffer,+cwjap) || strstr((char *)usart3_rx_buffer,wifi got ip)) { usart3_rx_cnt=0; usart3_rx_flag=0; led1=1; return 0; } else { usart3_rx_cnt=0; usart3_rx_flag=0; memset(usart3_rx_buffer,0,sizeof(usart3_rx_buffer)); } } delay_ms(10); i++; time++; time2++; if(time>=1000) { time=0; usartx_stringsend(usart3,at+cwjap?\r\n); } if(time2>=300) { led1=!led1; time2=0; } if(i>=100*60) { led1=1; break; } } return 1;}
改变世界的无损压缩算法发展史
物理学两大基石的矛盾
汽车应用的功率控制
什么是EPS电机 EPS电机的工作原理
工信部:农村和城市实现同网同速
STM32+ESP8266连接腾讯IOT微信小程序一键配网
小米最新消息:火爆米粉节,小米发布米粉节总销售战报,总销售额破13.6亿!
智慧城市为人和机器带来全新功能,未来七年内复合年增长率为24.7%
Ultimaker发布3D打印技术信心指数报告
Intel白皮书:UWB技术实现高速无线个人局域网
武汉市正在重点打造存储器 长江存储首个芯片计划量产
72V混合DC-DC转换器可将中间总线转换器尺寸减小多达50%
英特尔和IBM积极探索神经模态计算到底是什么?
限排效应下,铜箔基板CCL报价调涨5%至10%
误差小,精度高的AOA多功能高阶电流模滤波器
AMD Instinct MI200计算卡首曝:用上MCM多芯封装
爱立信携手英特尔和诺基亚致力于面向IoT的下一代无线连接
Altera专家:认知无线电,认知一切
“意念打字”新方法:每分钟能写近30个字母,错误率仅6.13%
SST™ DN4 DeviceNet PCIe NIC 集成总线、主从工序