当前位置: 首页 > news >正文

云平台+MQTT+C#上位机+单片机通信

1、MQTT协议

MQTT Version 3.1.1

一个 MQTT 数据包由: 固定头(Fixed header)、可变头(Variable header)、消息体(payload)三部分构成

(1) 固定头(Fixed header)。存在于所有 MQTT 数据包中,包含内容如MQTT报文类型(连接,断开连接,发布,订阅,心跳请求,心跳响应等)、Qos等级(0:最多分发一次,1:最少分发一次,2:只分发一次)等。
(2) 可变头(Variable header)。存在于部分 MQTT 数据包中,数据包类型决定了可变头是否存在及其具体内容。可变头部不是可选的意思,而是指这部分在有些协议类型中存在,在有些协议中不存在。
(3) 消息体(Payload)。存在于部分 MQTT 数据包中,表示客户端收到的具体内容。与可变头一样,在有些协议类型中有消息内容,有些协议类型中没有消息内容。

针对固定头和可变头的协议,一般进行上位机和单片机开发时都会移植第三方库,然后我们主要将焦点放在消息体上,传输数据时给消息体增加一个什么协议,方便数据的发送和解析

MQTT是一种轻量级的发布/订阅协议,适合物联网和低带宽环境。云平台可能需要处理大量设备连接,此时MQTT的高效性和低开销就很有优势。 

2、C#上位机连接云平台

(1)、框架升级:升级为 .NET Framework 4.8

(2)、安装MQTT Net程序包:建议选择4.3.6.1152版本,高版本未必可以使用,低版本API不相同

(3)、添加控件:云平台连接的几个参数:ip,port,username,password,clientId。

注意:

ip:服务器的ip地址,阿里云物联网云平台MQTT客户端直连:设备使用TCP接入的安全风险非常高,新建的企业版实例默认关闭TCP(非TLS加密)接入方式。有的云平台可以用ip连接,但有的只能用mqttHostUrl连接

clientId:表示客户端ID,可自定义,长度不可超过64个字符。建议使用设备的MAC地址或SN码,方便您识别区分不同的客户端。不同的云平台对其定义不一致,有的云平台对其值不做任何限制,有的云平台clientID必须完全匹配

(4)、代码编写

using MQTTnet;
using MQTTnet.Client;
using MQTTnet.Client.Internal;  IMqttClient mqttClient = new MqttFactory().CreateMqttClient();//连接阿里云平台private async void button_mqtt_connect_Click(object sender, EventArgs e){try{ if (button_mqtt_connect.Text == "连接"){string ip = textbox_mqtt_ip.Text;int port = Convert.ToInt32(textbox_mqtt_port.Text);string username = textbox_mqtt_username.Text;string password = textbox_mqtt_password.Text;string clientId = textbox_mqtt_clientId.Text;var options = new MqttClientOptionsBuilder().WithTcpServer(ip, port).WithCredentials(username, password).WithClientId(clientId).Build();mqttClient.ApplicationMessageReceivedAsync += MqttClient_ApplicationMessageReceivedAsync;//处理订阅主题报文//设置成功连接回调,用于订阅消息mqttClient.ConnectedAsync += async Connect =>{button_mqtt_connect.Invoke((Action)(() => button_mqtt_connect.Text = "断开"));//button_mqtt_connect.Text = "断开";string LogShow = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff") + "  连接服务器成功" + "\r\n";Invoke(new Action(() => textBox_mqtt_recv.AppendText(LogShow)));string topic = "0x04/" + textbox_mqtt_sn.Text;await mqttClient.SubscribeAsync(new MqttTopicFilterBuilder().WithTopic(topic).Build());Invoke(new Action(() => textBox_mqtt_recv.AppendText("subscribe topic:" + topic + "\r\n")));};//设置断开连接回调mqttClient.DisconnectedAsync += async Disconnect =>{//button_mqtt_connect.Text = "连接";button_mqtt_connect.Invoke((Action)(() => button_mqtt_connect.Text = "连接"));string LogShow = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff") + "  断开服务器" + "\r\n";Invoke(new Action(() => textBox_mqtt_recv.AppendText(LogShow)));};//连接到MQTT服务器await mqttClient.ConnectAsync(options);}else{//button_mqtt_connect.Text = "连接";button_mqtt_connect.Invoke((Action)(() => button_mqtt_connect.Text = "连接"));mqttClient.DisconnectAsync();}}catch (Exception ex){MessageBox.Show(ex.Message);}}private Task MqttClient_ApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs arg){var message = arg.ApplicationMessage;var Messagehex = new StringBuilder(message.Payload.Length * 2);foreach (byte b in message.Payload){Messagehex.AppendFormat("{0:X2}", b); // 大写字母,如需小写改为 "x2"}string payload = Messagehex.ToString();string TopicLogShow = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff") + "收到主题:" + message.Topic + "  消息:" + payload+ "\r\n";Invoke(new Action(() => textBox_mqtt_recv.AppendText(TopicLogShow)));    throw new NotImplementedException();}private void button_mqtt_publish_Click(object sender, EventArgs e){try{if (mqttClient.IsConnected){byte[] payload = { 0x5A,0x5A};string topic = "0x04/" + textbox_mqtt_sn.Text;//主题如果错误,则会断开连接mqttClient.PublishBinaryAsync(topic, payload);Invoke(new Action(() => textBox_mqtt_recv.AppendText("publish topic :" + topic + "\r\n")));}}catch (Exception ex){MessageBox.Show(ex.Message);}}

(5)、测试结果

3、单片机连接云平台

(1)、下载MQTT 源码

GitHub - eclipse-paho/paho.mqtt.embedded-c: Paho MQTT C client library for embedded systems. Paho is an Eclipse IoT project (https://iot.eclipse.org/)

(2)工程中新建一个MQTT文件夹

        将压缩包中paho.mqtt.embedded-c-master.zip\paho.mqtt.embedded-c-master\MQTTPacket\src 中的全部文件以及paho.mqtt.embedded-c-master.zip\paho.mqtt.embedded-c-master\MQTTPacket\samples 内的transport.c和transport.h拷入MQTT文件夹

 

(3)修改源码

第一步:

我们需要做的事情很简单, 只需要修改transport.c中的2个函数即可:
int transport_sendPacketBuffer(unsigned char* buf, int buflen);
int transport_getdata(unsigned char* buf, int count);
剩下的这三个可以不用去管,直接清空函数内容返回0即可
int transport_getdatanb(void *sck, unsigned char* buf, int count);
int transport_open(char* host, int port);
int transport_close(int sock);

//该函数把sock参数删除,原因是源代码使用sock发送数据,此处不需要
int transport_sendPacketBuffer( unsigned char* buf, int buflen)
{WiFi_SendString(buf,buflen);return 1;
}int transport_getdata(unsigned char* buf, int count)
{memcpy(buf,usart1_rcv_buf,count);return count;
}int transport_getdatanb(void *sck, unsigned char* buf, int count)
{return 0;
}int transport_open(char* addr, int port)
{return 0;
}int transport_close(int sock)
{return 0;
}

第二步:

编译报错,发现 cannot open source input file "sys/types.h",将tranport.c除开函数的部分全部删除,加入自己所需的头文件

#include "main.h"
#include "transport.h"

第三步:

新增连接云平台函数,订阅和发布函数

#include "main.h"
#include "transport.h"
#include "MQTTPacket.h"char *pubtopic="Topic_Send";//设备发送的主题,服务器订阅的主题
char *subtopic = "Topic_Receive";//设备接收的主题,服务器发送的主题#define MQTT_MAX_BUFF 200
uint8_t S_mqtt_buf[MQTT_MAX_BUFF] = {0};//调用此函数前需要确保单片机已经连接了服务器
void mqtt_connect(void)
{MQTTPacket_connectData data = MQTTPacket_connectData_initializer;//配置可变头部分data.clientID.cstring = "ClientID";//设备唯一ID,请向服务器端工程师索要或者商量制定data.keepAliveInterval = 60;//保活计时器,即连续两次心跳包发送的最大时间间隔(单位:秒)data.cleansession = 1;//1:丢弃之前的连接信息data.username.cstring = "userName" ;//用户名,向服务器端工程师索要即可data.password.cstring = "password";//密码,向服务器端工程师索要即可data.MQTTVersion = 4;memset(S_mqtt_buf,0,MQTT_MAX_BUFF);uint32_t len = MQTTSerialize_connect(S_mqtt_buf, MQTT_MAX_BUFF, &data); //构建连接报文并获取长度transport_sendPacketBuffer(S_mqtt_buf,len);//通过硬件接口发送给服务器已经封装好的报文//等待连接成功//wifi进入透传模式发送数据后,如果串口接收中断接受到报文信息,则说明连接成功
}void MQTTSendHeartbeat(void)
{unsigned char h_buf[200] = {0};//长度自行设定测试uint8_t len = MQTTSerialize_pingreq(h_buf, 200);//调用mqtt心跳包封装函数transport_sendPacketBuffer((unsigned char*)h_buf, len);//发送数据
}int mqtt_publish(char *pTopic,char *pMessage,uint8_t msglen)
{MQTTString topicString = MQTTString_initializer;topicString.cstring = pTopic;memset(S_mqtt_buf,0,MQTT_MAX_BUFF);int32_t  len = MQTTSerialize_publish(S_mqtt_buf, MQTT_MAX_BUFF, 0, 0, 0, 0, topicString, (unsigned char*)pMessage, msglen); //transport_sendPacketBuffer(S_mqtt_buf,len);//return 0;
}int mqtt_subscribe(char *pTopic)
{int32_t len;MQTTString topicString = MQTTString_initializer;memset(S_mqtt_buf,0,MQTT_MAX_BUFF);topicString.cstring = pTopic;len = MQTTSerialize_subscribe(S_mqtt_buf, MQTT_MAX_BUFF, 0, 1, 1, &topicString, 0);transport_sendPacketBuffer((unsigned char*)S_mqtt_buf, len);return 0;
}

第四步:开始验证代码移植情况

如果没有联网条件,可以通过查看报文来判断是否移植成功,首先通过网络调试助手连接到服务器,然后发送报文数据到服务器,就可以连接成功,报文的详细解释可以看下面的博客

网络调试助手使用MQTT协议与Mosquitto通信(3)_mqtt调试助手-CSDN博客

http://www.xdnf.cn/news/176473.html

相关文章:

  • 在 UniApp 中实现 App 与 H5 页面的跳转及通信
  • lightrag : from lightrag.utils import EmbeddingFunc 报错
  • 04.通过OpenAPI-Swagger规范让Dify玩转Agent
  • 【Redis】set类型
  • JavaEE-多线程实战02
  • AI如何重塑CC防护行业?五大变革与实战策略解析
  • 【创新实训个人博客】multi-agent调研(2)
  • promis(resolve,reject)入门级别
  • 互联网大厂Java面试:从Spring Boot到微服务架构的实践与挑战
  • 智诚科技苏州SOLIDWORKS授权代理商的卓越之选
  • vite.config.ts 的详细配置项说明、完整代码示例及表格总结
  • 代码随想录算法训练营day12(二叉树)
  • javaScript--数据结构和算法
  • 轮转数组(中等)
  • 如何优雅地解决AI生成内容粘贴到Word排版混乱的问题?
  • 从“世界工厂”到“智造之都”:双运放如何改写东莞产业基因?
  • JavaScript 中 undefined 和 not defined 的区别
  • Dev控件RadioGroup 如何设置一排有N个显示或分为几行
  • 使用cesium设置第一视角
  • 第2讲、Tensor高级操作与自动求导详解
  • w~嵌入式C语言~合集6
  • 【计算机哲学故事1-2】输入输出(I/O):你吸收什么,便成为什么
  • APP、游戏、网站被黑客攻击了怎么解决?
  • MongoDB 操作全解析:从部署到安全控制的详细指南(含 emoji 趣味总结)
  • 京东商品详情数据爬取难度分析与解决方案
  • Spark-Streaming核心编程(3)
  • windows开启内测压缩(亲测可用)
  • uniapp-商城-40-shop 购物车 选好了 进行订单确认4 配送方式3 地址编辑
  • C++和Java该如何选择?
  • DeepSeek智能时空数据分析(四):绘制行政区域并定制样式