单片机使用C语言实现MQTT协议
在单片机使用MQTT协议非常普遍,特别是在物联网相关领域,在阿里云,华为云等公有云都提供MQTT协议连接物联网平台。 本篇介绍如何用C语言实现MQTT的连接
MQTT连接主要有五步骤: 1. 连接云平台 2. 登录用户名密码等 3. 订阅主题 4. 发送心跳包 5. 发布主题
1. 连接云平台跟其他网站一样,只要有服务器地址和端口号就行,在这里我使用了以太网口去连接 代码如下:
u16 AnalyTarIp(u8 *TarIp,u16 port,u8 i)
{
static u8 dnsSel = 0;
u16 stateStamp;
uip_ipaddr_t ipaddr;
u8 ip[4];
g_mconn[i].flag = 0;
stateStamp = GetSecCnt();
//á??ó·t???÷
g_mconn[i].port = port; //端口
//IP还是域名
if(IsIPaVailable(TarIp)) //IP
{
if(str2ip(ip, TarIp)) //str To num
{
uip_ipaddr(&ipaddr, ip[0], ip[1], ip[2], ip[3]);
uip_ipaddr_copy(g_mconn[i].ip, ipaddr); //记录IP
S282_Log("uip connecting...");
g_mconn[i].tcp = uip_connect(&g_mconn[i].ip, htons(g_mconn[i].port));
g_mconn[i].state = TcpClient_Connectting;
stateStamp = GetSecCnt();
}
}
else //域名
{
u8 HaveDns = 0;
if(DhcpOk == 0)
{
if(dnsSel == 0)
{
if(SysInfo.DnsIp1[1] != 0 && SysInfo.DnsIp1[0] != 0xff)
{
uip_ipaddr(ipaddr, SysInfo.DnsIp1[0],SysInfo.DnsIp1[1],SysInfo.DnsIp1[2],SysInfo.DnsIp1[3]);
HaveDns = 1;
}
if(SysInfo.DnsIp2[1] !=0 || SysInfo.DnsIp1[2] !=0 )
{
dnsSel = 1;
}
}
if((HaveDns == 0) && dnsSel)
{ //DNS2
dnsSel = 0;
if(SysInfo.DnsIp2[1] != 0 && SysInfo.DnsIp2[0] != 0xff)
{
uip_ipaddr(ipaddr, SysInfo.DnsIp2[0],SysInfo.DnsIp2[1],SysInfo.DnsIp2[2],SysInfo.DnsIp2[3]);
HaveDns = 1;
}
}
}
if(HaveDns || DhcpOk)
{//进行域名解析
g_mconn[i].state = TcpClient_DnsRequest;
g_mconn[i].flag &= ~e_Dns_found;
S282_Log("Analy Target Server ip");
if(resolv_getserver() == NULL)
{
resolv_conf(ipaddr); //配置DNS服务器
}
g_mconn[i].dnsno = resolv_query((char*)&TarIp[0]);//请求域名解析
g_mconn[i].dnsno |= 0x80;
stateStamp = GetSecCnt();
}
}
return stateStamp;
}
域名解析成功后直接连接
g_mconn[i].tcp = uip_connect(&g_mconn[i].ip, htons(g_mconn[i].port));
g_mconn[i].state = TcpClient_Connectting;
- 登录用户 需要用户名 密码和设备ID
代码如下:
/*
MQTT 连接
入参 mode: 0 GPRS网络 1 以太网网络
*/
void MqttConnect(u8 mode)
{
u8 i;
u16 len;
MQTTPacket_connectData mqttConnDat = MQTTPacket_connectData_initializer;
GetMqttConnectData(m_mqttBuf,M_CLIENT);
if(SysInfo.MqttDeviceID[MQT_TXT_DATLEN] == 0)
{
//设备ID为空使用IMEI码
for(i = 0; i < 15; i++)
{
m_mqttBuf[i] = g_IMEI[i];
}
m_mqttBuf[i] = '\0';
}
if(SysInfo.MqttUserName[MQT_TXT_DATLEN] == 0)
{
//MQTT用户名为空 用默认值
for(i = 0; i < 4; i++)
{
m_mqttBuf[i + MQTT_PWD] = mqttDef[i];
}
m_mqttBuf[i] = '\0';
}
if(SysInfo.MqttPwd[MQT_TXT_DATLEN] == 0)
{
//MQTT密码为空 用默认值
for(i = 0; i < 4; i++)
{
m_mqttBuf[i + MQTT_PWD * 2] = mqttDef[i];
}
m_mqttBuf[i] = '\0';
}
mqttConnDat.clientID.cstring = (char *)m_mqttBuf;
//心跳存活时间根据平台需求设置
mqttConnDat.keepAliveInterval = SysInfo.MqttRepTim;
mqttConnDat.cleansession = 1;
mqttConnDat.username.cstring = (char *)&m_mqttBuf[MQTT_PWD];
mqttConnDat.password.cstring = (char *)&m_mqttBuf[MQTT_PWD * 2];
len = MQTTSerialize_connect(m_sendBuf,MQTT_PWD * 3,&mqttConnDat);
if(mode == 0)
{
SendGprsDat(m_sendBuf,len);
}
else
{
UipClient2Server(m_sendBuf,len);
}
}
- 订阅主题 这里我以tlink物联网平台为准
/*
MQTT订阅主题
*/
void MqttSubscribe(u8 mode)
{
//·服务质量
int qos = 0;
u16 len,i;
GetMqttConnectData(m_mqttBuf,M_SUBSCRIBE);
if(!ISASCCHAR(m_mqttBuf[0]))
{//tlink平台要求订阅主题为序列号+"/+"
GetMqttConnectData(m_mqttBuf,M_CLIENTID);
if(!ISASCCHAR(m_mqttBuf[0]))
{
for(i = 0; i < 15; i++)
{
m_mqttBuf[i] = g_IMEI[i];
}
m_mqttBuf[i] = '\0';
}
for(i = 0; i < 60; i++)
{
if(!ISASCCHAR(m_mqttBuf[i]))
{
break;
}
}
m_mqttBuf[i++] = '/';
m_mqttBuf[i++] = '+';
m_mqttBuf[i++] = '\0';
}
topicString.cstring = (char *)m_mqttBuf;
len = MQTTSerialize_subscribe(m_sendBuf,MQTT_PWD * 3,0,PacketId,1,&topicString,&qos);
PacketId++;
if(mode == 0)
{
SendGprsDat(m_sendBuf,len);
}
else
{
UipClient2Server(m_sendBuf,len);
}
}
- 发送心跳包,根据自己要求隔段时间发送
/*
MQTT Ping
防止MQTT断开连接
*/
void MqttPingReq(u8 mode)
{
u16 len;
len = MQTTSerialize_pingreq(m_mqttBuf,MQTT_PWD * 3);
if(mode == 0)
{
SendGprsDat(m_mqttBuf,len);
}
else
{
UipClient2Server(m_mqttBuf,len);
}
}
- 发布主题 根据自己要求处理
/*
MQTT 发布主题
入参: InBuf 要发送的数据
len 发送数据长度 mode 发送方式
*/
void MqttPublish(u8 *InBuf,u16 len,u8 mode)
{
u8 qos = 1;
u16 i;
GetMqttConnectData(m_mqttBuf,M_PUBLISH);
if(!ISASCCHAR(m_mqttBuf[0]))
{//没有填写发布主题 用IMEI码
GetMqttConnectData(m_mqttBuf,M_CLIENTID);
if(!ISASCCHAR(m_mqttBuf[0]))
{
for(i = 0; i < 15; i++)
{
m_mqttBuf[i] = g_IMEI[i];
}
m_mqttBuf[i] = '\0';
}
}
memset(m_sendBuf,0,1000);
topicString.cstring = (char *)m_mqttBuf;
len = MQTTSerialize_publish(m_sendBuf, 1000, 0, qos, 0, PacketId, topicString, InBuf, len);
PacketId++;
if(mode == 0)
{
SendGprsDat(m_sendBuf,len);
}
else
{
UipClient2Server(m_sendBuf,len);
}
}
以上是MQTT实现步骤,只要按步骤实现,基本可以完成,但也需要根据个人要求更改。
|