赞
踩
ESP32 是一款功能强大的 Wi-Fi 和蓝牙双模模块,可用于使用 ESP-NOW 协议实现低功耗、高效率的一对多通信。本文将介绍如何使用ESP-NOW协议进行一对多通信,并在接收端存储发送方的MAC地址。
本文主要实现在使用ESP-NOW协议进行一对多通信以及接收端存储发送方的MAC地址,当esp32上电后检测有无存储MAC地址,有则将MAC添加到对等点peer,当接收到now信息时将发送端的MAC存储到flash中方便下次直接发送信息。
看本次代码直接划到最后即可!
ESP-NOW 协议是乐鑫开发的一种快速高效的无线通信协议,专门用于 ESP8266 和 ESP32 模块之间的点对点或点对多点通信。它支持单播和组播两种传输模式,能够在网状网络中支持多达 20 个节点。与 Wi-Fi 和蓝牙等其他无线通信协议相比,ESP-NOW 特点如下:
本次开发IDE:arduino2.0.4
要在 ESP32 上配置 ESP-NOW,通过以下几步:
#include <esp_now.h> #include <WiFi.h> // REPLACE WITH YOUR RECEIVER MAC Address uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; // Structure example to send data // Must match the receiver structure typedef struct struct_message { char a[32]; int b; float c; bool d; } struct_message; // Create a struct_message called myData struct_message myData; esp_now_peer_info_t peerInfo; // callback when data is sent void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) { Serial.print("\r\nLast Packet Send Status:\t"); Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail"); } void setup() { // Init Serial Monitor Serial.begin(115200); // Set device as a Wi-Fi Station WiFi.mode(WIFI_STA); // Init ESP-NOW if (esp_now_init() != ESP_OK) { Serial.println("Error initializing ESP-NOW"); return; } // Once ESPNow is successfully Init, we will register for Send CB to // get the status of Trasnmitted packet esp_now_register_send_cb(OnDataSent); // Register peer memcpy(peerInfo.peer_addr, broadcastAddress, 6); peerInfo.channel = 0; peerInfo.encrypt = false; // Add peer if (esp_now_add_peer(&peerInfo) != ESP_OK){ Serial.println("Failed to add peer"); return; } } void loop() { // Set values to send strcpy(myData.a, "THIS IS A CHAR"); myData.b = random(1,20); myData.c = 1.2; myData.d = false; // Send message via ESP-NOW esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData)); if (result == ESP_OK) { Serial.println("Sent with success"); } else { Serial.println("Error sending the data"); } delay(2000); }
不知道如何获取MAC地址?
#include "WiFi.h"
void setup(){
Serial.begin(115200);
WiFi.mode(WIFI_MODE_STA);
Serial.println(WiFi.macAddress());
}
void loop(){
}
要使用 ESP-NOW 协议实现一对多通信,首先需要配置发送端和接收端。在发送端只需要读取有无存储到flash的MAC信息,如果有就添加到peer中,如果没有就等待接收到now信息然后添加到flash以及peer中。通过now信息发送将已添加到now里的对等点(peer)发送now信息。
esp_err_t result = esp_now_send(0, (uint8_t *)&test, sizeof(test_struct));
WiFi.useStaticBuffers(true);
在一对多通信场景中,跟踪发件人的 MAC 地址通常很有用。可以通过在接收方创建一个列表来存储所有发送方的 MAC 地址。每当收到新消息时,都可以从消息中提取发件人的 MAC 地址并将其添加到列表中。这样,就可以跟踪所有发件人及其相应的 MAC 地址。
在这里将MAC地址存储进入flash中,使用库是ArduinoNvs.h
,该库可以使存储信息到flash中简单化!
库地址如下
https://github.com/rpolitex/ArduinoNvs
打开不了?
来资源里下载(点击这里):https://download.csdn.net/download/hongyun1221/87712695
附上代码
#include <WiFi.h> #include <esp_now.h> #include "ArduinoNvs.h" #define MAX_MAC_ADDRESSES 10 //最大20个 esp_now_peer_info_t peerInfo; typedef struct test_struct { int x; int y; } test_struct; test_struct test; void printMacAddress(const uint8_t *macBytes) { for (int i = 0; i < 6; i++) { Serial.print(macBytes[i], HEX); if (i < 5) { Serial.print(":"); } } Serial.println(); } // Helper function to convert a MAC address array to a string String macToString(const uint8_t *mac) { String address = ""; for (int i = 0; i < 6; ++i) { address += String(mac[i], HEX); if (i < 5) { address += ":"; } } return address; } bool addPeer(const String &macAddress) { uint8_t macBytes[6]; peerInfo.channel = 0; peerInfo.encrypt = false; if (sscanf(macAddress.c_str(), "%02X:%02X:%02X:%02X:%02X:%02X", &macBytes[0], &macBytes[1], &macBytes[2], &macBytes[3], &macBytes[4], &macBytes[5]) != 6) { Serial.println("Failed to parse MAC address"); return false; } memcpy(peerInfo.peer_addr, macBytes, 6); if (esp_now_add_peer(&peerInfo) != ESP_OK) { Serial.println("Failed to add peer"); return false; } return true; } // callback when data is sent void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) { char macStr[18]; Serial.print("Packet to: "); // Copies the sender mac address to a string 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(macStr); Serial.print(" send status:\t"); Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail"); } void OnDataRecv(const uint8_t *mac, const uint8_t *incomingData, int len) { Serial.print("received MAC: "); Serial.print(macToString(mac)); Serial.print("Bytes received: "); Serial.println(len); // Check if MAC already exists in NVS String macAddress = macToString(mac); int count = NVS.getInt("count", 0); bool macExists = false; for (int i = 0; i < count; i++) { String storedMac = NVS.getString("mac" + String(i)); if (storedMac.equals(macAddress)) { macExists = true; Serial.println("macExists"); break; } } if (!macExists) { if (count >= MAX_MAC_ADDRESSES) { for (int i = 0; i < count; i++) { String nextMac = NVS.getString("mac" + String(i + 1)); NVS.setString("mac" + String(i), nextMac); } // Store the MAC address in NVS and add it to ESP-NOW peer node list NVS.setString("mac" + String(count-1), macToString(mac)); NVS.setInt("count", count); Serial.println("打印已存储的mac"); for (int i = 0; i < count; i++) { String macAddress = NVS.getString("mac" + String(i)); Serial.print(i); Serial.print(". "); Serial.println(macAddress); } ESP.restart(); } else { // Store the MAC address in NVS and add it to ESP-NOW peer node list NVS.setString("mac" + String(count), macToString(mac)); NVS.setInt("count", count + 1); memcpy(peerInfo.peer_addr, mac, 6); peerInfo.channel = 1; peerInfo.encrypt = false; if (esp_now_add_peer(&peerInfo) != ESP_OK) { Serial.println("Failed to add peer"); ESP.restart(); } } } } void setup() { Serial.begin(115200); // Initialize WiFi and ESP-NOW WiFi.useStaticBuffers(true); //非常重要!强制 Arduino 使用默认的 sdkconfig! WiFi.mode(WIFI_STA); // 初始化 ESP-NOW if (esp_now_init() == ESP_OK) { Serial.println("ESPNow Init Success"); } else { Serial.println("ESPNow Init Failed"); ESP.restart(); } // Initialize NVS NVS.begin("my-app"); // Print the stored MAC addresses int count = NVS.getInt("count", 0); Serial.printf("Stored %d MAC addresses:\n", count); for (int i = 0; i < count; i++) { String macAddress = NVS.getString("mac" + String(i)); Serial.print(i); Serial.print(". "); Serial.println(macAddress); if (addPeer(macAddress)) { // 成功添加对等节点 -- 处理 } else { // 添加对等节点失败 -- 处理 } } esp_now_register_send_cb(OnDataSent); esp_now_register_recv_cb(OnDataRecv); //信息初始化 test.x = 5123; test.y = 12345; } void loop() { delay(5000); int count = NVS.getInt("count", 0); //向已存在的同等体发送信息 if (0 == count) { Serial.println("No peer"); } else { esp_err_t result = esp_now_send(0, (uint8_t *)&test, sizeof(test_struct)); if (result == ESP_OK) { Serial.println("Sent with success"); } else { Serial.println("Error sending the data"); } Serial.print("Peer count: "); Serial.println(count); } }
输出展示:
以下是函数的讲解:
printMacAddress(const uint8_t *macBytes):打印 MAC 地址数组。
macToString(const uint8_t *mac):将 MAC 地址数组转换为字符串类型。
addPeer(const String &macAddress):将设备添加到 ESP NOW 对等节点列表中。
OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status):发送数据回调函数。如果数据发送成功,将打印“Delivery Success”;否则将打印“Delivery Fail”。
OnDataRecv(const uint8_t *mac, const uint8_t *incomingData, int len):接收数据回调函数。将检查是否已经存在该设备的 MAC 地址,并根据需要将其添加到 ESP NOW 对等节点列表中。
setup():初始化 Wi-Fi、ESP NOW 和 NVS。该函数还会打印存储的 MAC 地址,并注册了发送和接收数据的回调函数。
loop():每隔五秒钟向已配对的设备发送测试结构体 test 中的数据。该函数还会显示当前已存储的对等节点数量。
#define MAX_MAC_ADDRESSES 10 // 最大允许存储的 MAC 地址数量
esp_now_peer_info_t peerInfo; // 定义 ESP-NOW 的对等节点信息结构体
部分函数讲解
定义两个辅助函数,一个将MAC地址数组打印为十六进制字符串,另一个将MAC地址数组转换为字符串类型。
void printMacAddress(const uint8_t *macBytes) { for (int i = 0; i < 6; i++) { Serial.print(macBytes[i], HEX); if (i < 5) { Serial.print(":"); } } Serial.println(); } // Helper function to convert a MAC address array to a string String macToString(const uint8_t *mac) { String address = ""; for (int i = 0; i < 6; ++i) { address += String(mac[i], HEX); if (i < 5) { address += ":"; } } return address; }
定义将MAC地址添加到ESP-NOW对等体结构体变量中的函数。
bool addPeer(const String &macAddress) {
uint8_t macBytes[6];
peerInfo.channel = 0;
peerInfo.encrypt = false;
if (sscanf(macAddress.c_str(), "%02X:%02X:%02X:%02X:%02X:%02X", &macBytes[0], &macBytes[1], &macBytes[2], &macBytes[3], &macBytes[4], &macBytes[5]) != 6) {
Serial.println("Failed to parse MAC address");
return false;
}
memcpy(peerInfo.peer_addr, macBytes, 6);
if (esp_now_add_peer(&peerInfo) != ESP_OK) {
Serial.println("Failed to add peer");
return false;
}
return true;
}
总之,ESP-NOW 协议是一种强大的无线通信协议,可用于使用 ESP32 模组实现一对多通信。通过将发射器和接收器配置为使用 ESP-NOW 协议,您可以实现与多个节点的低延迟、高吞吐量和低功耗通信。此外,通过存储发送方的 MAC 地址,您可以跟踪网络中的所有节点。通过限制存储的 MAC 地址数量,可以防止内存溢出问题并确保 ESP32 模组的高效运行。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。