ESP32 ESP-NOW 是专门为其 ESP8266 和 ESP32 微控制器开发的无线通信协议。它为 ESP32 设备提供低功耗、安全、低成本、直接的无线通信解决方案。借助 ESP-NOW,多个 ESP32 设备可以相互通信,无需 WiFi 或路由器,从而创建设备的网状网络。
在本教程中,我们将学习使用 ESP32 ESP-NOW 在 ESP32 设备之间进行无线通信。无论您想要发送传感器数据、控制 ESP 输出还是建立双向通信,本指南都将为您提供必要的步骤。
ESP-NOW 协议介绍
使用 ESP-NOW,我们可以在 ESP MCU 设备之间进行单向甚至双向通信,而无需使用 Wi-Fi 网络。它允许低开销的点对点无线数据传输,但数据包较小。最多可传输 250 字节的数据。因此,如果需要传输大量数据,那么使用此协议就没用了。
使用 ESP-NOW,连接协议得到简化,从而降低了功耗,因为数据传输所需的时间更少。此外,ESP-NOWESP-NOW使用与 Wi-Fi 相同的 2.4 GHz 频段,但不需要连接或干扰本地网络连接。它是一种快速、方便的通信协议,适用于传输较小量的数据。
ESP32 ESP-NOW 主要特性
- 一对一的数据传输(加密和未加密)。
- 支持加密和未加密的对等设备。对于加密设备,工作站模式下最多有 10 个对等点,SoftAP 或两种模式的混合模式下最多有 6 个对等点。但是,对于未加密的设备,最多允许有 19 个设备,且不限制其运行模式。
- 最多可以以小数据包的形式传输 250 字节的数据。
- 它生成一个回调函数,通知应用层数据是否传输成功。
要初始化 ESP-NOW 连接,我们必须首先配对 ESP32 板。无论任何一块板重新启动,该连接都将保持,并且传输将继续顺利进行。
在本教程中,我们将演示一个 Arduino 草图,通过该草图我们将数据从一个 ESP32 板无线传输到另一块板(单向通信)。在此之前,让我们首先看一下可以使用该通信协议的一些配置。
ESP32 ESP-NOW 单向通信
在单向通信中,一个对等设备充当发送方/主设备,另一台充当接收方/从设备。在这种情况下,我们可以对发送方-接收方进行多种配置。
- 一块 ESP32 板向另一块 ESP32 板发送数据
如下图所示,一块 ESP32 板充当发送器,另一块板接收数据,因此充当接收器。
用途:发送传感器数据,控制 ESP 输出,包括 LED、继电器、蜂鸣器等。
- 一块 ESP32 发送器板向其他各种 ESP32 接收器板发送数据
在这种情况下,一个 ESP32 板将充当发送器/主设备,并将数据发送到多个充当接收器/从设备的 ESP32 板。
用途:遥控
- 一块 ESP32 板从其他各种 ESP32 发送器板接收数据
最后,在这种情况下,一个 ESP32 板(接收器/从机)从多个 ESP32 板(发送器/主机)接收数据。
用途:接收来自各种传感器的传感器数据。
ESP-NOW 双向通信
ESP-NOW 协议还支持对等设备之间的双向通信。在这种情况下,ESP32板可以同时充当发送器(主)和接收器(从)。我们可以有两个 ESP32 板来传输数据,如下所示:
或者甚至有一个 ESP32 板网络传输数据:
ESP-NOW 有用的功能
以下是 ESP-NOW 函数的列表,这些函数在将 ESP-NOW 与 ESP32 结合使用时非常方便且经常使用。要查看更多信息,请查看官方 ESP-NOW 文档。
- esp_now_init() :该函数将初始化 ESP-NOW 协议。请记住在初始化 ESP-NOW 通信协议之前启动 Wi-Fi。
- esp_now_add_peer() :此函数将通过将唯一的 MAC 地址作为参数传递到设备内部来连接设备。
- esp_now_send() :该函数将通过 ESP-NOW 发送数据。
- esp_now_register_send_cb() :此函数将注册一个回调函数,每当某些数据从一个对等设备发送到另一个设备时就会调用该回调函数。它将返回一条消息,指示数据是否发送成功。
- esp_now_register_rcv_cb() :此函数将注册一个回调函数,每当一个对等设备从另一设备接收到某些数据时就会调用该回调函数。
设置 Arduino IDE
我们将使用 Arduino IDE 对 ESP32 开发板进行编程。因此,应该拥有最新版本的 Arduino IDE。此外,还需要安装ESP32插件。
接下来,介绍一个 Arduino 草图,它将帮助我们识别 ESP32 板,以便我们准确地知道将数据传输到哪个板。它将在串行监视器上显示 ESP32 模块的 MAC 地址,稍后我们将在另一个草图中使用该地址。
获取ESP32 MAC地址
打开 Arduino IDE 并转到“文件”>“新建”以打开一个新文件。将下面给出的代码复制到该文件中并保存。
#include "WiFi.h"
void setup(){
Serial.begin(115200);
WiFi.mode(WIFI_MODE_STA);
Serial.println(WiFi.macAddress());
}
void loop(){
}
在 setup() 函数中,我们首先将 ESP32 板设置为站模式。然后通过使用 WiFi.macAddress() 方法,我们将获得串行监视器中唯一的 MAC 地址。
在将代码上传到开发板之前,请确保选择正确的开发板和 COM 端口。从工具 > 开发板菜单中选择ESP32 开发模块。然后,从“工具”>“端口”菜单中选择连接板的适当端口。在本例中,我们使用连接到 COM5 的 ESP32 开发板。
点击上传按钮将代码上传到ESP32开发板中。草图上传后按启用按钮。
在 Arduino IDE 中,打开串行监视器,您将能够看到 ESP32 模块的唯一 MAC 地址。
稍后我们将使用这个唯一地址来识别接收器 ESP32 模块。
ESP32 ESP-NOW 单向通信示例
现在,让我们学习如何使用 ESP-NOW 协议将数据从一个 ESP32 板发送到另一块板。我们将使用最简单的配置,其中一个 ESP32 板充当发送器,另一块 ESP32 板充当接收器。您可以使用下面给出的方法将传感器数据或任何类型的信息从一个 ESP 板传输到另一块板。我们将保持简单并在草图中创建一个结构,该结构将存储 char、int、float 和 Boolean 类型的值。这将帮助我们通过更改草图中的结构来传输任何类型的数据。对于这个项目,我们需要两个 Arduino 草图,一个用于发送器,另一个用于接收器。
发送端的 ESP-NOW ESP32 Arduino 草图
打开 Arduino IDE 并转到“文件”>“新建”以打开一个新文件。将下面给出的代码复制到该文件中并保存。该草图遵循以下几点:
- 首先,我们将使用 esp_now_init() 函数初始化 ESP NOW。
- 然后我们将创建一个名为 data_sent() 的回调函数,并使用 esp_now_register_send_cb() 将其注册为回调函数。这将在串行监视器中返回一条消息,显示数据是否已成功传输。
- 下一步将使用其唯一的 MAC 地址添加接收器 ESP32 板。
- 然后,我们将数据发送到我们设置的对等设备。
#include <esp_now.h>
#include <WiFi.h>
// REPLACE WITH YOUR RECEIVER MAC Address
uint8_t broadcastAddress[] = {0x7C, 0x9E, 0xBD, 0x37, 0xCA, 0x84};
typedef struct struct_message {
char character[100];
int integer;
float floating_value;
bool bool_value;
} struct_message;
struct_message message;
void data_sent(const uint8_t *mac_addr, esp_now_send_status_t status) {
Serial.print("\r\nStatus of Last Message Sent:\t");
Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_STA);
if (esp_now_init() != ESP_OK) {
Serial.println("Error initializing ESP-NOW");
return;
}
esp_now_register_send_cb(data_sent);
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() {
strcpy(message.character, "Welcome to Microcontrollerslab! This is test example.");
message.integer = random(1,10);
message.floating_value = 5.6;
message.bool_value = true;
esp_err_t outcome = esp_now_send(broadcastAddress, (uint8_t *) &message, sizeof(message));
if (outcome == ESP_OK) {
Serial.println("Mesage sent successfully!");
}
else {
Serial.println("Error sending the message");
}
delay(2000);
}
该代码如何运作?
包括库
首先,我们将包含必要的库。对于发送者草图,我们使用其中两个。其中包括用于 ESP-NOW 通信协议的 esp_now.h,以及允许我们的 ESP32 板使用 Wi-Fi 功能的 WiFi.h。
#include <esp_now.h>
#include <WiFi.h>
指定接收方 MAC 地址
其次,我们将指定充当接收器的 ESP32 板的 MAC 地址。在查找 MAC 地址时,我们将使用与上面草图中使用的相同的 ESP32 板。将地址替换为您自己的 ESP32 板的唯一 MAC 地址。您可以使用之前给出的草图来查找模块的 MAC 地址。
// REPLACE WITH YOUR RECEIVER MAC Address
uint8_t broadcastAddress[] = {0x7C, 0x9E, 0xBD, 0x37, 0xCA, 0x84};
定义发送数据的结构
现在,我们将定义一个名为“struct_message”的结构。在结构内部,我们将初始化变量,这些变量将保存我们将通过 ESP-NOW 传输到接收器板的数据。它们的类型为 char、int、float 和 bool。
typedef struct struct_message {
char character[100];
int integer;
float floating_value;
bool bool_value;
} struct_message;
接下来,我们将创建一个 struct_message 类型的新变量并将其称为消息。稍后将在草图中使用它来获取数据并相应地传输它。
struct_message message;
data_sent()
回调函数 data_sent() 充当消息的接收者。我们现在将该函数定义为参数,同时注册它以发送消息。每当 ESP32 发送方发送消息时,串行监视器都会打印消息是否成功发送。
void data_sent(const uint8_t *mac_addr, esp_now_send_status_t status) {
Serial.print("\r\nStatus of Last Message Sent:\t");
Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}
setup()
在 setup() 函数中,我们将以 115200 的波特率打开串行连接,并将 ESP32 板设置为站模式。
Serial.begin(115200);
WiFi.mode(WIFI_STA);
以下代码行将初始化 ESP-NOW 协议。如果连接不成功,串行监视器将显示“初始化 ESP-NOW 时出错”。
if (esp_now_init() != ESP_OK) {
Serial.println("Error initializing ESP-NOW");
return;
}
现在我们将 data_sent() 函数注册为回调函数。这将确保每当从发送方发送消息时,都会调用 data_sent() 函数。
esp_now_register_send_cb(data_sent);
以下代码行将两个 ESP32 板(发送器和接收器)配对。
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;
}
loop()
在loop()函数内,我们将消息传输到接收器ESP32板。每 2 秒后,将发送以下消息:
“欢迎来到微控制器实验室!这是一个测试示例” 作为字符,一个 1-10 之间的随机整数、浮点数 5.6 和值 1,因为我们已将 bool_value 设置为“true”。
您可以根据需要轻松更改“消息”的结构以发送数据。我们在这里合并了常见的数据类型。
strcpy(message.character, "Welcome to Microcontrollerslab! This is a test example.");
message.integer = random(1,10);
message.floating_value = 5.6;
message.bool_value = true;
然后我们将发送消息并监控消息是否发送成功。
esp_err_t outcome = esp_now_send(broadcastAddress, (uint8_t *) &message, sizeof(message));
if (outcome == ESP_OK) {
Serial.println("Mesage sent successfully!");
}
else {
Serial.println("Error sending the message");
}
接收端的 ESP-NOW ESP32 Arduino 草图
打开 Arduino IDE 并转到“文件”>“新建”以打开一个新文件。将下面给出的代码复制到该文件中并保存。该草图遵循以下几点:
- 同样,我们首先使用 esp_now_init() 函数初始化 ESP NOW。
- 然后,我们将创建另一个名为 data_receive() 的函数,并使用 esp_now_register_rcv_cb() 将其注册为回调函数。每当接收器 ESP32 板收到数据时,都会调用此回调函数。
#include <esp_now.h>
#include <WiFi.h>
typedef struct struct_message {
char character[100];
int integer;
float floating_value;
bool bool_value;
} struct_message;
struct_message message;
void data_receive(const uint8_t * mac, const uint8_t *incomingData, int len) {
memcpy(&message, incomingData, sizeof(message));
Serial.print("Bytes received: ");
Serial.println(len);
Serial.print("Char: ");
Serial.println(message.character);
Serial.print("Int: ");
Serial.println(message.integer);
Serial.print("Float: ");
Serial.println(message.floating_value);
Serial.print("Bool: ");
Serial.println(message.bool_value);
Serial.println();
}
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_STA);
if (esp_now_init() != ESP_OK) {
Serial.println("Error initializing ESP-NOW");
return;
}
esp_now_register_recv_cb(data_receive);
}
void loop() {
}
该代码如何运作?
包括库
首先,我们将包含必要的库。对于接收器草图,我们还使用与发送器草图相同的两个库。其中包括用于 ESP-NOW 通信协议的 esp_now.h,以及允许我们的 ESP32 板使用 Wi-Fi 功能的 WiFi.h。
#include <esp_now.h>
#include <WiFi.h>
定义接收数据的结构
现在,我们将定义与我们为发送者草图所做的相同的结构,名为“struct_message”。该结构将用于接收将通过 ESP NOW 从接收器 ESP32 板接收的数据。确保两个草图中的结构相同。
typedef struct struct_message {
char character[100];
int integer;
float floating_value;
bool bool_value;
} struct_message;
接下来,我们将创建一个 struct_message 类型的新变量并将其称为消息。稍后将在草图中使用它来接收数据。
struct_message message;
data_receive()
data_receive() 函数充当我们现在将定义的回调函数。当我们注册这个回调函数来接收消息时,它将被用作参数。每当从 ESP32 发送方收到消息时,就会在串行监视器上打印消息。
void data_receive(const uint8_t * mac, const uint8_t *incomingData, int len) {
memcpy(&message, incomingData, sizeof(message));
Serial.print("Bytes received: ");
Serial.println(len);
Serial.print("Char: ");
Serial.println(message.character);
Serial.print("Int: ");
Serial.println(message.integer);
Serial.print("Float: ");
Serial.println(message.floating_value);
Serial.print("Bool: ");
Serial.println(message.bool_value);
Serial.println();
}
setup()
在 setup() 函数中,我们将以 115200 的波特率打开串行连接,并将 ESP32 接收器板设置为站模式。
Serial.begin(115200);
WiFi.mode(WIFI_STA);
以下代码行将初始化 ESP-NOW 协议。如果连接不成功,串行监视器将显示“初始化 ESP-NOW 时出错”。
if (esp_now_init() != ESP_OK) {
Serial.println("Error initializing ESP-NOW");
return;
}
现在我们将 data_receive() 函数注册为回调函数,如下所示。这将确保每当从发送方收到消息时,都会调用 data_receive() 函数。
esp_now_register_recv_cb(data_receive);
演示 ESP32 ESP-NOW 单向通信
现在,保存发送器和接收器草图后,将它们上传到各自的 ESP32 板上。
首先,打开发送者草图。在将代码上传到发送器 ESP32 板之前,选择正确的板和 COM 端口。转到工具 > 开发板并选择 ESP32 开发模块。
接下来,转到“工具”>“端口”,然后选择用于连接开发板的适当端口。
单击上传按钮将代码上传到 ESP32 板(发送器)。将代码上传到开发板后,按“启用”按钮。
接下来,按照相同的步骤将接收器侧草图上传到接收器 ESP32 模块。确保选择正确的 COM 端口进行连接。请注意,两块板将连接到不同的 COM 端口,因此请相应地选择 COM 端口。单击上传按钮将代码上传到 ESP32 板(接收器)。将代码上传到开发板后,按“启用”按钮。
现在,打开两个串行监视器。每 2 秒后您将能够看到接收方显示的消息。其中包括我们在程序草图中指定的 char、int、float 和 bool 参数。
在发送方的串行监视器中,您将能够查看消息已成功发送的文本。
请注意,两个 COM 端口是不同的。在我们的例子中,接收方为 COM5,发送方为 COM11。
如何保护 ESP-NOW 通信的安全
您可以通过多种方法来保护 ESP-NOW 通信的安全,以保证其安全和私密:
加密数据:加密数据是保护 ESP-NOW 通信安全的最有用方法之一。您可以使用不同的加密算法对数据进行加密,例如 AES 或 RSA。加密数据将防止任何人拦截和读取传输的数据。
使用安全密钥:ESP-NOW 支持使用安全密钥进行身份验证并在设备之间建立连接。通过使用安全密钥,您可以确保只有授权的设备才能相互通信。
使用安全通信协议:如果应用程序的安全性需要更高级的安全措施,您可能需要考虑使用不同的通信协议,例如 WiFi,它内置了对加密和身份验证的支持。
使用单独的安全层:在某些情况下,在 ESP-NOW 之上使用单独的安全层来提供额外的安全性可能很有用。例如,您可以使用安全隧道协议(例如 HTTPS)来保护通过 ESP-NOW 传输的数据。
ESP32 ESP-NOW 系列
ESP-NOW 的范围取决于多种因素,包括天线设计和配置以及操作环境。一般来说,ESP-NOW 的范围可达 220 米(772 英尺),但是,这些范围是近似值,根据具体情况可能会有很大差异。
可能影响 ESP-NOW 范围的因素包括:
射频干扰:ESP-NOW 运行在 2.4 GHz 频段,与蓝牙和 WiFi 等其他无线技术共享该频段。这意味着可能会受到在同一频段运行的其他设备的干扰。
运行环境:ESP-NOW 的范围可能会受到墙壁、天花板和地板等物理障碍以及温度、湿度和大气压力等环境因素的影响。
天线设计:ESP-NOW 的范围可能会受到所用天线的类型和设计的影响。例如,使用定向天线可以增加 ESP-NOW 的范围,而使用全向天线则可以缩小范围。
总的来说,在选择 ESP-NOW 等无线通信协议时,考虑应用的具体范围要求非常重要。
结论
总之,我们了解了 ESP-NOW 通信协议及其各种功能。例如,我们以快速方便的方式将一小包数据从一个 ESP32 板发送到另一个板。您可以使用相同的草图来传输有用的数据,包括传感器读数,甚至可以通过另一块 ESP32 板轻松控制一块 ESP32 板的输出引脚。尽管如此,我们使用了两个 ESP32 板来相互通信。但你也可以使用 ESP-NOW 在 ESP8266 和 ESP32 板之间进行通信。
本文由IC先生网www.mrchip.cn编辑整理发布,请勿转载。