本文介紹如何在ESP32開發板上移植C-SDK4.0,并用MQTT Demo連上阿里云物聯網平臺。
開發環境說明
為了完成移植實踐,您需要:
一塊搭載ESP32的開發板。
USB連接線。
運行Linux或者macOS的計算機。
demo使用的開發板為ESP32 Core Board V2/ESP32 DevKitC,它搭載了ESP-WROOM-32官方模組,板載USB轉串口模塊(CP2102)和電源模塊。
我們使用的開發環境為macOS,使用其他系統的用戶也可以參考ESP32的官方入門教程完成開發環境搭建。
搭建開發環境
本節僅供參考使用,您在搭建開發環境中碰到問題請聯系開發板的供應商進行解決,然后再進行SDK的移植。建議您先閱讀樂鑫官方入門教程以加快開發環境搭建。
下面對macOS環境搭建的相關步驟做簡要說明:
安裝必要的軟件。
macOS用戶查看Standard Setup of Toolchain for Mac OS,建議您使用包管理工具Homebrew,需要安裝的包有
pip
、ninja
、cmake
等。Linux用戶查看Standard Setup of Toolchain for Linux。
復制
esp-idf
官方倉庫。本次演示使用
esp-idf
倉庫的release/v4.2分支,如果使用其他版本可能出現版本不兼容。cd ~ mkdir esp && cd esp git clone --recursive -b release/v4.2 https://github.com/espressif/esp-idf.git
安裝工具鏈和編譯工具。
cd esp-idf ./install.sh
配置環境變量。
運行以下腳本:
. $HOME/esp/esp-idf/export.sh
您也可參考以下腳本在
$HOME/.bash_profile
中添加配置以快速完成環境變量配置:set_esp32 () { export IDF_PATH=$HOME/esp/esp-idf . $HOME/esp/esp-idf/export.sh }
拷貝WiFi state例程到獨立目錄。
cd ~/esp cp -r $IDF_PATH/examples/wifi/getting_started/station .
連接開發板。
查看設備端口名,演示中的USB端口名為
/dev/cu.SLAB_USBtoUART
。
配置工程。
使用
idf.py menuconfig
配置工程,演示中使用了默認配置。編譯、燒寫、串口監視。
進入station項目路徑,使用
idf.py build
編譯工程。編譯完成后使用
idf.py -p PORT flash
命令燒寫固件(請用實際的USB端口名替換PORT)。燒寫成功后可運行
idf.py -p PORT monitor
打開串口打印信息監視器。您也可使用
idf.py -p PORT flash monitor
連續執行這兩條命令。
至此,您已經完成了ESP32開發環境的搭建,并完成了
wifi station
例程的編譯燒寫,下面我們將介紹如何移植C-SDK4.0,并成功連接阿里云物聯網平臺。
移植C-SDK4.0
移植C-SDK的過程主要包括了SDK代碼的導入,SDK port層文件配置和編譯系統的配置。
SDK的portfiles
目錄已經包含了ESP32的portfile
,因此您只需要導入SDK源碼,配置編譯系統即可完成移植工作。
基本概念
建議提前閱讀idf
的編譯系統介紹以理解移植過程,您需要了解idf
的一些基本概念:
project:項目目錄,僅包含了所有用于構建
app
的源文件和配置文件。components: 功能獨立的模塊化代碼, 將會編譯成
.a
靜態庫并鏈接到app
,這些模塊化的組件存放在idf
的components
目錄下,您可以添加自定義component
。
idf的編譯系統默認使用cmake
和ninja
組合,我們只需移入SDK代碼,編寫SDK對應的CMakeList.txt
即可將SDK加入編譯。
移植思路
方法一:在
project
目錄中引入C-SDK,將SDK源碼與您的其他app
源碼共同編譯。方法二:將C-SDK作為idf自定義組件引入到
idf
的components
目錄中。
我們推薦用第二種方法,將C-SDK作為獨立組件有助于在不同項目中復用,并解除與您其他app
代碼的耦合。
操作步驟
添加C-SDK自定義組件。
下載C-SDK4.0,將SDK復制到
$IDF_PATH/components
目錄下,在C-SDK目錄下添加構建文件CMakeLists.txt
,內容如下:set(include_dirs core core/sysdep core/utils) file(GLOB c_sdk_srcs "core/*.c" "core/utils/*.c" "core/sysdep/*.c" "portfiles/aiot_port/*.c" "external/*.c") idf_component_register(SRCS ${c_sdk_srcs} INCLUDE_DIRS "${include_dirs}" REQUIRES mbedtls)
說明由于C-SDK依賴mbedtls庫,因此需要使用
REQUIRES mbedtls
引入組件依賴。由于C-SDK沒有配置項,無需配置組件Kconfig。
若您需要使用SDK高級組件(如物模型,OTA),則在此
CMakeLists.txt
中添加組件對應的源文件和頭文件路徑。
移植demo程序。
您需要下載附件posix_port.c(適配了esp32),用它將
$IDF_PATH/components/C-SDK/portfiles/aiot_port
目錄下的posix_port.c
替換掉。LinkSDK與
idf
中都有mbedtls
庫,避免引用庫沖突,修改文件$IDF_PATH/components/C-SDK/core/sysdep/core_adapter.c
,關閉CORE_ADAPTER_MBEDTLS_ENABLED宏定義。由于idf兼容posix標準,您可下載附件station_example_main.c獲取并替換原有例程下文件
station/main/station_example_main.c
。說明wifi_init_sta()
函數會一直等待WiFi連接成功直到重連次數達到宏EXAMPLE_ESP_MAXIMUM_RETRY
定義的數值。WiFi連接成功后,我們便可以調用C-SDK的API進行MQTT建連,建連成功后即可與物聯網平臺進行數據收發了。
linkkit_main()
函數包含原C-SDK的mqtt demo。
編譯、燒寫。
在項目目錄下運行
idf.py menuconfig
,進入Example Configuration
菜單。修改
WiFi SSID
、WiFi Password
和Maximum retry
(最大重連次數)3個參數,保存并退出配置。運行
idf.py build
進行編譯。編譯成功后,運行
idf.py -p /dev/cu.SLAB_USBtoUART flash monitor
完成燒寫并打開串口監視器。
說明如果設備使用PSK密鑰交換則需要確保mbedTLS已經打開PSK密鑰交換方法,同時配置PSK最大長度為64,可參考以下步驟配置:
進入Component config菜單的mbedTLS子菜單,進入
TLS Key Exchange Methods
配置項。打開
Enable pre-shared-key ciphersuites
開關。同時在mbedtls組件的CMakeLists.txt中添加
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DMBEDTLS_PSK_MAX_LEN=64")
。
運行日志信息。
...... I (829) phy: phy_version: 4180, cb3948e, Sep 12 2019, 16:39:13, 0, 0 I (829) wifi: mode : sta (30:ae:a4:04:81:84) I (829) wifi station: wifi_init_sta finished. I (949) wifi: new:<11,0>, old:<1,0>, ap:<255,255>, sta:<11,0>, prof:1 I (949) wifi: state: init -> auth (b0) I (969) wifi: state: auth -> assoc (0) I (969) wifi: state: assoc -> run (10) I (1129) wifi: connected with C_SDK_Test, aid = 1, channel 11, BW20, bssid = ec:26:ca:4b:68:cc I (1129) wifi: security type: 3, phy: bgn, rssi: -37 I (1139) wifi: pm start, type: 1 I (1219) wifi: AP's beacon interval = 102400 us, DTIM period = 1 I (2129) esp_netif_handlers: sta ip: 192.168.0.100, mask: 255.255.255.0, gw: 192.168.0.1 I (2129) wifi station: got ip:192.168.0.100 I (2129) wifi station: connected to ap SSID:C_SDK_Test password:1234abcd I (2139) wifi station: Start linkkit mqtt [1.583][LK-0313] MQTT user calls aiot_mqtt_connect api, connect [1.587][LK-0317] mqtt_basic_demo&a13FNXXXXXX [1.590][LK-0318] 4780A5F17990D8DC4CCAD392683ED80160C4C2A1FFA649425CD0E2666A8593EB [1.598][LK-0319] a13FN5TplKq.mqtt_basic_demo|timestamp=2524608000000,_ss=1,_v=sdk-c-4.0.0,securemode=2,signmethod=hmacsha256,ext=1,| establish mbedtls connection with server(host='a13FN5TplKq.iot-as-mqtt.cn-shanghai.aliyuncs.com', port=[443]) success to establish mbedtls connection, fd = 54(cost 29739 bytes in total, max used 44007 bytes) [3.493][LK-0313] MQTT connect success in 1910 ms AIOT_MQTTEVT_CONNECT [3.494][LK-0309] sub: /sys/a13FN5TplKq/mqtt_basic_demo/thing/event/+/post_reply [3.499][LK-0309] pub: /sys/a13FN5TplKq/mqtt_basic_demo/thing/event/property/post [LK-030A] > 7B 22 69 64 22 3A 22 31 22 2C 22 76 65 72 73 69 | {"id":"1","versi [LK-030A] > 6F 6E 22 3A 22 31 2E 30 22 2C 22 70 61 72 61 6D | on":"1.0","param [LK-030A] > 73 22 3A 7B 22 4C 69 67 68 74 53 77 69 74 63 68 | s":{"LightSwitch [LK-030A] > 22 3A 30 7D 7D | ":0}} suback, res: -0x0000, packet id: 1, max qos: 1 [3.573][LK-0309] pub: /sys/a13FN5TplKq/mqtt_basic_demo/thing/event/property/post_reply [LK-030A] < 7B 22 63 6F 64 65 22 3A 32 30 30 2C 22 64 61 74 | {"code":200,"dat [LK-030A] < 61 22 3A 7B 7D 2C 22 69 64 22 3A 22 31 22 2C 22 | a":{},"id":"1"," [LK-030A] < 6D 65 73 73 61 67 65 22 3A 22 73 75 63 63 65 73 | message":"succes [LK-030A] < 73 22 2C 22 6D 65 74 68 6F 64 22 3A 22 74 68 69 | s","method":"thi [LK-030A] < 6E 67 2E 65 76 65 6E 74 2E 70 72 6F 70 65 72 74 | ng.event.propert [LK-030A] < 79 2E 70 6F 73 74 22 2C 22 76 65 72 73 69 6F 6E | y.post","version [LK-030A] < 22 3A 22 31 2E 30 22 7D | ":"1.0"} pub, qos: 0, topic: /sys/a13FNXXXXXX/mqtt_basic_demo/thing/event/property/post_reply pub, payload: {"code":200,"data":{},"id":"1","message":"success","method":"thing.event.property.post","version":"1.0"} heartbeat response heartbeat response heartbeat response ......
重要如果您看見“aiot_mqtt_connect failed: -0x0F0F”的報錯,說明網絡不通暢。建議您檢查wifi網絡狀態,確認板子在接收wifi信號的范圍內,必要時可以重試燒寫和連接。
備注:-0x0F0F的語義是STATE_PORT_NETWORK_CONNECT_TIMEOUT,連接超時。