本帖最后由 忙碌的死龙 于 2024-4-25 17:31 编辑
前言 ESPNOW协议是乐鑫信息科技(上海)有限公司(Espressif Systems)开发的一种基于IEEE 802.11标准的无线通信协议。乐鑫是一家专注于无线通信技术的企业,旗下产品如ESP8266和ESP32芯片广泛用于物联网(IoT)项目中,因其高性能和低成本获得了极大的流行。 ESPNOW协议允许设备在不需要建立WiFi连接的情况下进行直接通信,即可以在设备之间实现点对点或点对多点的数据传输。这种通信模式相对于传统的WiFi网络来说,在某些应用场景下可以提供更高效的数据交换方式,因为它省去了WiFi连接建立与断开的时间,从而减少了通信延迟。同时,ESPNOW协议还能够在低功耗模式下工作,这对于电池供电的物联网设备是非常重要的特性。 ESPNOW协议的主要特点包括: 高效的通信协议:由于不需要传统的WiFi网络连接过程(如握手协议),ESPNOW可以更快地完成设备间的数据交换。 灵活的设备对接模式:支持一对一、一对多和多对多的通信模式,这使得ESPNOW协议在物联网应用中非常灵活。 低功耗:特别适合于电池供电的设备,有助于延长设备的使用寿命。 使用简单:乐鑫为ESPNOW提供了一套相对简单的API和开发工具,使得开发人员可以相对容易地实现和部署基于此协议的应用。
1、ESPNOW的官方案例代码
我们直接使用官方的案例代码进行测试,这个案例需要使用两块ESP32开发板。
- /* Get Start Example
-
- This example code is in the Public Domain (or CC0 licensed, at your option.)
-
- Unless required by applicable law or agreed to in writing, this
- software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
- CONDITIONS OF ANY KIND, either express or implied.
- */
-
- #include "freertos/FreeRTOS.h"
- #include "freertos/task.h"
-
- #include "esp_log.h"
- #include "esp_system.h"
- #include "esp_wifi.h"
-
- #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0)
- #include "esp_mac.h"
- #endif
-
- #include "espnow.h"
- #include "espnow_storage.h"
- #include "espnow_utils.h"
-
- #include "driver/uart.h"
-
- // You can modify these according to your boards.
- #define UART_BAUD_RATE 115200
- #define UART_PORT_NUM 0
- #define UART_TX_IO UART_PIN_NO_CHANGE
- #define UART_RX_IO UART_PIN_NO_CHANGE
-
- static const char *TAG = "app_main";
-
- static void app_uart_read_task(void *arg)
- {
- esp_err_t ret = ESP_OK;
- uint32_t count = 0;
- size_t size = 0;
- uint8_t *data = ESP_CALLOC(1, ESPNOW_DATA_LEN);
-
- ESP_LOGI(TAG, "Uart read handle task is running");
-
- espnow_frame_head_t frame_head = {
- .retransmit_count = CONFIG_RETRY_NUM,
- .broadcast = true,
- };
-
- for (;;) {
- size = uart_read_bytes(UART_PORT_NUM, data, ESPNOW_DATA_LEN, pdMS_TO_TICKS(10));
- ESP_ERROR_CONTINUE(size <= 0, "");
-
- ret = espnow_send(ESPNOW_DATA_TYPE_DATA, ESPNOW_ADDR_BROADCAST, data, size, &frame_head, portMAX_DELAY);
- ESP_ERROR_CONTINUE(ret != ESP_OK, "<%s> espnow_send", esp_err_to_name(ret));
-
- ESP_LOGI(TAG, "espnow_send, count: %" PRIu32 ", size: %u, data: %s", count++, size, data);
- memset(data, 0, ESPNOW_DATA_LEN);
- }
-
- ESP_LOGI(TAG, "Uart handle task is exit");
-
- ESP_FREE(data);
- vTaskDelete(NULL);
- }
-
- static void app_uart_initialize()
- {
- uart_config_t uart_config = {
- .baud_rate = UART_BAUD_RATE,
- .data_bits = UART_DATA_8_BITS,
- .parity = UART_PARITY_DISABLE,
- .stop_bits = UART_STOP_BITS_1,
- .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
- #if SOC_UART_SUPPORT_REF_TICK
- .source_clk = UART_SCLK_REF_TICK,
- #elif SOC_UART_SUPPORT_XTAL_CLK
- .source_clk = UART_SCLK_XTAL,
- #endif
- };
-
- ESP_ERROR_CHECK(uart_param_config(UART_PORT_NUM, &uart_config));
- ESP_ERROR_CHECK(uart_set_pin(UART_PORT_NUM, UART_TX_IO, UART_RX_IO, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
- ESP_ERROR_CHECK(uart_driver_install(UART_PORT_NUM, 8 * ESPNOW_DATA_LEN, 8 * ESPNOW_DATA_LEN, 0, NULL, 0));
-
- xTaskCreate(app_uart_read_task, "app_uart_read_task", 4 * 1024, NULL, tskIDLE_PRIORITY + 1, NULL);
- }
-
- static void app_wifi_init()
- {
- esp_event_loop_create_default();
-
- wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
-
- ESP_ERROR_CHECK(esp_wifi_init(&cfg));
- ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
- ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM));
- ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE));
- ESP_ERROR_CHECK(esp_wifi_start());
- }
-
- static esp_err_t app_uart_write_handle(uint8_t *src_addr, void *data,
- size_t size, wifi_pkt_rx_ctrl_t *rx_ctrl)
- {
- ESP_PARAM_CHECK(src_addr);
- ESP_PARAM_CHECK(data);
- ESP_PARAM_CHECK(size);
- ESP_PARAM_CHECK(rx_ctrl);
-
- static uint32_t count = 0;
-
- ESP_LOGI(TAG, "espnow_recv, <%" PRIu32 "> [" MACSTR "][%d][%d][%u]: %.*s",
- count++, MAC2STR(src_addr), rx_ctrl->channel, rx_ctrl->rssi, size, size, (char *)data);
-
- return ESP_OK;
- }
-
- void app_main()
- {
- espnow_storage_init();
-
- app_uart_initialize();
- app_wifi_init();
-
- espnow_config_t espnow_config = ESPNOW_INIT_CONFIG_DEFAULT();
- espnow_init(&espnow_config);
-
- espnow_set_config_for_data_type(ESPNOW_DATA_TYPE_DATA, true, app_uart_write_handle);
- }
复制代码
2、代码解析
这个代码其实并不负责,首先初始化nvs存储(espnow_storage_init()),然后初始化串口设备(app_uart_initialize()),接下来初始化wifi功能,并初始化espnow功能。最后绑定espnow的回调函数,绑定接收函数调用的回调函数,在接收到发送端的数据后,回显在串口设备上。
发送端的串口线程代码如下,这个线程不断地从串口读取数据,然后将数据通过广播的形式,发送到接收设备上。
-
- static void app_uart_read_task(void *arg)
- {
- esp_err_t ret = ESP_OK;
- uint32_t count = 0;
- size_t size = 0;
- uint8_t *data = ESP_CALLOC(1, ESPNOW_DATA_LEN);
-
- ESP_LOGI(TAG, "Uart read handle task is running");
-
- espnow_frame_head_t frame_head = {
- .retransmit_count = CONFIG_RETRY_NUM,
- .broadcast = true,
- };
-
- for (;;) {
- size = uart_read_bytes(UART_PORT_NUM, data, ESPNOW_DATA_LEN, pdMS_TO_TICKS(10));
- ESP_ERROR_CONTINUE(size <= 0, "");
-
- ret = espnow_send(ESPNOW_DATA_TYPE_DATA, ESPNOW_ADDR_BROADCAST, data, size, &frame_head, portMAX_DELAY);
- ESP_ERROR_CONTINUE(ret != ESP_OK, "<%s> espnow_send", esp_err_to_name(ret));
-
- ESP_LOGI(TAG, "espnow_send, count: %" PRIu32 ", size: %u, data: %s", count++, size, data);
- memset(data, 0, ESPNOW_DATA_LEN);
- }
-
- ESP_LOGI(TAG, "Uart handle task is exit");
-
- ESP_FREE(data);
- vTaskDelete(NULL);
- }
复制代码
接收端的回调函数如下:
接收端在接收到广播数据后,打印对应的内容。
- static esp_err_t app_uart_write_handle(uint8_t *src_addr, void *data,
- size_t size, wifi_pkt_rx_ctrl_t *rx_ctrl)
- {
- ESP_PARAM_CHECK(src_addr);
- ESP_PARAM_CHECK(data);
- ESP_PARAM_CHECK(size);
- ESP_PARAM_CHECK(rx_ctrl);
-
- static uint32_t count = 0;
-
- ESP_LOGI(TAG, "espnow_recv, <%" PRIu32 "> [" MACSTR "][%d][%d][%u]: %.*s",
- count++, MAC2STR(src_addr), rx_ctrl->channel, rx_ctrl->rssi, size, size, (char *)data);
-
- return ESP_OK;
- }
复制代码
3、demo运行情况
ESPNOW使用起来还是比较简单的,但是目前示范的代码也只是一些简单的单对单、单对多、广播等内容,想要组成比较复杂的通讯网络和自定义数据转发,还是需要花时间写代码的。
|