一、环境介绍
单片机采用:STM32F103ZET6
上网方式:采用ESP8266,也可以使用其他设备代替,只要支持TCP协议即可。比如:GSM模块、有线网卡等。
与物联网云平台的通信协议: 标准MQTT协议3.1.1(TCP)
开发软件:keil5
物联网平台: 腾讯IOT物联网物联网平台。腾讯的物联网平台比起其他厂家的物联网平台更加有优势,腾讯物联网平台可以将数据推到微信小程序上,用户可以直接使用小程序绑定设备,完成与设备之间交互,现在用户基本都会使用微信,所以使用起来非常方便。
本项目完整代码下载地址: https://download.csdn.net/download/xiaolong1126626497/18973282
二、智慧农业介绍
智慧农业就是将物联网技术运用到传统农业中去,运用传感器和软件通过移动平台或者电脑平台对农业生产进行控制,使传统农业更具有“智慧”。除 了精准感知、控制与决策管理外,从广泛意义上讲,智慧农业还包括农业电子商务、食品溯源防伪、农业休闲旅游、农业信息服务等方面的内容。
所谓“智慧农业”就是充分应用现代信息技术成果,集成应用计算机与网络技术、物联网技术、音视频技术、3S技术、无线通信技术及专家智慧与知识,实现农业可视化远程诊断、远程控制、灾变预警等智能管理。
智慧农业是农业生产的高级阶段,是集新兴的互联网、移动互联网、云计算和物联网技术为一体,依托部署在农业生产现场的各种传感节点(环境温湿度、土壤水分、二氧化碳、图像等)和无线通信网络实现农业生产环境的智能感知、智能预警、智能决策、智能分析、专家在线指导,为农业生产提供精准化种植、可视化管理、智能化决策。
“智慧农业”是云计算、传感网、3S等多种信息技术在农业中综合、全面的应用,实现更完备的信息化基础支撑、更透彻的农业信息感知、更集中的数据资源、更广泛的互联互通、更深入的智能控制、更贴心的公众服务。“智慧农业”与现代生物技术、种植技术等科学技术融合于一体,对建设世界水平农业具有重要意义。
本项目采用STM32F103ZET6 + ESP8266 设计一个智慧农业管理系统, 能够获取空气中的温湿度数据,光照度数据等,根据种植区的空气温湿度数据,判断是否进行灌溉;可以通过ESP8266 + MQTT 协议将采集的温湿度、光照度上传至腾讯云物联网平台,并推送到微信小程序上实时查看;可以在小程序上直接控制电机抽水灌溉。
硬件详情介绍:
主控MCU: STM32F103ZET6
环境光传感器: BH1750
温湿度传感器: SHT30
本地OLED显示屏: 中景园电子0.96寸 SPI接口 OLED显示屏
电机: 微型直流电机
三、创建腾讯云物联网平台设备并配置微信小程序
如果之前从来没有使用过腾讯云物联网平台,创建的详细步骤请看这里: https://blog.csdn.net/xiaolong1126626497/article/details/116902653
下面就是登录腾讯云物联网平台,创建一个智慧农业的设备的关键步骤,有些细节步骤没写,细节请看上面链接这篇文章。
官网地址: https://console.cloud.tencent.com/iotexplorer
四、生成腾讯物联网平台的设备登录信息
使用MQTT协议登录需要一些参数信息,需要使用官网提供的方式生成。
Python示例代码:
-
#!/usr/bin/python
-
# -*- coding: UTF
-8 -*-
-
import base64
-
import hashlib
-
import hmac
-
import random
-
import
string
-
import time
-
import sys
-
# 生成指定长度的随机字符串
-
def RandomConnid(length):
-
return ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(length))
-
# 生成接入物联网通信平台需要的各参数
-
def IotHmac(productID, devicename, devicePsk):
-
# 1. 生成 connid 为一个随机字符串,方便后台定位问题
-
connid = RandomConnid(
5)
-
#
2. 生成过期时间,表示签名的过期时间,从纪元
1970年
1月
1日
00:
00:
00 UTC 时间至今秒数的 UTF8 字符串
-
expiry =
int(time.time()) +
30*
24*
60 *
60
-
#
3. 生成 MQTT 的 clientid 部分, 格式为 ${productid}${devicename}
-
clientid =
"{}{}".format(productID, devicename)
-
#
4. 生成 MQTT 的 username 部分, 格式为 ${clientid};${sdkappid};${connid};${expiry}
-
username =
"{};12010126;{};{}".format(clientid, connid, expiry)
-
#
5. 对 username 进行签名,生成token
-
secret_key = devicePsk.encode(
'utf-8') # convert to bytes
-
data_to_sign = username.encode(
'utf-8') # convert to bytes
-
secret_key = base64.b64decode(secret_key) #
this is still bytes
-
token = hmac.
new(secret_key, data_to_sign, digestmod=hashlib.sha256).hexdigest()
-
#
6. 根据物联网通信平台规则生成 password 字段
-
password =
"{};{}".format(token,
"hmacsha256")
-
return {
-
"clientid" : clientid,
-
"username" : username,
-
"password" : password
-
}
-
if __name__ ==
'__main__':
-
# 参数分别填入: 产品ID,设备名称,设备密匙
-
print(IotHmac(
"6142CX41XE",
"SmartAgriculture",
"20Y/aAcmj+y6SDDh+ANR9g=="))
输出的登录参数,用于MQTT协议填参数:
-
{
'clientid':
'6142CX41XESmartAgriculture',
'username':
'6142CX41XESmartAgriculture;12010126;HUA2G;1624271589',
-
'password':
'a8aadebe9721f70e6f9e14fe56ff1d2b5cac9625fa1f96af2f0e0098597fe78b;hmacsha256'}
五、使用MQTT软件测试
MQTT客户端软件下载地址: https://download.csdn.net/download/xiaolong1126626497/18784012
该软件采用QT开发,源码地址: https://blog.csdn.net/xiaolong1126626497/article/details/116779490
设备主题发布与定义的格式:
设备消息数据上传格式:
{"method":"report","clientToken":"123","params":{"light":78.4,"temperature":21.4,"humidity":60.8,"motor":1}}
登录成功之后,就可以看到设备在线:
打开微信小程序可以查看到设备上传的数据:
六、编写STM32设备端代码
6.1 main.c代码
-
#include "stm32f10x.h"
-
#include "led.h"
-
#include "delay.h"
-
#include "key.h"
-
#include "usart.h"
-
#include <string.h>
-
#include "timer.h"
-
#include "esp8266.h"
-
#include "mqtt.h"
-
#include "oled.h"
-
#include "fontdata.h"
-
#include "bh1750.h"
-
#include "iic.h"
-
#include "sht3x.h"
-
-
/*
-
硬件连接方式:
-
-
ESP8266串口WIFI模块与STM32的串口3相连接。
-
PB10--RXD 模块接收脚
-
PB11--TXD 模块发送脚
-
GND---GND 地
-
VCC---VCC 电源(3.3V~5.0V)
-
-
OLED接线:
-
D0----SCK-----PB14
-
D1----MOSI----PB13
-
RES—复位(低电平有效)—PB12
-
DC---数据和命令控制管脚—PB1
-
CS---片选引脚-----PA7
-
-
微型直流电机: PB8
-
紫光灯: PB9
-
-
LED硬件连接: PB5 PE5
-
KEY硬件连接:PE3 PE4
-
*/
-
-
#define ESP8266_WIFI_AP_SSID "CMCC-Cqvn" //将要连接的路由器名称 --不要出现中文、空格等特殊字符
-
#define ESP8266_AP_PASSWORD "99pu58cb" //将要连接的路由器密码
-
-
-
//腾讯物联网服务器的设备信息
-
#define MQTT_ClientID "6142CX41XESmartAgriculture"
-
#define MQTT_UserName "6142CX41XESmartAgriculture;12010126;HUA2G;1624271589"
-
#define MQTT_PassWord "a8aadebe9721f70e6f9e14fe56ff1d2b5cac9625fa1f96af2f0e0098597fe78b;hmacsha256"
-
-
//订阅与发布的主题
-
#define SET_TOPIC "$thing/down/property/6142CX41XE/SmartAgriculture" //订阅
-
#define POST_TOPIC "$thing/up/property/6142CX41XE/SmartAgriculture" //发布
-
-
-
char mqtt_message[
200];
//上报数据缓存区
-
char OLED_ShowBuff[
100];
-
u8 ESP8266_Stat=
0;
-
-
-
/*
-
函数功能: 温湿度\光强度显示
-
*/
-
void ShowTemperatureAndHumidity(float temp,float humi,float light)
-
{
-
sprintf(OLED_ShowBuff,
"T: %.2f",temp);
-
OLED_ShowString(
40,
16*
0,
16,OLED_ShowBuff);
-
sprintf(OLED_ShowBuff,
"H: %.2f%%",humi);
-
OLED_ShowString(
40,
16*
1,
16,OLED_ShowBuff);
-
sprintf(OLED_ShowBuff,
"L: %.2f%%",light);
-
OLED_ShowString(
40,
16*
2,
16,OLED_ShowBuff);
-
}
-
-
/*
-
函数功能: ESP8266显示页面
-
*/
-
void ESP8266_ShowPageTable(void)
-
{
-
if(ESP8266_Stat)OLED_ShowString(
0,
16*
0,
16,
"WIFI STAT:ERROR");
-
else OLED_ShowString(
0,
16*
0,
16,
"WIFI STAT:OK");
-
-
//显示字符串
-
sprintf((
char*)OLED_ShowBuff,
"%s",ESP8266_WIFI_AP_SSID);
-
OLED_ShowString(
0,
16*
1,
16,OLED_ShowBuff);
-
-
sprintf((
char*)OLED_ShowBuff,
"%s",ESP8266_AP_PASSWORD);
-
OLED_ShowString(
0,
16*
2,
16,OLED_ShowBuff);
-
}
-
-
-
int main()
-
{
-
u32 time_cnt=
0;
-
u32 i;
-
u8 key;
-
u8 page=
0;
-
float temp=
0;
-
float humi=
0;
-
float light=
0;
-
u8 motor_state=
0;
-
float Humidity;
-
float Temperature;
-
-
delay_ms(
1000);
-
delay_ms(
1000);
-
-
LED_Init();
-
KEY_Init();
-
IIC_Init();
-
-
//OLED初始化
-
OLED_Init(
0xc8,
0xa1);
//OLED显示屏初始化--正常显示;
-
//清屏
-
OLED_Clear(
0);
-
-
USART1_Init(
115200);
-
TIMER1_Init(
72,
20000);
//超时时间20ms
-
-
USART3_Init(
115200);
//串口-WIFI
-
TIMER3_Init(
72,
20000);
//超时时间20ms
-
-
Init_SHT30();
-
-
USART1_Printf(
"正在初始化WIFI请稍等.\n");
-
-
if(ESP8266_Init())
-
{
-
ESP8266_Stat=
1;
-
USART1_Printf(
"ESP8266硬件检测错误.\n");
-
}
-
else
-
{
-
//非加密端口
-
USART1_Printf(
"WIFI:%d\n",ESP8266_STA_TCP_Client_Mode(ESP8266_WIFI_AP_SSID,ESP8266_AP_PASSWORD,
"106.55.124.154",
1883,
1));
-
}
-
-
//2. MQTT协议初始化
-
MQTT_Init();
-
-
//3. 连接腾讯云IOT服务器
-
while(MQTT_Connect(MQTT_ClientID,MQTT_UserName,MQTT_PassWord))
-
{
-
USART1_Printf(
"服务器连接失败,正在重试...\n");
-
delay_ms(
500);
-
}
-
USART1_Printf(
"服务器连接成功.\n");
-
-
-
//3. 订阅主题
-
if(MQTT_SubscribeTopic(SET_TOPIC,
0,
1))
-
{
-
USART1_Printf(
"主题订阅失败.\n");
-
}
-
else
-
{
-
USART1_Printf(
"主题订阅成功.\n");
-
}
-
-
while(
1)
-
{
-
//按键可以测试开锁和关锁
-
key=KEY_Scan(
0);
-
if(key==
1)
-
{
-
//清屏
-
OLED_Clear(
0);
-
-
//翻页
-
if(page>=
1)
-
{
-
page=
0;
-
}
-
else
-
{
-
page++;
-
}
-
-
LED1=!LED1;
//LEd状态灯
-
}
-
else
if(key==
2)
-
{
-
LED1=!LED1;
//LEd状态灯
-
time_cnt=
0;
-
//电机状态改变
-
MOTOR_DEV=!MOTOR_DEV;
-
//电机状态
-
motor_state=MOTOR_DEV;
-
//补光灯
-
LIGHT_DEV=!LIGHT_DEV;
-
}
-
-
//微信小程序开锁方式: 接收WIFI返回的数据
-
if(USART3_RX_FLAG)
-
{
-
USART3_RX_BUFFER[USART3_RX_CNT]=
'\0';
-
-
//向串口打印微信小程序返回的数据
-
for(i=
0;i<USART3_RX_CNT;i++)
-
{
-
USART1_Printf(
"%c",USART3_RX_BUFFER[i]);
-
}
-
-
//如果是下发了属性,判断是开锁还是关锁
-
if(USART3_RX_CNT>
5)
-
{
-
//使用字符串查找函数
-
if(
strstr((
char*)&USART3_RX_BUFFER[
5],
"\"motor\":1"))
-
{
-
LED1=
0;
//亮灯
-
MOTOR_DEV=
1;
//开电机
-
motor_state=
1;
-
}
-
else
if(
strstr((
char*)&USART3_RX_BUFFER[
5],
"\"motor\":0"))
-
{
-
LED1=
1;
//灭灯
-
MOTOR_DEV=
0;
//关电机
-
motor_state=
0;
-
}
-
}
-
-
USART3_RX_CNT=
0;
-
USART3_RX_FLAG=
0;
-
}
-
-
//定时与保持与微信小程序的同步--1秒一次
-
delay_ms(
10);
-
time_cnt++;
-
if(time_cnt==
50)
-
{
-
time_cnt=
0;
-
-
//状态灯 --表示程序还活着
-
LED2=!LED2;
-
-
//读取光强度
-
light=Read_BH1750_Data();
-
-
//读取温湿度
-
SHT3x_ReadData(&Humidity,&Temperature);
-
humi=Humidity;
-
temp=Temperature;
-
-
//上传数据
-
sprintf(mqtt_message,
"{\"method\":\"report\",\"clientToken\":\"123\",\"params\":{\"temperature\":%f,\"humidity\":%f,\"motor\":%d,\"light\":%f}}",
-
temp,humi,motor_state,light);
-
MQTT_PublishData(POST_TOPIC,mqtt_message,
0);
-
//根据湿度自动灌溉
-
if(humi<
50.0)
//小于50自动灌溉
-
{
-
motor_state=
1;
//电机状态更新
-
MOTOR_DEV=
1;
//开电机
-
}
-
}
-
-
//OLED显示屏
-
if(page==
0)
-
{
-
ShowTemperatureAndHumidity(temp,humi,light);
-
}
-
else
if(page==
1)
-
{
-
ESP8266_ShowPageTable();
-
}
-
}
-
}
-
6.2 mqtt.c 代码
-
#include "mqtt.h"
-
-
u8 *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 00
-
const 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<
10;j++)
-
{
-
delay_ms(
50);
-
if(USART3_RX_FLAG)
-
{
-
memcpy((
char *)mqtt_rxbuf,USART3_RX_BUFFER,USART3_RX_CNT);
-
-
//memcpy
-
-
for(i=
0;i<USART3_RX_CNT;i++)USART1_Printf(
"%#x ",USART3_RX_BUFFER[i]);
-
-
USART3_RX_FLAG=
0;
-
USART3_RX_CNT=
0;
-
}
-
//CONNECT
-
if(mqtt_rxbuf[
0]==parket_connetAck[
0] && mqtt_rxbuf[
1]==parket_connetAck[
1])
//连接成功
-
{
-
return
0;
//连接成功
-
}
-
}
-
-
return
1;
-
}
-
-
/*
-
函数功能: MQTT订阅/取消订阅数据打包函数
-
函数参数:
-
topic 主题
-
qos 消息等级 0:最多分发一次 1: 至少分发一次 2: 仅分发一次
-
whether 订阅/取消订阅请求包 (1表示订阅,0表示取消订阅)
-
返回值: 0表示成功 1表示失败
-
*/
-
u8 MQTT_SubscribeTopic(char *topic,u8 qos,u8 whether)
-
{
-
u8 i,j;
-
mqtt_txlen=
0;
-
int topiclen =
strlen(topic);
-
-
int DataLen =
2 + (topiclen+
2) + (whether?
1:
0);
//可变报头的长度(2字节)加上有效载荷的长度
-
//固定报头
-
//控制报文类型
-
if(whether)mqtt_txbuf[mqtt_txlen++] =
0x82;
//消息类型和标志订阅
-
else mqtt_txbuf[mqtt_txlen++] =
0xA2;
//取消订阅
-
-
//剩余长度
-
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;
//消息标识符 MSB
-
mqtt_txbuf[mqtt_txlen++] =
0x0A;
//消息标识符 LSB
-
//有效载荷
-
mqtt_txbuf[mqtt_txlen++] = BYTE1(topiclen);
//主题长度 MSB
-
mqtt_txbuf[mqtt_txlen++] = BYTE0(topiclen);
//主题长度 LSB
-
memcpy(&mqtt_txbuf[mqtt_txlen],topic,topiclen);
-
mqtt_txlen += topiclen;
-
-
if(whether)
-
{
-
mqtt_txbuf[mqtt_txlen++] = qos;
//QoS级别
-
}
-
-
for(i=
0;i<
10;i++)
-
{
-
memset(mqtt_rxbuf,
0,mqtt_rxlen);
-
MQTT_SendBuf(mqtt_txbuf,mqtt_txlen);
-
for(j=
0;j<
10;j++)
-
{
-
delay_ms(
50);
-
if(USART3_RX_FLAG)
-
{
-
memcpy((
char *)mqtt_rxbuf,(
char*)USART3_RX_BUFFER,USART3_RX_CNT);
-
USART3_RX_FLAG=
0;
-
USART3_RX_CNT=
0;
-
}
-
-
if(mqtt_rxbuf[
0]==parket_subAck[
0] && mqtt_rxbuf[
1]==parket_subAck[
1])
//订阅成功
-
{
-
return
0;
//订阅成功
-
}
-
}
-
}
-
return
1;
//失败
-
}
-
-
//MQTT发布数据打包函数
-
//topic 主题
-
//message 消息
-
//qos 消息等级
-
u8 MQTT_PublishData(char *topic, char *message, u8 qos)
-
{
-
int topicLength =
strlen(topic);
-
int messageLength =
strlen(message);
-
static u16 id=
0;
-
int DataLen;
-
mqtt_txlen=
0;
-
//有效载荷的长度这样计算:用固定报头中的剩余长度字段的值减去可变报头的长度
-
//QOS为0时没有标识符
-
//数据长度 主题名 报文标识符 有效载荷
-
if(qos) DataLen = (
2+topicLength) +
2 + messageLength;
-
else DataLen = (
2+topicLength) + messageLength;
-
-
//固定报头
-
//控制报文类型
-
mqtt_txbuf[mqtt_txlen++] =
0x30;
// MQTT Message Type PUBLISH
-
-
//剩余长度
-
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++] = BYTE1(topicLength);
//主题长度MSB
-
mqtt_txbuf[mqtt_txlen++] = BYTE0(topicLength);
//主题长度LSB
-
memcpy(&mqtt_txbuf[mqtt_txlen],topic,topicLength);
//拷贝主题
-
mqtt_txlen += topicLength;
-
-
//报文标识符
-
if(qos)
-
{
-
mqtt_txbuf[mqtt_txlen++] = BYTE1(id);
-
mqtt_txbuf[mqtt_txlen++] = BYTE0(id);
-
id++;
-
}
-
memcpy(&mqtt_txbuf[mqtt_txlen],message,messageLength);
-
mqtt_txlen += messageLength;
-
-
MQTT_SendBuf(mqtt_txbuf,mqtt_txlen);
-
return mqtt_txlen;
-
}
-
-
void MQTT_SentHeart(void)
-
{
-
MQTT_SendBuf((u8 *)parket_heart,
sizeof(parket_heart));
-
}
-
-
void MQTT_Disconnect(void)
-
{
-
MQTT_SendBuf((u8 *)parket_disconnet,
sizeof(parket_disconnet));
-
}
-
-
void MQTT_SendBuf(u8 *buf,u16 len)
-
{
-
USARTx_DataSend(USART3,buf,len);
-
}
转载:https://blog.csdn.net/xiaolong1126626497/article/details/117167261