前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ESA2GJK1DH1K基础篇: APP使用SmartConfig绑定Wi-Fi 设备并通过MQTT控制设备--单片机源码讲解(SimplePackage)

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

作者头像
杨奉武
发布2020-03-23 11:46:41
4630
发布2020-03-23 11:46:41
举报
文章被收录于专栏:知识分享知识分享

前言

  代码中的运行流程已经在 

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服务器返回其它数据,就清零心跳包变量

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-03-21 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 准备一个空的工程
  • 包含mqtt.h 编译下
  • 在1ms定时器中放入以下函数
  • 连接MQTT
  • 接收处理通信过程中的各种数据
  • 订阅主题
  • 发布消息
  • 深入源码
  • 深入源码之-订阅主题0
  • 深入源码之-发布消息,消息等级0
  • 深入源码之-发布消息,消息等级1
  • 深入源码之-发布消息,消息等级2
  • 深入源码之-接收消息,消息等级1
  • 深入源码之-接收消息,消息等级2
  • 深入源码之-心跳包
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档