什么是OTA?
百度百科:空中下載技術(shù)(Over-the-Air Technology; OTA),是通過移動(dòng)通信的空中接口實(shí)現(xiàn)對(duì)移動(dòng)終端設(shè)備及SIM卡數(shù)據(jù)進(jìn)行遠(yuǎn)程管理的技術(shù)。經(jīng)過公網(wǎng)多年的應(yīng)用與發(fā)展,已十分成熟,網(wǎng)絡(luò)運(yùn)營(yíng)商通過OTA技術(shù)實(shí)現(xiàn)SIM卡遠(yuǎn)程管理,還能提供移動(dòng)化的新業(yè)務(wù)下載功能。
實(shí)際上,現(xiàn)在我們所說的OTA比百度百科的定義還要更廣泛,OTA的形式已經(jīng)不再局限于手機(jī)和SIM卡,只要涉及到遠(yuǎn)程下載升級(jí)程序的方式我們都可以稱之為OTA。例如通過4G,5G,WiFI,藍(lán)牙等無線通訊進(jìn)行下載升級(jí)的可以稱為OTA,通過U盤,RS485等串行接口進(jìn)行升級(jí)的也可以稱之為OTA。
OTA的作用?
OTA的意義在于它在一定程度上突破了距離的限制,在沒有下載器沒有電腦不用到現(xiàn)場(chǎng)不用拆開設(shè)備等情況下完成固件的燒錄,極大的方便了產(chǎn)品的升級(jí)和維護(hù),降低售后成本。
1 OTA原理簡(jiǎn)介
在使用OTA時(shí)我們一般會(huì)把內(nèi)存分成三個(gè)部分:BootLoader,APP,Download(OTA)。
分區(qū) | 作用 |
---|---|
BootLoader | 存放引導(dǎo)程序 |
APP | 存放用戶程序,也就是我們自己寫的代碼 |
Download(OTA) | 存放要升級(jí)的程序固件,也就是新版本的代碼 |
OTA原理簡(jiǎn)單介紹:
不管是在什么平臺(tái),不管用的是什么MCU,要使用OTA都離不開BootLoader,BootLoader是一個(gè)統(tǒng)稱,它其實(shí)只是一段引導(dǎo)程序,在MCU啟動(dòng)的時(shí)候會(huì)先運(yùn)行這段代碼,判斷是否需要升級(jí),如果不需要升級(jí)就跳轉(zhuǎn)到APP分區(qū)運(yùn)行用戶代碼,如果需要升級(jí)則跳轉(zhuǎn)到Download分區(qū)進(jìn)行固件解壓解碼等操作并且把該固件拷貝覆蓋到APP分區(qū),從而實(shí)現(xiàn)OTA。
怎么在Arduino下搭建OTA?
在明白了OTA升級(jí)原理之后我們?cè)賮砜纯碅rduino下搭建OTA需要哪些東西,首先,APP部分用戶程序我們肯定是有的,Download分區(qū)的固件其實(shí)也是我們的新版本的APP程序,這兩部分都沒什么問題,關(guān)鍵在于BootLoader,這個(gè)是必須要搞的,而且還要根據(jù)自己的實(shí)際情況來使用,不同的升級(jí)方式,不同的MCU,不同的內(nèi)存地址等等都會(huì)有區(qū)別。我這里介紹是是一種比較簡(jiǎn)單的方式,直接利用Arduino IDE現(xiàn)有的框架和開源源碼,通過TCP/IP協(xié)議來傳輸固件,從而實(shí)現(xiàn)OTA的功能,但是這種方式會(huì)有些局限性,具體有哪些局限性我放到最后再講。
2 Arduino IDE環(huán)境搭建
這個(gè)我具體就不說了,根據(jù)你自己用的MCU安裝好相應(yīng)的庫(kù)就行了,既然你都開始研究OTA了應(yīng)該不會(huì)連環(huán)境都沒搭好吧。如果有不懂的同學(xué)可以看下我之前發(fā)布的博客。
esp8266開發(fā)入門教程(基于Arduino)——環(huán)境安裝
使用VS code搭建Arduino IDE環(huán)境
3 編寫OTA測(cè)試代碼
我這里以ESP8266和ESP32為例編寫測(cè)試代碼,其他的MCU基本也是一致的,舉一反三即可。
硬件配置如下:
模塊 | 型號(hào) | 說明 |
---|---|---|
ESP8266 | ESP-12F | 這是安信可的一款模組,內(nèi)部主要是用樂鑫的ESP8266EX再加上一個(gè)片外FLASH組成,開發(fā)板型號(hào)是NodeMCU-12F(CH340版本) |
ESP32 | ESP-WROOM-32 | MCU是樂鑫的一款芯片,開發(fā)板型號(hào)ESP32 DEVKITV1 |
具體的硬件參數(shù)和電路原理圖這里就不發(fā)出來了,不同廠家做的開發(fā)板引腳可能會(huì)有點(diǎn)差別。
示例代碼如下:
提示1:ESP8266和ESP32的庫(kù)是不同的,但是基本用法是類似的,我這個(gè)示例代碼做了ESP8266和ESP32的兼容,可以通用。
提示2:WIFI賬號(hào)和密碼要根據(jù)自己修改,代碼中的定義僅供參考。
提示3:PC端和設(shè)備端要在同一個(gè)局域網(wǎng)下。不懂什么是局域網(wǎng)的同學(xué)直接把兩個(gè)設(shè)備都連到同一個(gè)WIFI即可。
#ifdef ESP8266
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#else
#include <WiFi.h>
#include <ESPmDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#endif
#define APP_VERSION "1.0.0" // app version
#ifndef STASSID
#define STASSID "test" // wifi user
#define STAPSK "123456789" // wifi password
#endif
const char* ssid = STASSID;
const char* password = STAPSK;
void setup() {
Serial.begin(115200);
Serial.printf("nAPP version: %srn", APP_VERSION);
Serial.println("Booting");
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.waitForConnectResult() != WL_CONNECTED)
{
Serial.println("Connection Failed! Rebooting...");
delay(5000);
ESP.restart();
}
ArduinoOTA.onStart([]() {
String type;
if (ArduinoOTA.getCommand() == U_FLASH) {
type = "sketch";
}
else { // U_FS
type = "filesystem";
}
// NOTE: if updating FS this would be the place to unmount FS using FS.end()
Serial.println("Start updating " + type);
});
ArduinoOTA.onEnd([]() {
Serial.println("nEnd");
});
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
Serial.printf("Progress: %u%%r", (progress / (total / 100)));
});
ArduinoOTA.onError([](ota_error_t error) {
Serial.printf("Error[%u]: ", error);
if (error == OTA_AUTH_ERROR) {
Serial.println("Auth Failed");
}
else if (error == OTA_BEGIN_ERROR) {
Serial.println("Begin Failed");
}
else if (error == OTA_CONNECT_ERROR) {
Serial.println("Connect Failed");
}
else if (error == OTA_RECEIVE_ERROR) {
Serial.println("Receive Failed");
}
else if (error == OTA_END_ERROR) {
Serial.println("End Failed");
}
});
ArduinoOTA.begin();
Serial.println("Ready");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
}
void loop() {
ArduinoOTA.handle();
}
4 OTA升級(jí)測(cè)試
因?yàn)镋SP8266和ESP32的測(cè)試結(jié)果是一樣的,這里就沒必要全部展示了,只貼一下ESP32的運(yùn)行情況給你們做個(gè)參考。
先把代碼燒錄進(jìn)去,通過串口打印的數(shù)據(jù),可以看到我們?cè)诖a里面寫的用戶版本號(hào)以及wifi連接成功后的IP地址。
#define APP_VERSION "1.0.0" // app version
Serial.printf("nAPP version: %srn", APP_VERSION);
然后打開Arduino IDE,在 工具 -> 端口 一欄可以看到多出了一個(gè)網(wǎng)絡(luò)端口,這個(gè)IP就是我們ESP32的網(wǎng)絡(luò)IP地址。
提示:如果沒有出現(xiàn)該端口,要么是設(shè)備沒有連上網(wǎng)絡(luò),要么是PC和設(shè)備不在同一個(gè)局域網(wǎng)。
選擇這個(gè)新的端口之后,我們就可以通過TCP/IP網(wǎng)絡(luò)協(xié)議燒錄程序。
我這里修改一下版本號(hào),然后重新燒錄一遍。在Arduino IDE這里可以看到燒錄的日志跟之前串口燒錄不一樣了,顯示的是IP地址和下載進(jìn)度條。(注:esp8266沒有顯示IP地址,只有進(jìn)度條,不過不影響使用)
同樣的通過串口也能看到升級(jí)時(shí)運(yùn)行的情況,Progress顯示的是OTA的升級(jí)進(jìn)度,后面的百分比在升級(jí)過程中是會(huì)動(dòng)的,從0%到100%。固件下載完成后設(shè)備會(huì)自動(dòng)重啟,不需要手動(dòng)進(jìn)入下載模式。
注:這個(gè)顯示的結(jié)果跟串口助手也有一點(diǎn)關(guān)系,我這里用的是Xshell,如果用其它普通串口助手的話,Progress是會(huì)打印很多出很多個(gè)的,不過并不影響正常使用,如果不需要顯示這個(gè)進(jìn)度,可以在代碼里面注釋掉。
結(jié)束語(yǔ)
好了,關(guān)于Arduino OTA的編程和使用方法就講到這里,其實(shí)這只是其中一種OTA的方式,而且有些局限性,因?yàn)镻C端和MCU之間是通過局域網(wǎng)進(jìn)行連接和傳輸固件的,在實(shí)際使用中,不可能所有設(shè)備和電腦都在同一網(wǎng)絡(luò)下,這樣的話就沒辦法做到遠(yuǎn)程OTA了。最好的辦法還是通過一個(gè)公網(wǎng)IP或者服務(wù)器來連接設(shè)備,設(shè)備可以通過http進(jìn)行固件的下載,這樣的話只要設(shè)備能連上網(wǎng)絡(luò),連上服務(wù)器,就可以實(shí)現(xiàn)真正意義上的遠(yuǎn)程OTA。
時(shí)間關(guān)系我這里就講這么多,后續(xù)有時(shí)間的話我會(huì)考慮再介紹一下其他方式的OTA。
想了解更多Arduino的內(nèi)容,可以關(guān)注一下博主,后續(xù)我還會(huì)繼續(xù)分享更多的經(jīng)驗(yàn)給大家。還有什么問題的話,歡迎在評(píng)論區(qū)留言。如果這篇文章能夠幫到你,就…你懂得。