1、背景
前段時間看到樂鑫推出了一種很有意思的Wi-Fi通訊協(xié)議,它允許設(shè)備在無連接的時候進行直接通訊。
樂鑫對它的概述如下:
“
ESP-NOW是一種由樂鑫公司定義的無連接Wi-Fi通信協(xié)議。在ESP-NOW中,應(yīng)用程序數(shù)據(jù)被封裝在各個供應(yīng)商的動作幀中,然后在無連接的情況下,從一個Wi-Fi設(shè)備傳輸?shù)搅硪粋€ Wi-Fi 設(shè)備。
感覺很有意思,于是找了樂鑫IDF提供的demo進行驗證。這里用到的demo在IDF的路徑為:esp-idf/examples/wifi/espnow。
找來幾個ESP32-C3模組,燒錄完之后,確實在沒有連接路由器的情況下可以進行直接通訊。
2、例程改造
通過運行demo:esp-idf/examples/wifi/espnow發(fā)現(xiàn)這個Demo有點不足的地方是沒有連接路由器,那么我在想,有沒有可能在既連接路由器的情況下,又可以直接與其他沒有連接路由器的設(shè)備進行通訊呢?
那么我的想法如下圖
在上面這里,A設(shè)備既連接路由器也直接與B/C/D三個設(shè)備基于ESP_NOW進行直接通訊。
這里我讓A設(shè)備工作在STA+AP模式下,其中STA用于連接路由,AP用于ESP_NOW進行通訊?;诖嗽O(shè)想,我還專門問了deepSeek,它也給出了方案可行的確定回答;
于是開開心心的寫了代碼,其中Wi-Fi和ESP_NOW的初始化程序如下,然后分別替換esp-idf/examples/wifi/espnow這里的初始化;
- Wi-Fi的初始化如下
#defineESP_AP_CHANNEL 6// 固定使用信道6
staticvoidexample_wifi_init(void)
{
wifi_config_twifi_config = {
.sta = {
.ssid ="xLogMonitor",
.password ="1234567890",
},
};
// 配置AP模式參數(shù) - 關(guān)鍵部分!
wifi_config_tap_config = {
.ap = {
.ssid ="", // 空SSID,不廣播
.ssid_len =0,
.channel = ESP_AP_CHANNEL,// 這是我們真正關(guān)心的參數(shù)
.authmode = WIFI_AUTH_OPEN,
.max_connection =0, // 不允許任何站連接
},
};
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_create_default_wifi_sta();
esp_netif_t*ap_netif = esp_netif_create_default_wifi_ap();
wifi_init_config_tcfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) );
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
ESP_EVENT_ANY_ID,
&event_handler,
NULL,
&instance_any_id));
ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
IP_EVENT_STA_GOT_IP,
&event_handler,
NULL,
&instance_got_ip));
ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_APSTA) );
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &ap_config));
ESP_ERROR_CHECK( esp_wifi_start());
// ESP_ERROR_CHECK( esp_wifi_set_channel(CONFIG_ESPNOW_CHANNEL, WIFI_SECOND_CHAN_NONE));
#ifCONFIG_ESPNOW_ENABLE_LONG_RANGE
ESP_ERROR_CHECK( esp_wifi_set_protocol(ESPNOW_WIFI_IF, WIFI_PROTOCOL_11B|WIFI_PROTOCOL_11G|WIFI_PROTOCOL_11N|WIFI_PROTOCOL_LR) );
#endif
}
- ESP_NOW的初始化如下
staticesp_err_texample_espnow_init(void)
{
example_espnow_send_param_t*send_param;
s_example_espnow_queue = xQueueCreate(ESPNOW_QUEUE_SIZE,sizeof(example_espnow_event_t));
if(s_example_espnow_queue ==NULL) {
ESP_LOGE(TAG,"Create mutex fail");
returnESP_FAIL;
}
/* Initialize ESPNOW and register sending and receiving callback function. */
ESP_ERROR_CHECK( esp_now_init() );
ESP_ERROR_CHECK( esp_now_register_send_cb(example_espnow_send_cb) );
ESP_ERROR_CHECK( esp_now_register_recv_cb(example_espnow_recv_cb) );
/* Set primary master key. */
ESP_ERROR_CHECK( esp_now_set_pmk((uint8_t*)CONFIG_ESPNOW_PMK) );
/* Add broadcast peer information to peer list. */
esp_now_peer_info_t*peer =malloc(sizeof(esp_now_peer_info_t));
if(peer ==NULL) {
ESP_LOGE(TAG,"Malloc peer information fail");
vSemaphoreDelete(s_example_espnow_queue);
esp_now_deinit();
returnESP_FAIL;
}
memset(peer,0,sizeof(esp_now_peer_info_t));
peer->channel = ESP_AP_CHANNEL;
peer->ifidx = ESP_IF_WIFI_AP;
peer->encrypt =false;
memcpy(peer->peer_addr, s_example_broadcast_mac, ESP_NOW_ETH_ALEN);
ESP_ERROR_CHECK( esp_now_add_peer(peer) );
free(peer);
/* Initialize sending parameters. */
send_param =malloc(sizeof(example_espnow_send_param_t));
if(send_param ==NULL) {
ESP_LOGE(TAG,"Malloc send parameter fail");
vSemaphoreDelete(s_example_espnow_queue);
esp_now_deinit();
returnESP_FAIL;
}
memset(send_param,0,sizeof(example_espnow_send_param_t));
send_param->unicast =false;
send_param->broadcast =true;
send_param->state =0;
send_param->magic = esp_random();
send_param->count = CONFIG_ESPNOW_SEND_COUNT;
send_param->delay = CONFIG_ESPNOW_SEND_DELAY;
send_param->len = CONFIG_ESPNOW_SEND_LEN;
send_param->buffer =malloc(CONFIG_ESPNOW_SEND_LEN);
if(send_param->buffer ==NULL) {
ESP_LOGE(TAG,"Malloc send buffer fail");
free(send_param);
vSemaphoreDelete(s_example_espnow_queue);
esp_now_deinit();
returnESP_FAIL;
}
memcpy(send_param->dest_mac, s_example_broadcast_mac, ESP_NOW_ETH_ALEN);
example_espnow_data_prepare(send_param);
xTaskCreate(example_espnow_task,"example_espnow_task",2048, send_param,4,NULL);
returnESP_OK;
}
程序跑起來了,確實也是符合我的預(yù)期,A設(shè)備連接上了路由器,然后同時也和BCD進行了通訊,感覺一切都很完美,如果不出意外的話就好出意外了;
3、問題出現(xiàn)了
在當我為改造例程的成功而高興的時候,問題出現(xiàn)了。我換了一個路由器,發(fā)現(xiàn)通訊失敗了。esp_send出現(xiàn)了如下錯誤:
E (12554) ESPNOW: Peer channel is not equal to the home channel, send fail!
這下懵逼了,為啥換個路由器就不行,難道這協(xié)議還和路由器有關(guān)系,樂鑫的官方文檔也沒提到呀~
樂鑫文檔:https://docs.espressif.com/projects/esp-idf/zh_CN/v4.4.6/esp32c3/api-reference/network/esp_now.html?highlight=esp_now_init#
4、問題分析
從錯誤的日志上來看這個錯誤指的是Peer channel和home channel,不一致導(dǎo)致的。
這里Peer指的應(yīng)該是要發(fā)送的對端通道,home應(yīng)該指的是本身;
但是這兩個地方我在配置的時候都是指定了#defineESP_AP_CHANNEL 6 // 固定使用信道6這個通道為啥還會出現(xiàn)這個錯誤呢?
后續(xù)我繼續(xù)運行多幾次,發(fā)現(xiàn)只有在A設(shè)備連接上網(wǎng)絡(luò)之后才會出現(xiàn)這個錯誤。
難道是連接路由器之后A設(shè)備的信道發(fā)生了變化?經(jīng)過查閱資料得知,確實是這樣的,STA設(shè)備在連接路由器之后,設(shè)備的Wi-Fi信道是由路由器決定的,所以當路由器分配的信道和#defineESP_AP_CHANNEL 6不一致的時候就會出現(xiàn)問題了。
于是我在esp_now_send之前打印了設(shè)備當前的信道信息,獲取到信息如下
I (12554) sta_ap_espnow: STA連接信息: SSID=xLogMonitor, 信道=8, RSSI=-61
I (12554) sta_ap_espnow: 當前工作信道: 8
E (12554) ESPNOW: Peer channel is not equal to the home channel, send fail!
E (12564) sta_ap_espnow: ESP-NOW數(shù)據(jù)發(fā)送失敗: 0x3066
理論和實驗結(jié)果一致,當設(shè)備連接之后信道變?yōu)榱?。
于是想要解決當前這個問題也很簡單了,只需要把所有的ESP_NOW的設(shè)備改成和所要連接的路由器同個信道8即可。
結(jié)果證實了,當信道改為8之后所有設(shè)備通訊就正常了;
5、總結(jié)
雖然我們知道了問題,也解決了問題。但是樂鑫文檔在描述這一塊時也沒著重,導(dǎo)致當時看文檔也沒特別留意。
ESP32-C3的STA+AP模式,在STA連接完路由器之后,AP模式指定的信道并不能作為ESP_NOW通訊;
如果設(shè)備需要連接路由器,需要提前知道連接的路由器信道再給其他設(shè)備指定一個統(tǒng)一的信道才能進行ESP_NOW進行通訊。這個在后續(xù)的產(chǎn)品落地確實是一個問題,需要看看如何優(yōu)化
-
通訊
+關(guān)注
關(guān)注
9文章
935瀏覽量
36174 -
ESP
+關(guān)注
關(guān)注
0文章
193瀏覽量
35793 -
ESP32
+關(guān)注
關(guān)注
21文章
1042瀏覽量
20278
發(fā)布評論請先 登錄
請問使用ESP-NOW通訊的時候如何獲取對應(yīng)的RSSI?
ESP32S2喚醒后無法收到另外一個機子發(fā)送的ESP-NOW的數(shù)據(jù),為什么?
使用ESP32-C3的藍牙進行傳感器數(shù)據(jù)上傳,ESP-NOW協(xié)議的功耗能滿足需求嗎?
ESP-NOW喚醒無法接收數(shù)據(jù)是怎么回事?
ESP32-S2的ESP-NOW的傳輸距離如何提高?
如何使用ESP-Now協(xié)議連接ESP32和ESP8266來控制LED?
ESP-NOW技術(shù)的介紹和使用方式及示例代碼資料免費下載

Arduino-IDE配置ESP32-CAM開發(fā)環(huán)境踩過的那些坑

ESP-32開發(fā)踩坑歷程(三)ESP-IDF 定時器使用

ESP8266相互通訊(ESP-NOW)

ESP32操縱桿手控制器ESP NOW開源

ESP-NOW無線通信之ESP32學習之旅-Arduino版

樂鑫低功耗方案 | ESP-NOW

評論