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=


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM