MQTT 协议学习:008-在STM32上移植MQTT

--- title: protocol-app-mqtt-8-porting-mqtt-on-stm32 date: 2020-02-07 14:16:51 categories: tags: - mqtt - protocol - stm32 - porting ---

前言

通过前面了解MQTT有关概念、分析了有关的报文,我们对于这个协议也有了更深的认识。但纸上谈来终觉浅,绝知此事要躬行

本文参考:《STM32+W5500+MQTT+Android实现远程数据采集及控制》《物联网核心之MQTT移植 》《基于联盛德w600的mqtt客户端程序示例》
host平台   :Ubuntu 16.04
Taget :STM32 + W5500。
MQTT-client : paho.mqtt.embedded-c

W5500 - 芯片介绍

全硬件TCPIP协议栈

  • 支持TCP,UDP,ICMP,IPv4,ARP,IGMP,PPPoE协议
  • 硬件协议栈不受网络攻击,安全稳定

8个独立的硬件Socket,各路通信互不影响
32KB片上缓存供TCP/IP包处理
集成802.3以太网MAC
集成10BaseT / 100Base-T以太网PHY
主机接口:SPI高速串行外设接口(最高80Mhz )

低功耗,工作温度40℃左右
支持嵌入式操作系统:Linux & RTOS
支持掉电模式 & UDP网络唤醒
工作电压3.3V,I/O 5V耐压
支持自动协商(全/半双工,10M/100M)
48Pin LQFP无铅封装(7x7mm, 0.5mm针间距)

W5500以太网芯片内核

全硬件TCP/IP协议栈以太网接入方案

MCU <---spi---> w5500 <------> 以太网
MCU : 应用层
w5500 : 传输层,网络层,链路层,物理层

方案介绍

STM32 <---spi---> W5500 <------> 以太网
实际上,单片机这块有很多的方案:RTL8711(WIFI SOC) + LWIP + FreeRTOS + MQTTESP8266 + MQTT

1)STM32F405为主控芯片,它通过传感器采集环境数据,比如温度,湿度,光照度,大气压强等;
2)主控芯片通过W5500模块将测量的数据通过MQTT协议方式发布到MQTT服务器(服务器域名和IP见固件程序);
3)主控订阅LED灯控制的消息,当接收到对应的控制指令后点亮或者熄灭对应的LED灯;
4)安卓手机端订阅传感器数据的消息,当接收到消息后将传感器数据在界面显示;
5)安卓手机可发送点亮或者熄灭LED灯的指令到服务器,然后服务器会将该指令转发给STM32主控,然后STM32主控解析该指令并执行指令。

准备

1)下载 MQTT客户端 源码

2)解压源码,再进入MQTTPacket文件夹,里面有三个文件夹。
A)) 拷贝 src 下 所有 *.c *.hsamples下的transport.c、transport.h两个文件复制到工程目录下。

这里我们主要的移植工作就在transport里面。

打开transport.c文件,这个是MQTT连接,发送,接收的接口,源码是Linux跟Windows平台,用的标准的Socket接口函数,我们这里的移植工作量很小,因为LWIP也是支持标准的Socket接口函数,只不过里面有些函数接口是LWIP不支持的,主要就是transport_open这个连接函数有区别。把原来的transport_open函数注释掉,重新写一个。

如果STM32或者其它单片机是用WIFI模块或者GPRS模块,没有用到LWIP的怎么办。其实只要理解的MQTT的源码,就不难用GPRS或者WiFi模块去实现。
MQTT的源码里都是对协议包进行打包解包,数据传输都是在tranport.c里面,我们完全不用transport,可以自己写通信接口,然后把打包的数据包通过模块发出去,写接收接口,把模块接收到服务器数据调用MQTT解包接口解析就可以了。

MQTT的移植非常简单,将C/C++ MQTT Embedded clients的代码添加到工程中,然后我们只需要再次封装4个函数即可:

// 通过网络以TCP的方式发送数据
int transport_sendPacketBuffer(unsigned char* buf, int buflen); 

// TCP方式从服务器端读取数据,该函数目前属于阻塞函数;
int transport_getdata(unsigned char* buf, int count);

// 打开一个网络接口,其实就是和服务器建立一个TCP连接;
int transport_open(void);

// 关闭网络接口。
int transport_close(void);

// 因为LWIP也是支持标准的Socket接口函数,只不过里面有些函数接口是LWIP不支持的,主要就是transport_open这个连接函数有区别。
// 所以,如果 协议栈是 LWIP,那么只需要 把原来的transport_open函数注释掉,重写 即可
// ref : http://www.openedv.com/forum.php?mod=viewthread&tid=228932&extra=
posted @ 2020-02-07 14:20  schips  阅读(11634)  评论(0编辑  收藏  举报