STM32F103代碼遠程升級(五)基於MQTT協議WiFi遠程升級代碼的實現


在實現了基於YModem和XModem協議的單片機代碼更新之後就在琢磨如何真正實現遠程升級,直接通過網絡就可以更新代碼。
參考了網上很多關於WIFI通信升級的帖子,先梳理了一下WiFi通信升級的流程,然後開始着手實現這一功能。
首先是WiFi通信模塊的通信工具的選擇,我這裏選用的是ESP8266。
然後是通信協議的選擇,可以選擇自定義通信協議,不過因爲ESP8266模塊有MQTT的庫可以直接調用,因此這裏我選用的是MQTT協議作爲WiFi模塊和服務器之間的通信協議。


一、WiFi模塊的選用與介紹

我選用的是基於樂鑫esp8266的NodeMcu開發板,具有GPIO、PWM、I2C、1-Wire、ADC等功能,結合NodeMcu 固件爲原型開發提供最快速的途徑。
官方網站:
NodeMcu --像Arduino一樣簡單的開源可編程固件
NodeMcu特點
NodeMcu開發板操作起來很簡單,使用Lua腳本語言對其進行操作。如果沒有入這款開發板,直接用ESP8266接上必要的外圍電路,然後利用ESP8266的串口就可進行燒寫了。如此要使用NodeMcu的固件只需要將其固件燒寫到ESP8266上即可。下面將介紹NodeMcu固件庫的燒寫過程。


二、ESP8266的固件擦除與燒寫

1、ESP8266 Flash擦除工具的安裝與使用。

在寫ESP8266的控制代碼時,偶爾會遇到需要徹底擦除Flash裏的內容,然後重新燒寫的情況,這裏介紹一款比較好用的Flash擦除工具—esptool.py
(1)首先安裝python環境,版本不宜過高,最好在2.0~3.0之間;
(2)安裝完成後通過cmd輸入python,若出現相關版本信息,則安裝成功。
(3)使用:先找到安裝python的文件夾,看是否該文件夾下存在esptool.py,若存在則通過cmd運行該程序,例如在我的安裝情況下運行:
C:\Python27\Lib\site-packages>esptool.py --port COM4 erase_flash
這句話的意思就是擦除串口4連接的ESP8266的Flash。等待擦除完成之後我們就可以往裏面重新燒寫固件了。

注意:在運行命令前,一定要先將ESP8266置於Flash模式,即必須先將GPIO0引腳拉低。

2、ESP8266固件燒寫
(1)在線獲取固件文件

NodeMCU custom builds
NodeMcu提供在線生成固件,用戶可以根據自己的需要選擇模塊生成固件,NodeMcu會將集成好的固件文件發送至用戶郵箱,只需通過郵箱裏的鏈接即可下載我們所需要的固件。燒寫地址(0x00000)
模塊選擇

(2)獲取SDK init數據

在如上所述,通過esptool.py完全擦除芯片之後,需要先給ESP8266燒寫SDK之後再燒寫NodeMcu固件。
NodeMCU版本是針對Espressif SDK的特定版本編譯的。SDK在閃存中保留用於存儲校準和其他數據的空間。此數據在SDK版本之間更改,如果它無效或不存在,則固件可能無法正確啓動。
Espressif SDK下載
解壓該壓縮包之後在bin文件夾下就能找到我們所需要的SDK文件。

  • esp_init_data_dedault.bin 初始化其他射頻參數區,至少燒錄一次。燒寫地址(0x3FC000)
  • blank.bin 初始化RF_CAL參數區,燒寫地址(0x3FE000)
(3)ESP8266 Flash燒寫工具的使用

使用的是ESP8266Flasher.exe
下載安裝好,運行該文件,先選擇串口,然後配置文件,可以將SDK和固件一次性下載到ESP8266模塊中,如圖:
燒寫固件
然後點擊Flash按鈕,若出現芯片的MAC地址,則表示開始燒寫中,然後等待片刻,當左下角出現綠色的圓標打勾,則表示燒錄完畢。


三、NodeMcu基於Lua腳本開發

1、上傳代碼到ESP8266

選用的上傳代碼工具爲ESPlorer
需要Java運行環境,下載安裝之後,通過串口連接ESP8266,打開串口,然後重啓ESP8266,若是固件燒寫成功,則串口會打印相應的固件模塊,並且提示“lua: cannot open init.lua”。
ESPlorer工具的窗口布局如下圖所示:
ESPlorer窗口
左側窗口主要用於查看和編輯Lua腳本,然後通過左下角的按鈕可以將編輯好的Lua腳本保存(Save to ESP)、發送(Send to ESP)以及上傳(Upload to ESP)到ESP8266上。
最右側的縱向列表顯示了目前ESP8266上所存的lua腳本數量。
運行NodeMcu首先得先寫好init.lua腳本,然後上傳到板子上,再重啓運行。init.lua就相當於C語言中得main()函數,是程序的入口,必不可少的部分。

2、init.lua 連上WiFi

一切準備就緒之後我們就可以開始着手編寫我們的lua腳本了。
沒有接觸過lua,則可以先通過教程簡單學習一下lua編程。Lua教程
要運行lua腳本,可以選擇命令行運行的lua.exe,或者編譯環境友好的SciTE.exe以及LuaStudio。目前我用的最多的是後面兩款工具,其中LuaStudio在試用階段特別的好用。
利用Lua模塊,可以直接將WiFi連接配置的部分寫成一個模塊然後直接在init.lua中調用WiFi連接函數即可。具體代碼如下:

--wifi_cfg.lua
local module = {}
local led = require("led")
local function mWifiConfig()
	wifi.setmode(wifi.STATION)
	local station_cfg = {}
	station_cfg.ssid = "WiFi名字"
	station_cfg.pwd = "WiFi密碼"
	station_cfg.save = false
	wifi.sta.config(station_cfg)
	
	local cfg = {}
	cfg.ssid = "NodeMCU"
	cfg.pwd = "20180719"
	wifi.ap.config(cfg)
	wifi.sta.autoconnect(1)
end

function module.connectWIFI()   -- timer1
	print('Setting up WIFI date in 20180730...')
	mWifiConfig()
	led.LEDInit()
	--connect to a wireless network 
	tmr.alarm(1, 1000, tmr.ALARM_AUTO, function()
		if wifi.sta.getip() == nil then 
			print('Waiting for IP ...')
			led.RedLED()
		else
			print('IP is ' .. wifi.sta.getip())
			led.GreenLED()
			tmr.stop(1)
		end
	end)
end
return module


-- init.lua
local my_wifi = require("wifi_cfg")

-------main---------
--connect wifi 
my_wifi.connectWIFI()

然後將wifi_cfg.lua和init.lua兩個文件一起上傳到ESP8266上,上傳完成之後,重啓板子,然後ESP8266就連上了WiFi了。

3、更多ESP8266 關於lua腳本開發

在學習NodeMcu時,在網上找到了不少好的帖子,裏面關於NodeMcu入門lua開發講得很詳細了,這裏就不再贅述了,貼出鏈接供大家學習。

NodeMcu之旅(一):構建、刷入固件、上傳代碼
NodeMcu之旅(二):斷線自動重連,閃爍連接狀態
NodeMcu之旅(三):響應配置按鈕
NodeMcu之旅(四):實現Web配置頁面

看完網上的教程後發現,教程中所用的代碼大多數是NodeMcu提供的官方文檔中的樣例改寫來的,所以,多多研究官方的API,想要什麼功能自己實現就好了。
NodeMcu官方文檔

四、通信協議的選擇與使用

在學會了如何用lua腳本控制WiFi模塊之後,現在就需要着手選擇通信協議了,這裏我用的是MQTT。
因爲MQTT可以以極少的代碼和有限的帶寬,爲連接遠程設備提供實時可靠的消息服務。做爲一種低開銷、低帶寬佔用的即時通訊協議,使其在物聯網、小型設備、移動應用等方面有較廣泛的應用。
並且NodeMcu固件庫中包含了MQTT模塊,其中關於MQTT的客戶端與代理服務器的連接,訂閱和發佈消息的操作都很簡單。

1、MQTT協議原理

關於MQTT協議的介紹和原理,網上有許多帖子介紹的,這裏就貼出,我學習時看的帖子。
MQTT協議簡介及協議原理
MQTT協議解析

2、搭建MQTT代理服務器

在知道了協議通信原理之後,就可以在本地搭建一個MQTT的代理服務器了,方便日後的調試使用。
這裏我用的是Apache Apollo 服務器。在安裝之前需首先安裝JAVA jdk,配置環境變量,注意版本不要太高。
(1)Apollo服務器下載,下載地址 直接下載 apache-apollo-1.7.1-windows 的安裝包。下載後解壓到一個文件夾,注意路徑不要包含中文。安裝時參照安裝手冊 一步一步安裝即可。
(2)創建apollo的服務器應用實例,通過cmd進入apache-apollo-1.7.1的目錄裏面運行apollo.cmd create mybroker,如下:

F:\apache-apollo-1.7.1-windows-distro\apache-apollo-1.7.1\bin\apollo.cmd create mybroker

(3)創建成功之後進入mybroker文件運行服務器,如下:

F:\apache-apollo-1.7.1-windows-distro\apache-apollo-1.7.1\bin\mybroker\bin>apollo-broker run

(4)啓動服務後,在瀏覽器上面輸入:https://127.0.0.1:61681/或http://127.0.0.1:61680/使用默認的用戶名和密碼登錄 (admin;password),進入服務器頁面,如圖:
Apollo服務器

3、安裝MQTT客戶端

搭建好代理服務器之後,再安裝一個MQTT客戶端,即可測試MQTT通信協議了。因爲MQTT屬於訂閱/轉發類的通信協議,而MQTT的代理服務器只具備信息轉發功能,所以我們可以使用ESP8266作爲一個客戶端,PC即是客戶端又是代理服務器,通過ESP8266發佈消息,PC端訂閱消息,則可以實現兩者之間的通信。
這裏我安裝的PC客戶端是MQTT.fx 通過配置代理服務器的IP和端口號即可連接。
mqtt.fx

後面涉及到測試ESP8266通過MQTT接收16進制數,我又使用了另一個串口工具:通信貓調試軟件,一款很小但是功能齊全的串口調試工具,也可以連上MQTT代理服務器,並且能夠發送16進制數據
通信貓串口工具


五、基於MQTT協議WiFi遠程升級的具體實現

1、自定義MQTT文件發送客戶端

在測試了ESP8266通過MQTT與代理服務器連接良好,並且之間通信16進制數據也正常之後,此時面臨的問題就是,沒有合適的MQTT客戶端能夠直接發送文件。而且因爲ESP8266的接收緩存有線,所以一個更新文件我們也不能一次性發送,所以得分包發送。
如此,最好的就是自定義一個可以分包發送文件的客戶端,我主要負責單片機方面的開發,所以自定義的客戶端具體實現過程我也不太清楚。這裏就說下我使用的客戶端的滿足的要求。
(1)滿足TCP連接,能夠正常連接上MQTT代理服務器;
(2)能夠讀取出文件大小及文件名;
(3)能夠將文件分成指定大小的數據包,並且加上包頭,校驗和包尾後通過發佈消息發送給代理服務器。

2、客戶端與ESP8266的通信過程

完成了以上所有工作之後,最後的就是協調客戶端和ESP8266之間的通信了。
這裏我通過訂閱主題update接收來自客戶端的文件數據包,當然這裏我上傳給客戶端的文件是直接可執行的bin文件。
然後客戶端通過訂閱主題back來接收單片機的反饋信息。
主要通信過程爲:
(1)單片機做好更新程序的準備後,發佈主題爲back,消息爲–請求的數據包號給客戶端;
(2)客戶端收到單片機做好準備的標識和包號之後,通過識別包號,發佈主題爲update,消息爲—包數據給ESP8266;
(3)單片機收到一包數據處理完成之後,請求下一包;
(4)客戶端收到請求之後發送下一包數據,直至文件發送完成,發送結束標識。

這裏客戶端發送的第一包也可包含文件大小和文件名,然後單片機的處理就類似與YModem協議處理即可。
通過ESP8266遠程升級單片機程序,除了通信協議不一樣,其餘部分都可按照之前說的YModem和XModem協議處理即可。


參考鏈接

STM32遠程升級(基於串口本地升級與WiFi通信遠程升級)
基於WiFi的車載終端遠程軟件升級方法

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章