ESA2GJK1DH1K基础篇: APP使用SmartConfig绑定Wi-Fi 设备并通过MQTT控制设备--单片机源码讲解(SimplePackage)

2020-03-23 11:46:41 浏览数 (1)

前言

  代码中的运行流程已经在 

https://cloud.tencent.com/developer/article/1602667

  文章的最后做了介绍

  其实咱学东西最主要的是学以致用,应用到自己的工程项目里面

  这节着重说一下如何把源码中的MQTT底层包移植到用户自己的工程

  这节代码只是讲解详细流程,并不可以使用

  这节代码使用的底层:

https://cloud.tencent.com/developer/article/1602665

  这节代码是在底层又做了一层封装

  主要是加入了数据缓存发送,便于处理消息等级为1和2的消息

准备一个空的工程

  1.注:请自行准备一个已经可以实现TCP连接的工程

  由于用的网络芯片不一样,连接方式不一样,本人就在工程中假设连接了TCP

  2.把以下文件放入自己的工程

  添加一个文件夹

  添加文件

  添加MQTT文件中的所有文件

  添加头文件路径

包含mqtt.h 编译下

错误原因

这是两个把数据发送给网络模块的函数

这两个函数需要根据自己的修改

用户需要把数据发送给网络模块的函数放到此处

就是模块作为TCP客户端,把TCP客户端发送数据给TCP服务器数据的函数放在这里

大家不要有任何的疑问,让您怎么做就怎么做就可以!!!!

在1ms定时器中放入以下函数

#include "mqtt.h"

mqtt_time_data(&mymqtt);

连接MQTT

1.用一些数组存储连接MQTT的信息

注册连接和断开函数

代码语言:javascript复制
unsigned char MQTTid[50] = "123456789";//ClientID
unsigned char MQTTUserName[20] = "yang";//用户名
unsigned char MQTTPassWord[50] = "11223344";//密码
unsigned char MQTTkeepAlive = 30;//心跳包时间
unsigned char MQTTPublishTopic[30]="1111";//存储MQTT发布的主题
unsigned char MQTTWillMessage[50] = "{"data":"status","status":"offline"}";//遗嘱消息
unsigned char MQTTWillQos = 0;//消息等级
unsigned char MQTTWillRetained = 1;//是否需要服务器记录
代码语言:javascript复制
/**连接上MQTT回调函数
* @brief   连接上MQTT回调函数
* @param   None
* @retval  None
* @warning None
* @example
**/
void MqttConnect()
{
    
}

/**MQTT断开连接回调
* @brief   MQTT断开连接回调
* @param   None
* @retval  None
* @warning None
* @example
**/
void MqttDisConnect()
{
    mqtt_init(&mymqtt);
}
代码语言:javascript复制
    mqtt_init(&mymqtt);
    mqtt_connect_reg(&mymqtt,MqttConnect);//注册连接回调函数
    mqtt_disconnect_reg(&mymqtt,MqttDisConnect);//注册断开连接回调函数

注:如果不想使用遗嘱,可自行屏蔽

2.实现具体的连接

用户先用自己的模块用TCP连接上TCP服务器(MQTT服务器)

然后发送连接MQTT指令

最后判断下是否连接成功

代码语言:javascript复制
int len;//获取数据长度
unsigned char *str;//打包的数据首地址
char ConnectedMqttFlag;//1:连接上MQTT 0:未连接
代码语言:javascript复制
if(ConnectedMqttFlag == 0){//没有连接上MQTT
            //用户先自行控制模块以TCP方式连接上MQTT服务器
            //发送连接MQTT的指令
            mymqtt.mqtt_connect_info.client_id = MQTTid;//client_id
            mymqtt.mqtt_connect_info.keepalive = MQTTkeepAlive;//心跳包时间
            mymqtt.mqtt_connect_info.username = MQTTUserName;//用户名
            mymqtt.mqtt_connect_info.password = MQTTPassWord;///密码
            mymqtt.mqtt_connect_info.will_topic = MQTTPublishTopic;//遗嘱发布的主题
            mymqtt.mqtt_connect_info.will_message = MQTTWillMessage;//遗嘱的消息
            mymqtt.mqtt_connect_info.will_qos = MQTTWillQos;//遗嘱的消息等级
            mymqtt.mqtt_connect_info.will_retain = MQTTWillRetained;//是否需要服务器保留消息
            mymqtt.mqtt_connect_info.clean_session = 1;//清除连接信息
            
            len = mqtt_connect(&mymqtt,&str);//打包连接信息
            //打包的数据首地址 str 数据长度:len
            if(len>0){ 
                UsartOutStr(str,len);//发送MQTT协议数据给网络模块,其实就是TCP客户端发送数据给服务器(请根据自己的替换)
            }
            //发送完连接指令以后,MQTT服务器会返回连接信息,请按照下面程序处理信息
            //判断模块是否连接上,假设模块返回的数据存入了Usart1ReadBuff数组
            if(mqtt_connect_ack(Usart1ReadBuff)==0)//连接上了MQTT
            {
                ConnectedMqttFlag = 1;//连接上MQTT
                if(mymqtt.connectCb){//调用连接回调函数
                    mymqtt.connectCb();
                }
            }
        }

3.如果断开连接,需要让模块重新连接MQTT,请在断开连接回调函数中

代码语言:javascript复制
ConnectedMqttFlag=0;//断开连接以后,重新配置模块连接

接收处理通信过程中的各种数据

1.后期的通信都是利用数据缓存实现,请先添加以下程序

代码语言:javascript复制
        if(ConnectedMqttFlag)//配置模块成功(模块连接了MQTT)
        {
            mqtt_send_function(&mymqtt);//提取发送缓存的MQTT协议
            mqtt_keep_alive(&mymqtt);//处理发送心跳包
            
            //网络模块接收到了数据
            if(1)//此处请根据自己的网络模块自行修改
            {
                //假设网络接收到的数据:Usart1ReadBuff  数据长度:Usart1ReadCntCopy
                mqtt_read_function(&mymqtt,Usart1ReadBuff,Usart1ReadCntCopy);
            }
        }

2.注册接收数据函数

代码语言:javascript复制
/**
* @brief   MQTT接收数据回调
* @param   topic:主题
* @param   topic_len:主题长度
* @param   data:接收的数据
* @param   lengh:接收的数据长度
* @retval  None
* @warning None
* @example
**/
void MqttReceive(const char* topic, uint32_t topic_len,const char *data, uint32_t lengh)//接收到数据回调
{
    
}
代码语言:javascript复制
mqtt_received_reg(&mymqtt,MqttReceive);//注册接收数据回调函数

订阅主题

1.一般可以在连接成功回调函数里面订阅主题

当然只要连接上以后,可以在程序的任何地方执行订阅函数

代码语言:javascript复制
unsigned char MQTTSubscribeTopic[30]="2222";//存储MQTT订阅的主题
代码语言:javascript复制
/**订阅主题成功
* @brief   订阅主题成功
* @param   None
* @retval  None
* @warning None
* @example
**/
void subscribedCb(int pdata)
{
    
}

/**订阅主题失败
* @brief   订阅主题失败
* @param   None
* @retval  None
* @warning None
* @example
**/
void failsubscribedCb(int pdata)
{
    
}
代码语言:javascript复制
mqtt_subscribe(&mymqtt, MQTTSubscribeTopic,0,subscribedCb,failsubscribedCb);//订阅主题

订阅的消息等级支持0,1,2

mqtt_subscribe(&mymqtt, MQTTSubscribeTopic,0,subscribedCb,failsubscribedCb);

mqtt_subscribe(&mymqtt, MQTTSubscribeTopic,1,subscribedCb,failsubscribedCb);

mqtt_subscribe(&mymqtt, MQTTSubscribeTopic,2,subscribedCb,failsubscribedCb);

发布消息

1.列如:把接收的消息发布出去

代码语言:javascript复制
/**
* @brief   发布成功
* @param   None
* @retval  None
* @warning None
* @example
**/
void PublishedCb()
{
    
}

/**
* @brief   MQTT接收数据回调
* @param   topic:主题
* @param   topic_len:主题长度
* @param   data:接收的数据
* @param   lengh:接收的数据长度
* @retval  None
* @warning None
* @example
**/
void MqttReceive(const char* topic, uint32_t topic_len,const char *data, uint32_t lengh)//接收到数据回调
{
    mqtt_publish(&mymqtt,MQTTPublishTopic,(unsigned char*)data,topic_len, 0, 1,PublishedCb);//发布消息
}

提示:只有发布的消息等级是1/2的时候,服务器才会有应答信息

所以只有1/2的时候才会进入发布成功回调函数

深入源码

1.要想知道底层如何封装处理的,必须知道的基础知识

https://cloud.tencent.com/developer/article/1583664

2.订阅主题,发布消息,发送心跳包的数据都存储在了缓存里面

程序中默认每隔20Ms提取一次

注:特殊的地方会超过20Ms

提取数据

这个函数一开始让大家放在了1Ms定时器里面

深入源码之-订阅主题0

1.订阅主题

2.提取到数据,发给服务器

有些需要等待服务器返回的地方都会启用超时检测

超时时间归零以后,才会把后面缓存的其它数据发送给服务器

3.判断服务器的返回

深入源码之-发布消息,消息等级0

因为消息等级0不需要任何的应答,所以组合的消息直接用TCP发送出去

深入源码之-发布消息,消息等级1

深入源码之-发布消息,消息等级2

深入源码之-接收消息,消息等级1

深入源码之-接收消息,消息等级2

深入源码之-心跳包

1.心跳包内部自动处理,用户只需要调用以下函数

mqtt_keep_alive(&mymqtt);

2.处理思路

到达发送心跳包时间,把心跳包数据插入缓存,

如果超过5S服务器没有返回应答,则再发一次

如果超过5S还是没有返回应答,则执行mqtt断开连接函数

返回了心跳应答,清零所有关于心跳包的变量,重新开始计数

注:鉴于如果MQTT服务器一直处于发送其余数据的状态,

那么服务器会延迟发送过来心跳包应答

所以,只要MQTT服务器返回其它数据,就清零心跳包变量

0 人点赞