了解如何使用ESP-NOW在使用Arduino IDE编程的ESP32板之间交换数据。 ESP-NOW是由乐鑫开发的无连接通信协议,具有短数据包传输的功能。 该协议使多个设备可以轻松地相互通信。
ESP-NOW是Espressif开发的一种协议,在Espressif网站上表示,它使多个设备无需使用Wi-Fi即可相互通信。 该协议类似于低功耗2.4GHz无线连接(…)。 设备之间需要进行配对,然后才能进行通信。 配对完成后,连接安全且点对点,无需握手。”
这意味着在将设备彼此配对后,连接将保持不变。换句话说,如果您的一块板突然断电或复位,则在重新启动时,它将自动连接到其对等端以继续通信。
ESP-NOW支持以下功能:
加密和未加密的单播通信;
混合加密和未加密对等设备;
最多可以承载250字节有效负载;
发送回调函数,可以将其设置为通知应用程序层
传输成功或失败。
ESP-NOW技术还具有以下限制:
有限的加密对等体。工作站模式下最多支持10个加密对等体;在SoftAP或SoftAP + Station模式下最多6个;
支持多个未加密的对等体,但是它们的总数应少于20,其中包括已加密的对等体。
有效负载限制为250个字节。
简而言之,ESP-NOW是一种快速通信协议,可用于在ESP32板之间交换小消息(最大250字节)。
ESP-NOW具有多种用途,您可以在不同的设置中进行单向或双向通信。
ESP-NOW单向通信
例如,在单向通信中,您可能会遇到以下情形:
一个ESP32板向另一个ESP32板发送数据
这种配置非常容易实现,并且很容易将数据从一块板发送到另一块板,例如传感器读数或控制GPIO的ON和OFF命令。
一个“主” ESP32将数据发送到多个ESP32“从站”
一块ESP32板向不同的ESP32板发送相同或不同的命令。 此配置是构建遥控器之类的理想选择。 整个房屋中可以有几个由一个主ESP32板控制的ESP32板。
一个ESP32“从站”从多个“主站”接收数据
一个ESP32“从站”从多个“主站”接收数据如果要将多个传感器节点的数据收集到一个ESP32板中,则此配置非常理想。 例如,可以将其配置为Web服务器以显示来自所有其他板的数据。
注意:在ESP-NOW文档中,没有“发件人/主人”和“接收者/从属”之类的东西。 每个板都可以是发送者或接收者。 但是,为使内容清楚,我们将使用“发送者”和“接收者”或“主”和“从”这两个术语。
ESP-NOW双向通讯
使用ESP-NOW,每个板都可以同时是发送者和接收者。 因此,您可以在板之间建立双向通信。
例如,您可以使两个板彼此通信。
您可以在此配置中添加更多板卡,并使它们看起来像一个网络(所有ESP32板卡都可以相互通信)。
总而言之,ESP-NOW是构建网络的理想选择,在该网络中,您可以有多个ESP32板相互交换数据。
ESP32:获取板的MAC地址
要通过ESP-NOW进行通信,您需要知道ESP32接收器的MAC地址。 这样您才能知道将信息发送到哪个设备。
每个ESP32都有一个唯一的MAC地址,这就是我们识别每块板以使用ESP-NOW向其发送数据的方式(了解如何获取和更改ESP32 MAC地址)。
要获取主板的MAC地址,请上传以下代码。
#include "WiFi.h"
void setup(){
Serial.begin(115200);
WiFi.mode(WIFI_MODE_STA);
Serial.println(WiFi.macAddress());
}
void loop(){
}
请保存您的板卡MAC地址,因为您需要它通过ESP-NOW将数据发送到正确的板卡。
ESP-NOW单向点对点通信
为了让您开始使用ESP-NOW无线通信,我们将构建一个简单的项目,展示如何将消息从一个ESP32发送到另一个。 一个ESP32将成为“发送方”,另一个ESP32将成为“接收方”。
我们将发送一个结构,其中包含char,int,float,String和boolean类型的变量。然后,您可以修改结构以发送适合您项目的任何变量类型(例如传感器读数或布尔变量以打开或关闭某些内容)。
为了更好地理解,我们将ESP32#1称为“发送者”,将ESP32#2称为“接收者”。
这是我们应包含在发件人草图中的内容:
初始化ESP-NOW;
发送数据时注册回调函数–发送消息时将执行OnDataSent函数。这可以告诉我们消息是否成功发送;
添加一个对等设备(接收方)。为此,您需要知道接收者的MAC地址;
向对等设备发送消息。
在接收方,草图应包括:
初始化ESP-NOW;
注册接收回调函数(OnDataRecv)。收到消息后将执行的功能。
在该回调函数内部,将消息保存到变量中以执行具有该信息的任何任务。
ESP-NOW与回调函数一起使用,这些回调函数在设备收到消息或发送消息时调用(您可以确定消息是否已成功发送或失败)。
ESP-NOW有用的功能
以下是最基本的ESP-NOW功能的摘要:
函数名称和说明
esp_now_init()初始化ESP-NOW。 您必须先初始化Wi-Fi,然后再初始化ESP-NOW。
esp_now_add_peer()调用此函数以配对设备并将对等MAC地址作为参数传递。
esp_now_send()使用ESP-NOW发送数据。
esp_now_register_send_cb()注册在发送数据时触发的回调函数。 发送消息后,将调用一个函数–该函数返回传递是否成功。
esp_now_register_rcv_cb()注册在接收数据时触发的回调函数。 通过ESP-NOW接收到数据后,将调用一个函数。
有关这些功能的更多信息,请参阅“阅读文档”中的ESP-NOW文档。
ESP32发件人草图(ESP-NOW)
这是ESP32发送板的代码。 将代码复制到您的Arduino IDE,但尚未上传。 您需要进行一些修改以使其适合您。
/*
Rui Santos
Complete project details at https://RandomNerdTutorials.com/esp-now-esp32-arduino-ide/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
*/
#include
#include
// 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;
String d;
bool e;
} struct_message;
// Create a struct_message called myData
struct_message myData;
// 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
esp_now_peer_info_t peerInfo;
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 = "Hello";
myData.e = 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);
}
代码如何工作
首先,包括esp_now.h和WiFi.h库。
#include
#include
在下一行中,应插入ESP32接收器MAC地址。
uint8_t broadcastAddress[] = {0x30, 0xAE, 0xA4, 0x07, 0x0D, 0x64};
在我们的例子中,接收者的MAC地址是:30:AE:A4:07:0D:64,但是您需要用您自己的MAC地址替换该变量。
然后,创建一个包含我们要发送的数据类型的结构。 我们将此结构称为struct_message,它包含5种不同的变量类型。 您可以更改此设置以发送所需的任何变量类型。
typedef struct struct_message {
char a[32];
int b;
float c;
String d;
bool e;
} struct_message;
然后,创建一个名为myData的struct_message类型的新变量,该变量将存储变量值。
接下来,定义OnDataSent()函数。 这是一个回调函数,将在发送消息时执行。 在这种情况下,此功能仅打印是否成功发送了邮件。
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");
}
ESP32 Receiver Sketch (ESP-NOW)
/*
Rui Santos
Complete project details at https://RandomNerdTutorials.com/esp-now-esp32-arduino-ide/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
*/
#include
#include
// Structure example to receive data
// Must match the sender structure
typedef struct struct_message {
char a[32];
int b;
float c;
String d;
bool e;
} struct_message;
// Create a struct_message called myData
struct_message myData;
// callback function that will be executed when data is received
void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
memcpy(&myData, incomingData, sizeof(myData));
Serial.print("Bytes received: ");
Serial.println(len);
Serial.print("Char: ");
Serial.println(myData.a);
Serial.print("Int: ");
Serial.println(myData.b);
Serial.print("Float: ");
Serial.println(myData.c);
Serial.print("String: ");
Serial.println(myData.d);
Serial.print("Bool: ");
Serial.println(myData.e);
Serial.println();
}
void setup() {
// Initialize 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 recv CB to
// get recv packer info
esp_now_register_recv_cb(OnDataRecv);
}
void loop() {
}