ESP32-NOW是一种由乐鑫科技开发的无连接Wi-Fi通信协议,它可以让多个支持ESP-NOW的设备在不需要路由器或接入点的情况下进行快速、安全和低功耗的数据传输。ESP32-NOW可以应用于智能灯、遥控器、传感器等场景,也可以与其他无线通信协议如蓝牙、Wi-Fi、LoRa等结合使用。
要使用ESP32-NOW,需要以下几个步骤:
安装Arduino IDE和ESP32开发板支持包,以及esp_now库。esp_now库是一个基于ESP-NOW协议的轻量级库,它可以让您轻松地创建和注册不同的发送和接收回调函数,以及发送和接收数据结构体。编写Arduino程序,设置ESP32的Wi-Fi模式为WIFI_STA(站点模式),并初始化ESP-NOW。您还需要获取并记录每个设备的MAC地址,以便在发送数据时指定目标设备。定义一个数据结构体,用于存储和传输您想要发送或接收的数据。数据结构体可以包含不同类型的变量,如字符串、整数、浮点数、布尔值等,但总长度不能超过250字节。添加配对设备,即将目标设备的MAC地址、信道和加密方式添加到配对设备列表中。您可以选择是否启用加密功能,如果启用,则需要设置一个16字节的本地主密钥(LMK)。注册发送回调函数,用于在发送数据后通知应用层发送状态。发送状态有两种:ESP_NOW_SEND_SUCCESS(发送成功)和ESP_NOW_SEND_FAIL(发送失败)。注册接收回调函数,用于在接收数据时处理数据。可以在接收回调函数中打印或显示数据,或者根据数据执行其他操作。发送数据,即调用esp_now_send()函数,传入目标设备的MAC地址和数据结构体指针,发送数据。您可以在循环中定期发送数据,或者根据按键或传感器触发发送数据。以下是一个ESP32-NOW双向通信的代码示例,它可以实现以下功能:

Sender端代码:
#include <WiFi.h>#include <esp_now.h>#include <Wire.h>#include <Adafruit_GFX.h>#include <Adafruit_SSD1306.h>// 设置OLED屏幕参数#define SCREEN_WIDTH 128 // OLED display width, in pixels#define SCREEN_HEIGHT 64 // OLED display height, in pixels#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);// 设置光传感器引脚#define LIGHT_PIN 39// 设置数据结构体typedef struct struct_message { String board_name; int random_number; int light_value;} struct_message;struct_message myData;// 设置Receiver端的MAC地址uint8_t broadcastAddress[] = {0x24, 0x6F, 0x28, 0x88, 0x62, 0x80};// 发送回调函数void OnDataSent(const uint8_t mac_addr, esp_now_send_status_t status) { Serial.print("Packet to: "); for (int i = 0; i < 6; i++) { Serial.print(mac_addr[i], HEX); if (i < 5) { Serial.print(":"); } } Serial.println(); Serial.print("Send status: "); if (status == ESP_NOW_SEND_SUCCESS) { Serial.println("Delivery Success"); } else { Serial.println("Delivery Fail"); }}// 接收回调函数void OnDataRecv(const uint8_t mac_addr, const uint8_t data, int data_len) { char macStr[18]; snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x", mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); Serial.print("Packet received from: "); Serial.println(macStr); struct_message incomingData = (struct_message )data; Serial.print("Board name: "); Serial.println(incomingData->board_name); Serial.print("Light value: "); Serial.println(incomingData->light_value); // 在OLED屏幕上显示数据 display.clearDisplay(); display.setTextSize(1); display.setTextColor(WHITE); display.setCursor(0,0); display.println("Sender"); display.setCursor(0,10); display.println("Received from:"); display.setCursor(0,20); display.println(incomingData->board_name); display.setCursor(0,30); display.print("Light value: "); display.println(incomingData->light_value); display.display();}void setup() { // 初始化串口通信 Serial.begin(115200); // 初始化OLED屏幕 if(!display.begin(SSD1306_SWITCHCAPVCC,0x3C)){ Serial.println(F("SSD1306 allocation failed")); for(;;); // Don't proceed, loop forever } display.clearDisplay(); display.setTextSize(1); display.setTextColor(WHITE); display.setCursor(0,0); display.println("Sender"); display.display(); // 设置WiFi模式为WIFI_STA WiFi.mode(WIFI_STA); // 初始化ESP-NOW if (esp_now_init() != ESP_OK) { Serial.println("Error initializing ESP-NOW"); return; } // 注册发送回调函数 esp_now_register_send_cb(OnDataSent); // 注册接收回调函数 esp_now_register_recv_cb(OnDataRecv); // 添加配对设备 esp_now_peer_info_t peerInfo; memcpy(peerInfo.peer_addr, broadcastAddress, 6); peerInfo.channel = 0; peerInfo.encrypt = false; // 添加配对设备 if (esp_now_add_peer(&peerInfo) != ESP_OK){ Serial.println("Failed to add peer"); return; }}void loop() { // 设置数据结构体的值 myData.board_name = "Sender"; myData.random_number = random(100); // 发送数据结构体 esp_err_t result = esp_now_send(broadcastAddress, (uint8_t ) &myData, sizeof(myData)); if (result == ESP_OK) { Serial.println("Sent with success"); // 在OLED屏幕上显示数据 display.clearDisplay(); display.setTextSize(1); display.setTextColor(WHITE); display.setCursor(0,0); display.println("Sender"); display.setCursor(0,10); display.println("Sent to:"); for (int i = 0; i < sizeof(broadcastAddress); ++i) { char buffer [3]; sprintf(buffer,"%02X",broadcastAddress[i]); display.print(buffer); if(i<sizeof(broadcastAddress)-1){ display.print(":"); } } display.setCursor(0,20); display.print("Random number: "); display.println(myData.random_number); display.display();