1、MQTT协议
MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议),是一种基于发布/订阅(publish/subscribe)模式的"轻量级"通讯协议,该协议构建于TCP/IP协议上,由IBM在1999年发布。MQTT最大优点在于,可以以极少的代码和有限的带宽,为连接远程设备提供实时可靠的消息服务。作为一种低开销、低带宽占用的即时通讯协议,使其在物联网、小型设备、移动应用等方面有较广泛的应用。
协议详情: MQTT Version 3.1.1(英文版)
(中文版)
2、STM32实现的自我理解
既然是一个协议,所以有一个基本的物理网络层就可以实现
将就手上的一个ESP8266无线wifi串口模块,一个STM32的板子。也就可以完成MQTT的测试了。
一般来说在协议中扮演的是一个客户端。主要的工作就是连接服务器、订阅消息、发送消息几个功能。最开始我在网上找了MQTT的客户端代码包,打开一看就蒙了。太多、太杂了,完全大于了我们的需求。所以我自己通过抓包对着协议写了一个数据包生成代码。
3、测试前准备
MQTT服务器:我用的是Apollo Console(账号默认为:admin 密码默认:password 后面连接时要用)
MQTT客户端: 通信猫。
具体怎么用大家百度。。。
4、代码实现
4.1、固定报头 Fixed header
类型:
标志位:
根据这个可以写一个生成固定头的函数
#define MQTT_TypeCONNECT 1//请求连接
#define MQTT_TypeCONNACK 2//请求应答
#define MQTT_TypePUBLISH 3//发布消息
#define MQTT_TypePUBACK 4//发布应答
#define MQTT_TypePUBREC 5//发布已接收,保证传递1
#define MQTT_TypePUBREL 6//发布释放,保证传递2
#define MQTT_TypePUBCOMP 7//发布完成,保证传递3
#define MQTT_TypeSUBSCRIBE 8//订阅请求
#define MQTT_TypeSUBACK 9//订阅应答
#define MQTT_TypeUNSUBSCRIBE 10//取消订阅
#define MQTT_TypeUNSUBACK 11//取消订阅应答
#define MQTT_TypePINGREQ 12//ping请求
#define MQTT_TypePINGRESP 13//ping响应
#define MQTT_TypeDISCONNECT 14//断开连接
unsigned char GetDataFixedHead(unsigned char MesType,unsigned char DupFlag,unsigned char QosLevel,unsigned char Retain)
{
unsigned char dat = 0;
dat = (MesType & 0x0f) << 4;
dat |= (DupFlag & 0x01) << 3;
dat |= (QosLevel & 0x03) << 1;
dat |= (Retain & 0x01);
return dat;
}
4.2、连接
连接时抓的包的:
根据协议分析
固定报头 Fixed header
也就是数据包前两个10 21
后面是可变头:协议名、协议级别、连接标志、清除会话、遗嘱标志、遗嘱、遗嘱保留、用户名标志、密码标志、保持连接。
然后是有效载荷:客户端标识符、遗嘱主题、遗嘱消息、用户名、密码。
#define MQTT_StaCleanSession 1 //清理会话
#define MQTT_StaWillFlag 0 //遗嘱标志
#define MQTT_StaWillQoS 0 //遗嘱QoS连接标志的第4和第3位。
#define MQTT_StaWillRetain 0 //遗嘱保留
#define MQTT_StaUserNameFlag 1 //用户名标志 User Name Flag
#define MQTT_StaPasswordFlag 1 //密码标志 Password Flag
#define MQTT_KeepAlive 60 //心跳包秒数
#define MQTT_ClientIdentifier "test" //客户端标识符 Client Identifier
#define MQTT_WillTopic "" //遗嘱主题 Will Topic
#define MQTT_WillMessage "" //遗嘱消息 Will Message
#define MQTT_UserName "admin" //用户名 User Name
#define MQTT_Password "password" //密码 Password
void GetDataConnet(unsigned char *buff)//获取连接的数据包正确连接返回20 02 00 00
{
unsigned int i,len,lennum = 0;
unsigned char *msg;
buff[0] = GetDataFixedHead(MQTT_TypeCONNECT,0,0,0);
buff[2] = 0x00;
buff[3] = 0x04;
buff[4] = 'M';
buff[5] = 'Q';
buff[6] = 'T';
buff[7] = 'T';
buff[8] = 0x04;//协议级别 Protocol Level
buff[9] = 0 | (MQTT_StaCleanSession << 1) | (MQTT_StaWillFlag << 1)
| (MQTT_StaWillQoS << 3) | (MQTT_StaWillRetain << 5)
| (MQTT_StaPasswordFlag << 6) |(MQTT_StaUserNameFlag << 7);//连接标志
buff[10] = MQTT_KeepAlive >> 8;
buff[11] = MQTT_KeepAlive;
len = strlen(MQTT_ClientIdentifier);
buff[12] = len >> 8;
buff[13] = len;
msg = MQTT_ClientIdentifier;
for(i = 0;i
{
buff[14+i] = msg[i];
}
lennum += len;
if(MQTT_StaWillFlag)
{
len = strlen(MQTT_WillTopic);
buff[13 + lennum + 1] = len >> 8;
buff[13 + lennum + 2] = len;
lennum += 2;
msg = MQTT_WillTopic;
for(i = 0;i
{
buff[14+lennum+i] = msg[i];
}
lennum += len;
len = strlen(MQTT_WillMessage);
buff[12] = len >> 8;
buff[13] = len;
lennum += 2;
msg = MQTT_WillMessage;
for(i = 0;i
{
buff[14+lennum+i] = msg[i];
}
lennum += len;
}
if(MQTT_StaUserNameFlag)
{
len = strlen(MQTT_UserName);
buff[13 + lennum + 1] = len >> 8;
buff[13 + lennum + 2] = len;
lennum += 2;
msg = MQTT_UserName;
for(i = 0;i
{
buff[14+lennum+i] = msg[i];
}
lennum += len;
}
if(MQTT_StaPasswordFlag)
{
len = strlen(MQTT_Password);
buff[13 + lennum + 1] = len >> 8;
buff[13 + lennum + 2] = len;
lennum += 2;
msg = MQTT_Password;
for(i = 0;i
{
buff[14+lennum+i] = msg[i];
}
lennum += len;
}
buff[1] = 13 + lennum - 1;//最后计算长度
}
4.3、订阅主题
订阅a/b时抓的包:
/**********************
订阅主题的数据包
Num:主题序号 (每次连接从1开始)
RequestedQoS:服务质量要求0,1或2
**********************/
void GetDataSUBSCRIBE(unsigned char *buff,const char *dat,unsigned int Num,unsigned char RequestedQoS)
{
unsigned int i,len = 0,lennum = 0;
buff[0] = 0x82;
len = strlen(dat);
buff[2] = Num>>8;
buff[3] = Num;
buff[4] = len>>8;
buff[5] = len;
for(i = 0;i
{
buff[6+i] = dat[i];
}
lennum = len;
buff[6 + lennum ] = RequestedQoS;
buff[1] = lennum + 5;
}
4.4、发布信息
固定报头:
发送a/c主题信息为123时抓的包:
/**************************************
buff:数据包数组
dup :重发标志
qos :服务质量等级
retain:保留标志
topic:主题如“a/c”
msg:消息
************************************/
void GetDataPUBLISH(unsigned char *buff,unsigned char dup, unsigned char qos,unsigned char retain,const char *topic ,const char *msg)
{
unsigned int i,len=0,lennum=0;
buff[0] = GetDataFixedHead(MQTT_TypePUBLISH,dup,qos,retain);
len = strlen(topic);
buff[2] = len>>8;
buff[3] = len;
for(i = 0;i
{
buff[4+i] = topic[i];
}
lennum = len;
len = strlen(msg);
for(i = 0;i
{
buff[4+i+lennum] = msg[i];
}
lennum += len;
buff[1] = lennum + 2;
}
4.5、心跳请求
客户端发送PINGREQ报文给服务端的。
用于:
在没有任何其它控制报文从客户端发给服务的时,告知服务端客户端还活着。
请求服务端发送 响应确认它还活着。
使用网络以确认网络连接没有断开。
心跳请求抓的包:
可以看到就是发了一个C0 00
而服务器返回一个 d0 00
5、总结
文中就讲了几个非常重要的请求格式。esp8266连接tcp服务器后就可以发送生成的数据包,就可以实现MQTT的功能。
代码我已经测试过完全可用。
下面给完整的代码:
mqtt.h
#ifndef __MQTT_H
#define __MQTT_H
#include "sys.h"
#include
#define MQTT_TypeCONNECT 1//请求连接
#define MQTT_TypeCONNACK 2//请求应答
#define MQTT_TypePUBLISH 3//发布消息
#define MQTT_TypePUBACK 4//发布应答
#define MQTT_TypePUBREC 5//发布已接收,保证传递1
#define MQTT_TypePUBREL 6//发布释放,保证传递2
#define MQTT_TypePUBCOMP 7//发布完成,保证传递3
#define MQTT_TypeSUBSCRIBE 8//订阅请求
#define MQTT_TypeSUBACK 9//订阅应答
#define MQTT_TypeUNSUBSCRIBE 10//取消订阅
#define MQTT_TypeUNSUBACK 11//取消订阅应答
#define MQTT_TypePINGREQ 12//ping请求
#define MQTT_TypePINGRESP 13//ping响应
#define MQTT_TypeDISCONNECT 14//断开连接
#define MQTT_StaCleanSession 1 //清理会话
#define MQTT_StaWillFlag 0 //遗嘱标志
#define MQTT_StaWillQoS 0 //遗嘱QoS连接标志的第4和第3位。
#define MQTT_StaWillRetain 0 //遗嘱保留
#define MQTT_StaUserNameFlag 1 //用户名标志 User Name Flag
#define MQTT_StaPasswordFlag 1 //密码标志 Password Flag
#define MQTT_KeepAlive 60
#define MQTT_ClientIdentifier "Tan1" //客户端标识符 Client Identifier
#define MQTT_WillTopic "" //遗嘱主题 Will Topic
#define MQTT_WillMessage "" //遗嘱消息 Will Message
#define MQTT_UserName "admin" //用户名 User Name
#define MQTT_Password "password" //密码 Password
unsigned char GetDataFixedHead(unsigned char MesType,unsigned char DupFlag,unsigned char QosLevel,unsigned char Retain);
void GetDataPUBLISH(unsigned char *buff,unsigned char dup, unsigned char qos,unsigned char retain,const char *topic ,const char *msg);//获取发布消息的数据包
void GetDataSUBSCRIBE(unsigned char *buff,const char *dat,unsigned int Num,unsigned char RequestedQoS);//订阅主题的数据包 Num:主题序号 RequestedQoS:服务质量要求0,1或2
void GetDataDisConnet(unsigned char *buff);//获取断开连接的数据包
void GetDataConnet(unsigned char *buff);//获取连接的数据包正确连接返回20 02 00 00
void GetDataPINGREQ(unsigned char *buff);//心跳请求的数据包成功返回d0 00
#endif
mqtt.c
#include "mqtt.h"
unsigned char GetDataFixedHead(unsigned char MesType,unsigned char DupFlag,unsigned char QosLevel,unsigned char Retain)
{
unsigned char dat = 0;
dat = (MesType & 0x0f) << 4;
dat |= (DupFlag & 0x01) << 3;
dat |= (QosLevel & 0x03) << 1;
dat |= (Retain & 0x01);
return dat;
}
void GetDataConnet(unsigned char *buff)//获取连接的数据包正确连接返回20 02 00 00
{
unsigned int i,len,lennum = 0;
unsigned char *msg;
buff[0] = GetDataFixedHead(MQTT_TypeCONNECT,0,0,0);
buff[2] = 0x00;
buff[3] = 0x04;
buff[4] = 'M';
buff[5] = 'Q';
buff[6] = 'T';
buff[7] = 'T';
buff[8] = 0x04;//协议级别 Protocol Level
buff[9] = 0 | (MQTT_StaCleanSession << 1) | (MQTT_StaWillFlag << 1)
| (MQTT_StaWillQoS << 3) | (MQTT_StaWillRetain << 5)
| (MQTT_StaPasswordFlag << 6) |(MQTT_StaUserNameFlag << 7);//连接标志
buff[10] = MQTT_KeepAlive >> 8;
buff[11] = MQTT_KeepAlive;
len = strlen(MQTT_ClientIdentifier);
buff[12] = len >> 8;
buff[13] = len;
msg = MQTT_ClientIdentifier;
for(i = 0;i
{
buff[14+i] = msg[i];
}
lennum += len;
if(MQTT_StaWillFlag)
{
len = strlen(MQTT_WillTopic);
buff[13 + lennum + 1] = len >> 8;
buff[13 + lennum + 2] = len;
lennum += 2;
msg = MQTT_WillTopic;
for(i = 0;i
{
buff[14+lennum+i] = msg[i];
}
lennum += len;
len = strlen(MQTT_WillMessage);
buff[12] = len >> 8;
buff[13] = len;
lennum += 2;
msg = MQTT_WillMessage;
for(i = 0;i
{
buff[14+lennum+i] = msg[i];
}
lennum += len;
}
if(MQTT_StaUserNameFlag)
{
len = strlen(MQTT_UserName);
buff[13 + lennum + 1] = len >> 8;
buff[13 + lennum + 2] = len;
lennum += 2;
msg = MQTT_UserName;
for(i = 0;i
{
buff[14+lennum+i] = msg[i];
}
lennum += len;
}
if(MQTT_StaPasswordFlag)
{
len = strlen(MQTT_Password);
buff[13 + lennum + 1] = len >> 8;
buff[13 + lennum + 2] = len;
lennum += 2;
msg = MQTT_Password;
for(i = 0;i
{
buff[14+lennum+i] = msg[i];
}
lennum += len;
}
buff[1] = 13 + lennum - 1;
}
void GetDataDisConnet(unsigned char *buff)//获取断开连接的数据包
{
buff[0] = 0xe0;
buff[1] = 0;
}
void GetDataPINGREQ(unsigned char *buff)//心跳请求的数据包成功返回d0 00
上一篇:STM32实战1:按键点亮LED小灯 hh
下一篇:STM32 Cube点亮第一个LED
推荐阅读
史海拾趣
品质是Chemi-Con公司的生命线。公司始终坚持严格的质量管理体系,从原材料采购到生产制造,再到产品出厂,每一个环节都经过严格的把控。这种对品质的执着追求,使得Chemi-Con的产品在市场上获得了良好的口碑。同时,公司还积极拓展市场,与全球多家知名企业建立了稳定的合作关系,产品远销海外市场。
为了更好地服务全球客户,CR Magnetics积极在全球范围内拓展业务。公司在东亚、欧洲和美洲等地设立了制造和销售办事处,以便更快速地响应市场需求和提供更好的服务。同时,公司还与国际知名厂商建立了合作关系,共同推动电子行业的发展。
随着技术的不断进步和市场的不断变化,CR Magnetics意识到只有不断创新才能在竞争中立于不败之地。因此,公司加大了研发投入,积极引进新技术和新材料,不断推出具有创新性和竞争力的新产品。例如,公司研发的直流传感器在行业内享有很高的声誉,广泛应用于电池充电等领域。此外,公司还推出了一系列模拟量传感器、ANSI和商业级电流互感器等,满足了不同客户的需求。
为了进一步提升公司的竞争力和市场地位,富芯森美积极寻求资本市场的支持。通过上市融资等方式,公司获得了充足的资金支持,为技术研发、市场拓展和产能扩张提供了有力保障。同时,资本市场的关注也进一步提升了富芯森美的品牌价值和市场影响力。在资本市场的助力下,富芯森美实现了快速发展,成为了电子行业中一颗璀璨的明星。
1984年,台湾的电子行业正迎来蓬勃发展的黄金时期。在这一年的10月,Bytesonic Corporation在台湾台北正式成立,标志着这家电子公司正式踏入竞争激烈的电子市场。初创时期,公司面临着资金短缺、技术匮乏等多重挑战,但凭借着创始人的远见卓识和团队的拼搏精神,公司逐渐在市场中站稳了脚跟。
随着公司规模的扩大和订单量的增加,ECLIPTEK面临着越来越大的供应链管理挑战。为了应对这些挑战,公司投入大量资源优化供应链管理,引入先进的供应链管理系统和自动化生产设备。通过提高生产效率和降低生产成本,ECLIPTEK成功地保持了其在市场上的竞争优势。
5月底,我跟经理提出了加薪申请。经过半年多的工作,大家对我的工作方式及工作效率也都有了一致赞同,单是PCB一版成功(基本都是含开关电源和视频信号的板子),也为公司省下不少的开版费,并且极大缩小了新产品开发周期。 申请的结果很不理想, ...… 查看全部问答∨ |
|
GlobalLogic 急聘Mobile Development Lead Job Responsibilities: l Lead development team to ensure development projects are delivered to clients in a timely manner and meet the company\'s standard of quality and requiremen ...… 查看全部问答∨ |
首先声明,以下只是我的个人想法,具体可行性和实现,还需要经过很过拷问 开始了 在做单片机开发的时候,特别是中小型的系统中,常常是 输入-》处理-》输出 即是根据不同的输入来处理,然后生成不输出 那么是不是可以这样来理解 将 ...… 查看全部问答∨ |
我在做一个有关SD卡的项目,项目对SD卡读写速度要求较高。我的芯片是STM32F103ZET6,现在用了一块SDHC的卡,卡的时钟现在用24MHz。4线读写。理论上可以有12MB/S的速度,现在用了STM32提供的V4.2.0版本的库,DMA模式。发现SD_ReadBlock实际读取 ...… 查看全部问答∨ |
|
招兼职vxworks相关讲师,周期短,可周末,如您想挣点外块,积累资源,充实生活,请联系我,要求有实际项目经历,两年以上项目经历,表达能力较好,有意者请联系QQ:2294693830,邮件soft@info-soft.cn。… 查看全部问答∨ |
看了例程与官方的英文资料,头都大了,不知道该如何使用F28027的内部IIC的资源。希望大家能够集体i讨论一下 ,这个网上也没有多少资料,可能是因为其他的28X的DSP芯片都没有这个模块吧。… 查看全部问答∨ |