周三的網(wǎng)文閱讀量好慘,到了周日還沒(méi)過(guò) 200,本想暫時(shí)不更此方面內(nèi)容了。
但是看到群里的小伙伴在修改 linkkitapp 例程遇到了麻煩,今天再分享一下代碼修改的全過(guò)程,本文我在虛擬機(jī)中重復(fù)修改驗(yàn)證了三遍,包你可以順利移植成功。
本文的實(shí)現(xiàn),在上一篇網(wǎng)文的基礎(chǔ)上實(shí)現(xiàn),開(kāi)發(fā)環(huán)境的搭建參見(jiàn)下文:
AliOS Things 物聯(lián)網(wǎng)操作系統(tǒng)學(xué)習(xí)第一步:Windows 下 AliOS Things 開(kāi)發(fā)環(huán)境搭建
本文我們實(shí)現(xiàn) linkkitapp 例程修改、ESP8266 固件的下載、一鍵配網(wǎng)和云智能 APP 綁定設(shè)備。
需要解決的問(wèn)題
ESP8266 有兩個(gè) UART:UART0 和 UART1。
UART0 有 TX、RX,可以作為系統(tǒng)的打印信息輸出接口和數(shù)據(jù)收發(fā)口。
UART1 的 RX 被 Flash 占用,只有發(fā)送引腳 TX(GPIO2,即 UART1_TXD),所以一般作為打印信息輸出接口(調(diào)試用)。
通常情況下,我們使用 UART0 和外設(shè)通訊,而使用 UART1 作為日志打印端口。
D1 mini ESP8266 模塊兩個(gè)串口的所在位置:
ESP8266 D1 mini 模塊
我們使用一個(gè) Micro USB 線與 D1 mini ESP8266 模塊相連,上文編譯后的固件燒錄之后,串口助手中會(huì)收到如下打印信息:
我們可以看到默認(rèn)的 linkkitapp 示例,Log 信息是通過(guò) UART0 發(fā)送出來(lái)的,而且里面有很多咱們不關(guān)心的信息,應(yīng)該將此部分信息進(jìn)行屏蔽。
所以我們需要做如下幾個(gè)工作:
- 將串口 0 和串口 1 的比特率設(shè)為一致;交換 UART0 和 UART1,讓 UART1 輸出 Log 日志;UART0 與 STM32 進(jìn)行通信;將 STM32 發(fā)上來(lái)的信息,通過(guò) UART0 接收并發(fā)送到云端;將云端下發(fā)的有用的信息通過(guò) UART0 轉(zhuǎn)發(fā)給 STM32。
解決問(wèn)題 1. 串口的初始化函數(shù)在platformmcuesp8266bspdriveruart.c
411 行 中,初始化 uart1,uart0 的波特率都為 115200。
void
uart_init_new(uart_dev_t?*uart)
{
????UART_WaitTxFifoEmpty(UART0);
????UART_WaitTxFifoEmpty(UART1);
????if?(uart?==?NULL)
????{
????????return;
????}
????if?(uart->port?==?1)
????{
????????//printf("port=?1n?");
????????//uart1?setting
????????UART_ConfigTypeDef?uart_config;
????????uart_config.baud_rate?=?uart->config.baud_rate;
????????uart_config.data_bits?=?UART_WordLength_8b;
????????uart_config.parity?=?USART_Parity_None;
????????uart_config.stop_bits?=?USART_StopBits_1;
????????uart_config.flow_ctrl?=?USART_HardwareFlowControl_None;
????????uart_config.UART_RxFlowThresh?=?120;
????????uart_config.UART_InverseMask?=?UART_None_Inverse;
????????//UART_ParamConfig(UART0,?&uart_config);
????????//uart2?setting?for?log
????????//uart_config.baud_rate?=?uart->config.baud_rate;
????????UART_ParamConfig(UART1,?&uart_config);
????????UART_SetPrintPort(UART1);
????????//UART_intr_handler_register(uart0_rx_isr,?NULL);
????????ETS_UART_INTR_ENABLE();
????}
????else
????{
????????//printf("port=?0?n?");
????????UART_ConfigTypeDef?uart_config;
????????uart_config.baud_rate?=?uart->config.baud_rate;
????????//?uart_config.baud_rate?=?BIT_RATE_921600;
????????uart_config.data_bits?=?UART_WordLength_8b;
????????uart_config.parity?=?USART_Parity_None;
????????uart_config.stop_bits?=?USART_StopBits_1;
????????uart_config.flow_ctrl?=?USART_HardwareFlowControl_None;
????????uart_config.UART_RxFlowThresh?=?120;
????????uart_config.UART_InverseMask?=?UART_None_Inverse;
????????UART_ParamConfig(UART0,?&uart_config);
????????UART_IntrConfTypeDef?uart_intr;
????????uart_intr.UART_IntrEnMask?=?UART_RXFIFO_TOUT_INT_ENA?|?UART_FRM_ERR_INT_ENA?|?UART_RXFIFO_FULL_INT_ENA?|?UART_TXFIFO_EMPTY_INT_ENA;
????????uart_intr.UART_RX_FifoFullIntrThresh?=?100;//10
????????uart_intr.UART_RX_TimeOutIntrThresh?=?10;//2
????????uart_intr.UART_TX_FifoEmptyIntrThresh?=?20;
????????UART_IntrConfig(UART0,?&uart_intr);
????????UART_SetPrintPort(UART0);
????????UART_intr_handler_register(uart0_rx_isr,?NULL);
????????ETS_UART_INTR_ENABLE();
????}
}
解決問(wèn)題 2. 交換 UART0 和 UART1:修改此文件:AliOS-Thingsplatformmcuesp8266haluart.c
17 行。
int32_t?hal_uart_send(uart_dev_t?*uart,?const?void?*data,?uint32_t?size,?uint32_t?timeout)
{
????int?i?=?0;
????char*?pdata?=?(char?*)data;
????for(i?=?0;?i?<?size;?i++)
????{
????????//uart0_write_char(pdata[i]);
????????if(uart->port?==?1)
????????????uart0_write_char(pdata[i]);
????????else
????????????uart1_write_char(pdata[i]);????????
????}
????return?0;
}
編譯一下,報(bào)錯(cuò):
去掉platformmcuesp8266bspdriveruart.c
60 行, LOCAL void uart1_write_char(char c)
函數(shù)前面的 LOCAL。
再次編譯正常。
修改串口初始化,文件所在路徑:platformmcuesp8266bspentry.c
60 行,修改后的代碼具體如下:
void?user_init(void)
{
????int?ret?=?0;
????extern?int32_t?hal_uart_init(uart_dev_t?*uart);
????extern?void?key_gpio_init(void);
????key_gpio_init();
????///hal_uart_init(&uart_0);
????uart_config_t?uartConfig0;
????uartConfig0.baud_rate?=?115200;
????uartConfig0.parity?=?0;
????uartConfig0.stop_bits?=?1;
????uart_dev_t?uart0;
????uart0.port?=?0;
????uart0.config?=?uartConfig0;
????hal_uart_init(&uart0);
????uart_config_t?uartConfig1;
????uartConfig1.baud_rate?=?115200;
????uart_dev_t?uart1;
????uart1.port?=?1;
????uart1.config?=?uartConfig1;
????hal_uart_init(&uart1);
????printf("[%d]?--?Message?from?printf?--?user_init?--?rn",(unsigned)aos_now_ms());
????hal_wifi_register_module(&aos_wifi_esp8266);
????ret?=?hal_wifi_init();
????if?(ret){
????????printf("waring:?wifi?init?fail?ret?is?%d?rn",?ret);
????}
#if?defined(SUPPORT_SINGAPORE_DOMAIN)
????aos_task_new("main",?app_entry,?0,?7.5*1024);
#elif?defined(ESP8266_CHIPSET)
????aos_task_new("main",?app_entry,?0,?2*1024);
#else
????aos_task_new("main",?app_entry,?0,?6*1024);
#endif
}
解決問(wèn)題 3.
- 下發(fā)有用信息:
修改文件appexamplelinkkitapplinkkit_example_solo.c
109 行。
/**?recv?event?post?response?message?from?cloud?**/
static?int?user_property_set_event_handler(const?int?devid,?const?char?*request,?const?int?request_len)
{
????int?res?=?0;
????EXAMPLE_TRACE("Property?Set?Received,?Request:?%s",?request);
????hal_uart0_send(request,strlen(request));????????//xiaoha?+++
????res?=?IOT_Linkkit_Report(EXAMPLE_MASTER_DEVID,?ITM_MSG_POST_PROPERTY,
?????????????????????????????(unsigned?char?*)request,?request_len);
????EXAMPLE_TRACE("Post?Property?Message?ID:?%d",?res);
????return?0;
}
- 上發(fā)有用信息:
修改文件 appexamplelinkkitapplinkkit_example_solo.c
?27 行處添加頭文件:
#include?"aos/hal/uart.h"
在includeaoshaluart.h
文件 102 行后增加兩個(gè)函數(shù)聲明:
int32_t?hal_uart0_printf(const?void?*data);
int32_t?hal_uart0_send(const?void?*data,?uint32_t?size);
在AliOS-Thingsplatformmcuesp8266haluart.c
文件 32 行后增加兩個(gè)函數(shù)實(shí)現(xiàn):
int32_t?hal_uart0_printf(const?void?*data)
{
????int?i?=?0;
????char*?pdata?=?(char?*)data;
????while(*?pdata)
????????uart0_write_char(*?pdata++);
????return?0;
}
int32_t?hal_uart0_send(const?void?*data,?uint32_t?size)
{
????int?i?=?0;
????char*?pdata?=?(char?*)data;
????for(i?=?0;?i?<?size;?i++)
????{
????????uart0_write_char(pdata[i]);
????}
????uart0_write_char('r');
????uart0_write_char('n');
????return?0;
}
修改文件appexamplelinkkitapplinkkit_example_solo.c
?378 行, 修改上傳屬性的數(shù)據(jù):
/*?Post?Proprety?Example?*/
uint8_t?receive_bytes[255];
memset(receive_bytes,0,255);????// 或者?memset(receive_bytes,0,128*sizeof(char));
int32_t?ret?=?-1;
uint32_t?i,?recv_size?=?0;
uart_dev_t?uart0;
uart0.port?=?0;????
ret?=?hal_uart_recv_II(&uart0,?&receive_bytes,?255,?&recv_size,?20);
if?((ret?==?0))
{
????hal_uart0_printf(receive_bytes);
????char?property_payload[30]?=?{0};
????HAL_Snprintf(property_payload,sizeof(property_payload),"%s",receive_bytes);
????res?=?IOT_Linkkit_Report(EXAMPLE_MASTER_DEVID,ITM_MSG_POST_PROPERTY,
????????????????????????????(unsigned?char?*)property_payload,strlen(property_payload));
????EXAMPLE_TRACE("Post?Property?Message?ID:?%d",res);
}
修改智能設(shè)備的三元組信息:
//?for?demo?only
#define?PRODUCT_KEY??????"a1xHkDXXXXX"
#define?PRODUCT_SECRET???"0miHcO6f4E8XXXXX"
#define?DEVICE_NAME??????"ZNFS0001"
#define?DEVICE_SECRET????"xnOe5VcOkvXFTBAZaik4hz7y67XXXXXX"
登錄阿里云飛燕平臺(tái):https://living.aliyun.com/#/
創(chuàng)建阿里云物聯(lián)網(wǎng)智能設(shè)備的方法請(qǐng)參見(jiàn)下文:
七步快速開(kāi)啟產(chǎn)品智能化
在產(chǎn)品頁(yè)面獲得ProductSecret
:
在設(shè)備頁(yè)面獲得設(shè)備的三元組信息:
?
燒寫(xiě)固件
?
使用云智能 APP 配網(wǎng)并添加設(shè)備
固件燒寫(xiě)完成之后,復(fù)位 ESP8266 模塊,可以看到 ESP8266 的串口 1 打印如下信息:
此時(shí)雖然在掃描 SSID,但是掃描二維碼并不能正常添加設(shè)備,需要先進(jìn)入配網(wǎng)模式,再掃描二維碼添加設(shè)備。
進(jìn)入配網(wǎng)模式的方法:
使用一個(gè)跳線,先把 D5(GPIO14)接 GND,再接 3.3V。
出現(xiàn)如下 Log 即進(jìn)入配網(wǎng)模式:
?
然后使用云智能 APP 掃描上面的二維碼添加設(shè)備并配網(wǎng)。
配網(wǎng)成功,云智能 APP 出現(xiàn)如下界面:
配網(wǎng)成功,串口助手可以收到來(lái)自服務(wù)器端的如下 Log 日志:
此時(shí)查看阿里云飛燕平臺(tái)的后臺(tái),可以看到設(shè)備已經(jīng)成功上線。
?
模擬上傳屬性
經(jīng)過(guò)上面的改造之后,我們只需要向 UART0 發(fā)送 JSON 格式的數(shù)據(jù),即可修改服務(wù)器端的數(shù)值,比如發(fā)送:
{"CurrentTemperature":26}
發(fā)送完畢,服務(wù)器端的當(dāng)前溫度值將會(huì)修改為 26℃,在運(yùn)行狀態(tài)中可以實(shí)時(shí)看出來(lái)當(dāng)前溫度值是實(shí)時(shí)變化的。
?
模擬設(shè)置屬性
手機(jī)端 APP 點(diǎn)擊某個(gè)按鈕之后,將會(huì)將數(shù)據(jù)包發(fā)送至 ESP8266,ESP8266 將有用信息通過(guò) UART0 的 TX 引腳發(fā)送給 STM32,STM32 將收到服務(wù)器端指令,對(duì)此指令進(jìn)行解析,進(jìn)而做相應(yīng)的動(dòng)作,具體邏輯類似下圖所示。
調(diào)試真實(shí)設(shè)備中,對(duì)電源開(kāi)關(guān)設(shè)置為 1,即{"PowerSwitch":1},在串口助手中我們收到指令{"PowerSwitch":1};
我們對(duì)電源開(kāi)關(guān)設(shè)置為 0,即{"PowerSwitch":0},可以看到串口助手中,收到對(duì)應(yīng)的指令{"PowerSwitch":0}。
STM32 中我們使用 cJSON 對(duì)上面字符串進(jìn)行解析即可,然后做相應(yīng)的動(dòng)作,即完成了云端對(duì)設(shè)備的遠(yuǎn)程控制。
細(xì)心的人可能發(fā)現(xiàn)了,為什么我們用 CurrentTemperature 或者 PowerSwitch 來(lái)設(shè)置屬性呢?其實(shí)他們就是我們創(chuàng)建產(chǎn)品的時(shí)候,進(jìn)行功能定義的時(shí)候,設(shè)置的標(biāo)識(shí)符。
至此,使用 ESP8266 模塊,已經(jīng)完成了燒寫(xiě) AliOS Things 3.0 固件,成功配網(wǎng)、添加設(shè)備并連上了阿里云服務(wù)器。
讓 ESP8266 的串口 0 與 STM32 的串口進(jìn)行數(shù)據(jù)通信,發(fā)送模擬上傳屬性中的數(shù)據(jù)完成屬性的上報(bào),串口接收、解析服務(wù)器返回的數(shù)據(jù),根據(jù)解析的結(jié)果進(jìn)而完成對(duì)設(shè)備的控制,從而實(shí)現(xiàn)了 STM32 和 ESP8266 的雙向通信。
各位小伙伴可以在我的基礎(chǔ)上隨意擴(kuò)展,這樣你的設(shè)備就實(shí)現(xiàn)了接入阿里云物聯(lián)網(wǎng)平臺(tái)。