STM32 + ESP8266 + MQTT协议连接OneNet

一、环境介绍
单片机采用:stm32f103c8t6
上网方式:采用esp8266,也可以使用其他设备代替,只要支持tcp协议即可。比如:gsm模块、有线网卡等。
开发软件:keil5
硬件连接功能:esp8266接在stm32的串口3上。通过at指令与esp8266进行通信。
注意:本篇文章没有贴esp8266的底层编程代码,如果不会esp8266底层编程,请看这里:
https://blog.csdn.net/xiaolong1126626497/article/details/107379554
如果需要了解esp8266+mqtt协议连接阿里云物联网服务器请看这里:https://blog.csdn.net/xiaolong1126626497/article/details/107311897
二、功能介绍 2.1 功能说明  通过onenet物联网服务器实现设备数据远程上传、下发,实现数据交互(不清楚onenet物联网服务器功能的可以百度一下进入官网看简介)。之前的onenet服务器不支持标准mqtt协议登录的,现在官网更新之后支持标准的mqtt协议,本篇文章介绍使用stm32+esp8266使用标准mqtt协议登录onenet服务器,实现数据交互。实现步骤onenet官方提供了很详细的文档,可以参考一下。
文档地址:onenet-中国移动物联网开放平台


2.2 硬件资源 在当前使用的开发板上有4盏led灯、一个蜂鸣器、4个按键,esp8266型号是esp-12f,stm32型号是:stm32f103c8t6。

三、onenet支持的mqtt协议版本 目前onenet服务器支持mqtt 3.1.1版本,mqtt协议官网: mqtt - the standard for iot messaging
报文支持情况:  支持connect、subscribe、publish、ping、unsubscribe、disconnect等报文,不支持pubrec、pubrel、pubcomp报文。
四、登录onenet服务器创建物联网产品  没有注册账号的,需要提前登录官网注册账号,再进入下面步骤:

​ 

这里根据自己产品情况填写。 



产品创建成功之后,点击产品名称,跳转页面,继续添加设备。











​ 




下面选择仪表盘的数据来源,根据自己创建的数据点选择。

创建一个文本控件,显示数据点更新的时间,方便调试。




onente有手机版本的app,登录之后也可以看到该页面。
下载地址:https://open.iot.10086.cn/doc/book/device-develop/multpro/sdk-doc-tool/app.html


下面是手机上登录app看到的界面效果:


五、onenet服务器mqtt登录地址与订阅主题相关格式介绍 官网介绍文档地址: 设备连接_开发者文档_onenet

5.1 mqtt服务器登录地址 ​
目前mqtt协议支持两个ip地址和端口号,一个需要加密、一个不需要加密。
注意:单片机上移植加密算法很麻烦,这里采用不需要加密的端口。(ip地址: 183.230.40.96  端口: 1883)

5.2 mqtt登录的:设备id、用户名称、密码 格式参数 ​

​  上面图片里说明了,onenet的设备参数与标准mqtt协议的登录参数对应关系。 onenet的设备参数,在设备页面可以去查看。
登录密码生成看下面步骤:



注意:该工具在win10系统运行可能会提示非信任程序,点击任要运行即可。
下面是生成mqtt登录密匙的工具使用示例。

注意:工具中填的参数说明请看文档介绍。
res选项参数的格式: products/{产品id}/devices/{设备名称}
et是设置token过期时间:算出1970-1-1到你想要设置的到期时间,单位是秒,填入即可。
比如: 超时时间设置为2020-07-20 ,那么,这里填入的秒就是:1970-1-1到2020-07-20之间的秒单位时间。
linux下代码:
#include #include #include int main(){ time_t time_sec; time_sec=time(null); //当前的秒单位时间--utc时间 printf(当前时间(秒):%ldn,time_sec); printf(加30天的时间(秒):%ldn,time_sec+30*24*60*60); return 0;} key的参数格式: 就是设备创建之后,在设备详情页的key
工具生成的结果值,直接当做mqtt登录的密码。
5.3 主题订阅格式 文档地址:协议规范_开发者文档_onenet


5.4 设备保活时间 ​

5.5 向服务器传数据点 ​


六、核心代码 6.1 matt.c代码#include mqtt.hu8 *mqtt_rxbuf;u8 *mqtt_txbuf;u16 mqtt_rxlen;u16 mqtt_txlen;u8 _mqtt_txbuf[256];//发送数据缓存区u8 _mqtt_rxbuf[256];//接收数据缓存区typedef enum{ //名字 值 报文流动方向 描述 m_reserved1 =0 , // 禁止 保留 m_connect , // 客户端到服务端 客户端请求连接服务端 m_connack , // 服务端到客户端 连接报文确认 m_publish , // 两个方向都允许 发布消息 m_puback , // 两个方向都允许 qos 1消息发布收到确认 m_pubrec , // 两个方向都允许 发布收到(保证交付第一步) m_pubrel , // 两个方向都允许 发布释放(保证交付第二步) m_pubcomp , // 两个方向都允许 qos 2消息发布完成(保证交互第三步) m_subscribe , // 客户端到服务端 客户端订阅请求 m_suback , // 服务端到客户端 订阅请求报文确认 m_unsubscribe , // 客户端到服务端 客户端取消订阅请求 m_unsuback , // 服务端到客户端 取消订阅报文确认 m_pingreq , // 客户端到服务端 心跳请求 m_pingresp , // 服务端到客户端 心跳响应 m_disconnect , // 客户端到服务端 客户端断开连接 m_reserved2 , // 禁止 保留}_typdef_mqtt_message;//连接成功服务器回应 20 02 00 00//客户端主动断开连接 e0 00const u8 parket_connetack[] = {0x20,0x02,0x00,0x00};const u8 parket_disconnet[] = {0xe0,0x00};const u8 parket_heart[] = {0xc0,0x00};const u8 parket_heart_reply[] = {0xc0,0x00};const u8 parket_suback[] = {0x90,0x03};void mqtt_init(void){ //缓冲区赋值 mqtt_rxbuf = _mqtt_rxbuf; mqtt_rxlen = sizeof(_mqtt_rxbuf); mqtt_txbuf = _mqtt_txbuf; mqtt_txlen = sizeof(_mqtt_txbuf); memset(mqtt_rxbuf,0,mqtt_rxlen); memset(mqtt_txbuf,0,mqtt_txlen); //无条件先主动断开 mqtt_disconnect(); delay_ms(100); mqtt_disconnect(); delay_ms(100);}/*函数功能: 登录服务器函数返回值: 0表示成功 1表示失败*/u8 mqtt_connect(char *clientid,char *username,char *password){ u8 i,j; int clientidlen = strlen(clientid); int usernamelen = strlen(username); int passwordlen = strlen(password); int datalen; mqtt_txlen=0; //可变报头+payload 每个字段包含两个字节的长度标识 datalen = 10 + (clientidlen+2) + (usernamelen+2) + (passwordlen+2); //固定报头 //控制报文类型 mqtt_txbuf[mqtt_txlen++] = 0x10; //mqtt message type connect //剩余长度(不包括固定头部) do { u8 encodedbyte = datalen % 128; datalen = datalen / 128; // if there are more data to encode, set the top bit of this byte if ( datalen > 0 ) encodedbyte = encodedbyte | 128; mqtt_txbuf[mqtt_txlen++] = encodedbyte; }while ( datalen > 0 ); //可变报头 //协议名 mqtt_txbuf[mqtt_txlen++] = 0; // protocol name length msb mqtt_txbuf[mqtt_txlen++] = 4; // protocol name length lsb mqtt_txbuf[mqtt_txlen++] = 'm'; // ascii code for m mqtt_txbuf[mqtt_txlen++] = 'q'; // ascii code for q mqtt_txbuf[mqtt_txlen++] = 't'; // ascii code for t mqtt_txbuf[mqtt_txlen++] = 't'; // ascii code for t //协议级别 mqtt_txbuf[mqtt_txlen++] = 4; // mqtt protocol version = 4 对于 3.1.1 版协议,协议级别字段的值是 4(0x04) //连接标志 mqtt_txbuf[mqtt_txlen++] = 0xc2; // conn flags mqtt_txbuf[mqtt_txlen++] = 0; // keep-alive time length msb mqtt_txbuf[mqtt_txlen++] = 100; // keep-alive time length lsb 100s心跳包 保活时间 mqtt_txbuf[mqtt_txlen++] = byte1(clientidlen);// client id length msb mqtt_txbuf[mqtt_txlen++] = byte0(clientidlen);// client id length lsb memcpy(&mqtt_txbuf[mqtt_txlen],clientid,clientidlen); mqtt_txlen += clientidlen; if(usernamelen > 0) { mqtt_txbuf[mqtt_txlen++] = byte1(usernamelen); //username length msb mqtt_txbuf[mqtt_txlen++] = byte0(usernamelen); //username length lsb memcpy(&mqtt_txbuf[mqtt_txlen],username,usernamelen); mqtt_txlen += usernamelen; } if(passwordlen > 0) { mqtt_txbuf[mqtt_txlen++] = byte1(passwordlen); //password length msb mqtt_txbuf[mqtt_txlen++] = byte0(passwordlen); //password length lsb memcpy(&mqtt_txbuf[mqtt_txlen],password,passwordlen); mqtt_txlen += passwordlen; } memset(mqtt_rxbuf,0,mqtt_rxlen); mqtt_sendbuf(mqtt_txbuf,mqtt_txlen); for(j=0;j 6.2 mqtt.h代码#ifndef __fy_mqtt_h_#define __fy_mqtt_h_#include stm32f10x.h#include string.h#include stdio.h#include stdlib.h#include stdarg.h#include delay.h#include usart.h#define byte0(dwtemp) (*( char *)(&dwtemp))#define byte1(dwtemp) (*((char *)(&dwtemp) + 1))#define byte2(dwtemp) (*((char *)(&dwtemp) + 2))#define byte3(dwtemp) (*((char *)(&dwtemp) + 3)) //用户名初始化void onenet_logininit(char *productkey,char *devicename,char *devicesecret);//mqtt协议相关函数声明u8 mqtt_publishdata(char *topic, char *message, u8 qos);u8 mqtt_subscribetopic(char *topic,u8 qos,u8 whether);void mqtt_init(void);u8 mqtt_connect(char *clientid,char *username,char *password);void mqtt_sentheart(void);void mqtt_disconnect(void);void mqtt_sendbuf(u8 *buf,u16 len);#endif 6.3 main.c 主函数代码#include stm32f10x.h#include led.h#include delay.h#include key.h#include usart.h#include #include timer.h#include esp8266.h#include mqtt.h/*序号 符号 编码1 + %2b2 空格%203 / %2f4 ? %3f5 % %256 # %237 & %268 = %3d*///onenet物联网服务器的设备信息#define mqtt_clientid mq2#define mqtt_username 361594#define mqtt_password version=2018-10-31&res=products%2f361594%2fdevices%2fmq2&et=1597492895&method=sha1&sign=uqva0kkjxw0fln01at6fwrgblgw%3d//订阅与发布的主题//格式:$sys/{产品id}/{设备名称}/##define set_topic $sys/361594/mq2/# //订阅设备所有信息//格式: $sys/{产品id}/{设备名称}/dp/post/json#define post_topic $sys/361594/mq2/dp/post/json //发布char mqtt_message[200];//上报数据缓存区int main(){ u32 time_cnt=0; u32 i; u8 key; led_init(); beep_init(); key_init(); usart1_init(115200); timer1_init(72,20000); //超时时间20ms usart3_init(115200);//串口-wifi timer3_init(72,20000); //超时时间20ms usart1_printf(正在初始化wifi请稍等.n); if(esp8266_init()) { usart1_printf(esp8266硬件检测错误.n); } else { //加密端口 //usart1_printf(wifi:%dn,esp8266_sta_tcp_client_mode(oneplus5t,1126626497,183.230.40.16,8883,1)); //非加密端口 usart1_printf(wifi:%dn,esp8266_sta_tcp_client_mode(oneplus5t,1126626497,183.230.40.96,1883,1)); } //2. mqtt协议初始化 mqtt_init(); //3. 连接onenet服务器 while(mqtt_connect(mqtt_clientid,mqtt_username,mqtt_password)) { usart1_printf(onenet服务器连接失败,正在重试...n); delay_ms(500); } usart1_printf(onenet服务器连接成功.n); //3. 订阅主题 if(mqtt_subscribetopic(set_topic,0,1)) { usart1_printf(主题订阅失败.n); } else { usart1_printf(主题订阅成功.n); } while(1) { key=key_scan(0); if(key==2) { time_cnt=0; sprintf(mqtt_message,{id:1,dp:{mq2:[{v:50}]}}); mqtt_publishdata(post_topic,mqtt_message,0); usart1_printf(发送状态1rn); } else if(key==3) { time_cnt=0; sprintf(mqtt_message,{id:1,dp:{mq2:[{v:80}]}}); mqtt_publishdata(post_topic,mqtt_message,0); usart1_printf(发送状态0rn); } if(usart3_rx_flag) { usart3_rx_buffer[usart3_rx_cnt]='�'; for(i=0;i;i++)> 七、设备登录运行效果 登录成功之后,网页会显示在线状态。
​  
按下开发按键上传烟雾数据到服务器效果: 

工程完整源码下载: https://download.csdn.net/download/xiaolong1126626497/15803518

;i++)usart1_printf(%#x>
20W射频调频放大器电路图分享
iQOO 冯宇飞表示: 希望用 3-5 年冲刺第一阵营,奔着前三去
魅族pro7什么时候上市?魅族pro7最新消息:魅族pro7确定屏幕和配置参数都出来了?
英国电信大幅裁员 压力之下铤而走险进军体育电视和移动领域
如何寻找区块链上的杀手级资产
STM32 + ESP8266 + MQTT协议连接OneNet
全国产+5G+AI在智慧电力中的应用探索 Q&A问答
揭秘福建奔驰福州工厂
基于RS-485总线的LED夜景照明控制系统设计
哪些云计算平台可以成为“独角兽”?
一加8T赛博朋克2077限定款首销瞬间在苏宁易购抢购一空
聚人才、兴产业、创发展,深开鸿联合承办2022年度“强国杯”技术技能大赛颁奖典礼暨信创人才发展论坛
基于AT89C51单片机和地感线圈实现动态车辆检测器的设计
数据解读红米 Note 7
Micro LED屏幕技术取得突破,良率高达99.9996%
自动驾驶汽车—动力系统能胜任这项任务吗
三防智能手机的优秀性能是怎样的
2019年中国网络安全产业规模将超过600亿元年增长率超过20%
小米新品笔记本23日发布,小米5C或惊喜亮相!
智慧家庭新经济:重新定义互联家庭