ESP-NOW

 
这是基于ESP32板之间交换数据的一种协议,当然也支持ESP8266。ESP-NOW是乐鑫开发的无连接通信协议,具有短数据包传输的功能。该协议使多个设备可以轻松地相互通信。

这篇文章将带领大家来了解如何使用ESP-NOW,文章内容来源于国外网站,我认为这篇文章比较有价值,这是基于ESP32板之间交换数据的一种协议,当然也支持ESP8266。ESP-NOW是乐鑫开发的无连接通信协议,具有短数据包传输的功能。该协议使多个设备可以轻松地相互通信。

材料准备

  1. ESP32模块至少两个
  2. 搭建好了ESP32环境的arduino IDE,或者使用notes.qutaojiao.com中的在线编译环境

介绍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板上,则此配置非常理想。例如,可以将其配置为Web服务器以显示来自所有其他板的数据。

 

注意:在ESP-NOW文档中,没有“发送方/主方”和“接收方/从方”之类的东西。每个板都可以是发送者或接收者。但是,为使内容清楚,我们将使用术语“发送者”和“接收者”或“主”和“从”。

ESP-NOW双向通讯

使用ESP-NOW,每个板可以同时是发送者和接收者。因此,您可以在板之间建立双向通信。

例如,您可以使两个板彼此通信。

 

 

您可以在此配置中添加更多的板,并使它们看起来像一个网络(所有ESP32板彼此通信)。

总而言之,ESP-NOW是构建网络的理想选择,在该网络中,您可以有多个ESP32板相互交换数据。

ESP32:获取板的MAC地址

要通过ESP-NOW进行通信,您需要知道ESP32接收器的MAC地址。这样您便知道将信息发送到哪个设备。

每个ESP32都有一个唯一的MAC地址,这就是我们确定每个板使用ESP-NOW向其发送数据的方式(了解如何获取和更改ESP32 MAC地址)。

要获取主板的MAC地址,请上传以下代码。

  1. #include "WiFi.h"
  2. void setup(){
  3. Serial.begin(115200);
  4. WiFi.mode(WIFI_MODE_STA);
  5. Serial.println(WiFi.macAddress());
  6. }
  7. void loop(){
  8. }

上传代码后,以115200的波特率打开串口监视器,然后按ESP32 RST / EN按钮。MAC地址应如下打印:

保存您的板子MAC地址,因为您需要它通过ESP-NOW将数据发送到正确的板上。

 

ESP-NOW单向点对点通信

要通过ESP-NOW进行通信,您需要知道ESP32接收器的MAC地址。这样您便知道将信息发送到哪个设备。

每个ESP32都有一个唯一的MAC地址,这就是我们确定每个板使用ESP-NOW向其发送数据的方式(了解如何获取和更改ESP32 MAC地址)。

要获取主板的MAC地址,请上传以下代码:

  1. #include "WiFi.h"
  2. void setup(){
  3. Serial.begin(115200);
  4. WiFi.mode(WIFI_MODE_STA);
  5. Serial.println(WiFi.macAddress());
  6. }
  7. void loop(){
  8. }

 

上传代码后,以115200的波特率打开串口监视器,然后按ESP32 RST / EN按钮。MAC地址应如下打印:

保存您的板MAC地址,因为您需要它通过ESP-NOW将数据发送到正确的板上。

ESP-NOW单向点对点通信

为了让您开始使用ESP-NOW无线通信,我们将构建一个简单的项目,展示如何从一个ESP32向另一个ESP32发送消息。一个ESP32将成为“发送方”,另一个ESP32将成为“接收方”。

我们将发送一个结构,其中包含charintfloatStringboolean类型的变量。然后,您可以修改结构以发送适合您项目的任何变量类型(例如传感器读数或布尔变量以打开或关闭某些内容)。

为了更好地理解,我们将ESP32#1称为“发送者”,将ESP32#2称为“接收者”。

这是我们应该包含在发送者程序中的内容:

  1. 初始化ESP-NOW;
  2. 在发送数据时注册回调函数– OnDataSent发送消息时将执行功能。这可以告诉我们消息是否成功发送;
  3. 添加对等设备(接收方)。为此,您需要知道接收者的MAC地址;
  4. 向对等设备发送消息。

在接收者,程序应包括:

  1. 初始化ESP-NOW;
  2. 注册接收回调函数(OnDataRecv)。收到消息后将执行的功能。
  3. 在该回调函数内部,将消息保存到变量中以执行具有该信息的任何任务。

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接收到数据后,将调用一个函数。
 

ESP32发送板程序(ESP-NOW)

这是ESP32发送板的代码。将代码复制到您的Arduino IDE,但尚未上传。您需要进行一些修改以使其适合您:

  1. #include <esp_now.h>
  2. #include <WiFi.h>
  3. // REPLACE WITH YOUR RECEIVER MAC Address
  4. uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
  5. // Structure example to send data
  6. // Must match the receiver structure
  7. typedef struct struct_message {
  8. char a[32];
  9. int b;
  10. float c;
  11. String d;
  12. bool e;
  13. } struct_message;
  14. // Create a struct_message called myData
  15. struct_message myData;
  16. // callback when data is sent
  17. void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  18. Serial.print("rnLast Packet Send Status:t");
  19. Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
  20. }
  21. void setup() {
  22. // Init Serial Monitor
  23. Serial.begin(115200);
  24. // Set device as a Wi-Fi Station
  25. WiFi.mode(WIFI_STA);
  26. // Init ESP-NOW
  27. if (esp_now_init() != ESP_OK) {
  28. Serial.println("Error initializing ESP-NOW");
  29. return;
  30. }
  31. // Once ESPNow is successfully Init, we will register for Send CB to
  32. // get the status of Trasnmitted packet
  33. esp_now_register_send_cb(OnDataSent);
  34. // Register peer
  35. esp_now_peer_info_t peerInfo;
  36. memcpy(peerInfo.peer_addr, broadcastAddress, 6);
  37. peerInfo.channel = 0;
  38. peerInfo.encrypt = false;
  39. // Add peer
  40. if (esp_now_add_peer(&peerInfo) != ESP_OK){
  41. Serial.println("Failed to add peer");
  42. return;
  43. }
  44. }
  45. void loop() {
  46. // Set values to send
  47. strcpy(myData.a, "THIS IS A CHAR");
  48. myData.b = random(1,20);
  49. myData.c = 1.2;
  50. myData.d = "Hello";
  51. myData.e = false;
  52. // Send message via ESP-NOW
  53. esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));
  54. if (result == ESP_OK) {
  55. Serial.println("Sent with success");
  56. }
  57. else {
  58. Serial.println("Error sending the data");
  59. }
  60. delay(2000);
  61. }

 

代码如何工作

首先,包括 esp_now.h 和 WiFi.h 库。

  1. #include <esp_now.h>
  2. #include <WiFi.h>

在下一行中,应插入ESP32接收器MAC地址。

  1. uint8_t broadcastAddress[] = {0x30, 0xAE, 0xA4, 0x07, 0x0D, 0x64};

在我们的例子中,接收者的MAC地址是: 30:AE:A4:07:0D:64,但您需要用自己的MAC地址替换该变量。

然后,创建一个包含我们要发送的数据类型的结构。我们称这种结构struct_message它包含5种不同的变量类型。您可以更改它以发送所需的任何变量类型。

  1. typedef struct struct_message {
  2. char a[32];
  3. int b;
  4. float c;
  5. String d;
  6. bool e;
  7. } struct_message;

然后,创建一个新的类型为 struct_message 它被称作 myData 将存储变量值。

  1. struct_message myData;

接下来,定义 OnDataSent()功能。这是一个回调函数,将在发送消息时执行。在这种情况下,此功能仅打印是否成功发送了邮件。

  1. void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  2. Serial.print("rnLast Packet Send Status:t");
  3. Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
  4. }

在里面 setup(),初始化串行监视器以进行调试:

  1. Serial.begin(115200);

将设备设置为Wi-Fi站点:

  1. WiFi.mode(WIFI_STA);

立即初始化ESP:

  1. if (esp_now_init() != ESP_OK) {
  2. Serial.println("Error initializing ESP-NOW");
  3. return;
  4. }

成功初始化ESP-NOW之后,注册将在发送消息时调用的回调函数。在这种情况下,我们注册OnDataSent() 先前创建的功能。

  1. esp_now_register_send_cb(OnDataSent);

之后,我们需要与另一个ESP-NOW设备配对以发送数据。这就是我们在接下来的几行中所做的:

  1. //Register peer
  2. esp_now_peer_info_t peerInfo;
  3. memcpy(peerInfo.peer_addr, broadcastAddress, 6);
  4. peerInfo.channel = 0;
  5. peerInfo.encrypt = false;
  6. //Add peer
  7. if (esp_now_add_peer(&peerInfo) != ESP_OK){
  8. Serial.println("Failed to add peer");
  9. return;
  10. }

在loop()

我们将每2秒通过ESP-NOW发送一条消息(您可以更改此延迟时间)。

首先,我们将变量值设置如下:

  1. strcpy(myData.a, "THIS IS A CHAR");
  2. myData.b = random(1,20);
  3. myData.c = 1.2;
  4. myData.d = "Hello";
  5. myData.e = false;

请记住 myData是一个结构。在这里,我们分配要在结构内部发送的值。例如,第一行分配一个char,第二行分配一个随机的Int数,一个Float,一个String和一个Boolean变量。

我们创建这种结构来向您展示如何发送最常见的变量类型。您可以更改结构以发送任何其他类型的数据。

最后,发送消息如下:

  1. esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));

检查消息是否已成功发送:

  1. if (result == ESP_OK) {
  2. Serial.println("Sent with success");
  3. }
  4. else {
  5. Serial.println("Error sending the data");
  6. }

这 loop()每2000毫秒(2秒)执行一次。

  1. delay(2000);

 

ESP32接收板程序(ESP-NOW)

将以下代码上传至ESP32接收板:

隐藏内容,支付积分后阅读
已经有3人购买查看了此内容
100

 

代码如何工作

与发送板类似,首先包括以下库:

  1. #include <esp_now.h>
  2. #include <WiFi.h>

创建一个结构以接收数据。此结构应与发件板程序中定义的结构相同。

  1. typedef struct struct_message {
  2. char a[32];
  3. int b;
  4. float c;
  5. String d;
  6. bool e;
  7. } struct_message;

创建一个 struct_message 变量称为 myData

 

struct_message myData;

创建一个回调函数,当ESP32通过ESP-NOW接收数据时将调用该函数。该函数称为onDataRecv() 并应接受以下几个参数:

  1. void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {

我们复制内容 入库数据 数据变量放入 myData 多变的。

  1. memcpy(&myData, incomingData, sizeof(myData));

现在 myData结构内部包含几个变量,以及发送方ESP32发送的值。访问变量一种,例如,我们只需要致电 myData.a

在此示例中,我们仅打印接收到的数据,但是在实际应用中,例如,您可以在显示器上打印数据。

  1. Serial.print("Bytes received: ");
  2. Serial.println(len);
  3. Serial.print("Char: ");
  4. Serial.println(myData.a);
  5. Serial.print("Int: ");
  6. Serial.println(myData.b);
  7. Serial.print("Float: ");
  8. Serial.println(myData.c);
  9. Serial.print("String: ");
  10. Serial.println(myData.d);
  11. Serial.print("Bool: ");
  12. Serial.println(myData.e);
  13. Serial.println();
  14. }

在里面 setup(),初始化串行监视器。

  1. Serial.begin(115200);

将设备设置为Wi-Fi站。

  1. WiFi.mode(WIFI_STA);

立即初始化ESP:

  1. if (esp_now_init() != ESP_OK) {
  2. Serial.println("Error initializing ESP-NOW");
  3. return;
  4. }

注册接收数据时将调用的回调函数。在这种情况下,我们注册OnDataRecv() 先前创建的功能。

  1. esp_now_register_recv_cb(OnDataRecv);

 

测试ESP-NOW通信

将发送板程序上传到发送者ESP32板,将接收板程序上传到接收者ESP32板。

现在,打开两个Arduino IDE窗口。一个给接收者,另一个给发送者。打开每个板卡的串行监视器。每个板应该是不同的COM端口。

这就是您在发送板获得的消息:

 

这就是您应该在接收板端得到的。请注意,Int变量会在每次接收到的读数之间变化(因为我们在发送方将其设置为随机数):

我们测试了两块板之间的通信范围,并且能够在空旷的地方进行长达220米(约722英尺)的稳定通信。在该实验中,两个ESP32天线都指向彼此。

最后

我们试图使示例尽可能简单,以便更好地理解一切。还有更多与ESP-NOW相关的功能在您的项目中很有用,例如:管理对等点,删除对等点,扫描从设备等…有关完整的示例,请在Arduino IDE中转到“文件” >“示例” >“ ESP32”ESPNow,然后选择示例程序之一。

 

文中如果有错误或者任何问题,欢迎大家下方留言。

posted @ 2022-01-31 15:37  为鲸  阅读(4266)  评论(0编辑  收藏  举报