ESP32 入门笔记07: ESP-NOW (ESP32 for Arduino)


【B站乐鑫】 ESP-NOW 无线通信方案


简介

ESP-NOW 是一种快速、无连接的通信技术,具有短数据包传输的特点。

ESP-NOW 是乐鑫开发的一种“协议”,它使多个设备无需使用 Wi-Fi 即可相互通信。该协议类似于低功耗 2.4GHz 无线连接 。在通信之前需要设备之间的配对。配对完成后,连接是安全的点对点连接,不需要握手

这意味着在设备彼此配对后,连接是持久的。换句话说,如果你的一块板突然断电或复位,当它重新启动时,它会自动连接到它的对端以继续通信。

ESP-NOW 是智能灯、遥控设备、传感器和其他应用的理想选择。

ESP-NOW 支持以下功能:

  • 加密和未加密的单播通信;
  • 混合加密和未加密的对等设备;
  • 最多可携带250字节的有效载荷
  • 发送回调函数,可设置通知应用层发送成功或失败。

ESP-NOW 技术也有以下限制:

  • 有限的加密对等体。Station 模式最多支持10个加密节点;SoftAP 或SoftAP+Station 模式下最多 6 个;
  • 支持多个未加密的 peer,但包括加密的 peer 在内,总数应小于20;
  • 有效负载限制为 250 字节。

简单来说,ESP-NOW 是一种快速通信协议,可用于在 ESP32 开发板之间交换小消息(最多 250 字节)。


ESP-NOW 通信方式

1. ESP-NOW 单向通信

一块 ESP32 板向另一块 ESP32 板发送数据

这种配置非常容易实现,并且非常适合将数据从一块板发送到另一块板,例如传感器读数或打开和关闭命令以控制 GPIO。

在这里插入图片描述

一个ESP32“主设备” 向多个 ESP32“从设备”发送数据

一块 ESP32 开发板向不同的 ESP32 开发板发送相同或不同的命令。此配置非常适合构建类似遥控器的东西。可以在房子周围安装多个 ESP32 板,这些板由一个主 ESP32 板控制。

在这里插入图片描述

注意:在 ESP-NOW 文档中没有sender/masterreceiver/slave这样的东西。每个板都可以是发送者或接收者。但是,为了清楚起见,我们将使用术语“发送方”和“接收方”或“主控方”和“从属方”。


2. ESP-NOW 双向通信

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

例如,可以让两个板相互通信。

在这里插入图片描述

可以在此配置中添加更多电路板,并拥有一个看起来像网络的东西(所有 ESP32 电路板都相互通信)。

在这里插入图片描述


ESP32获取开发板 MAC 地址

要通过 ESP-NOW 进行通信,您需要知道ESP32 接收器的 MAC 地址。这就是您知道要将数据发送到哪个设备的方式。

什么是 MAC 地址?

MAC地址代表媒体访问控制地址,它是识别网络上每个设备的硬件唯一标识符。

MAC 地址由六组 两位 十六进制数字组成,以冒号分隔,例如:30:AE:A4:07:0D:64

MAC 地址由制造商分配,但您也可以为开发板提供自定义 MAC 地址。但是,每次板子重置时,它都会返回到其原始 MAC 地址。因此,您需要在每个草图中包含设置自定义 MAC 地址的代码。

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

获取开发板的 MAC 地址

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

#ifdef ESP32
  #include <WiFi.h>
#else
  #include <ESP8266WiFi.h>
#endif

void setup(){
  Serial.begin(115200);
  Serial.println();
  Serial.print("ESP Board MAC Address:  ");
  Serial.println(WiFi.macAddress());
}
 
void loop(){
Serial.println(WiFi.macAddress());
delay(1000);
}

重置自定义 MAC 地址

在某些应用程序中,为您的开发板提供自定义 MAC 地址可能很有用。但是,如前所述,这不会覆盖制造商设置的 MAC 地址。因此,每次您重置电路板或上传新代码时,它都会恢复为默认 MAC 地址。

#include <WiFi.h>
#include <esp_wifi.h>

// 设置你自定义的 MAC 地址 94:E6:86:09:1F:70  | 40:22:D8:5C:24:B0
uint8_t newMACAddress[] = {0x32, 0xAE, 0xA4, 0x07, 0x0D, 0x66};

void setup(){
  Serial.begin(115200);
  Serial.println();
  
  WiFi.mode(WIFI_STA);
  
  Serial.print("[OLD] ESP32 Board MAC Address:  ");
  Serial.println(WiFi.macAddress());
  
  // ESP32 Board add-on before version < 1.0.5
  //esp_wifi_set_mac(ESP_IF_WIFI_STA, &newMACAddress[0]);
  
  // ESP32 Board add-on after version > 1.0.5
  esp_wifi_set_mac(WIFI_IF_STA, &newMACAddress[0]);
  
  Serial.print("[NEW] ESP32 Board MAC Address:  ");
  Serial.println(WiFi.macAddress());
}
 
void loop(){

}

上传代码后,以 115200 的波特率打开串口监视器。重新启动 ESP32,你应该得到它的旧 MAC 地址和新 MAC 地址。

在这里插入图片描述

实验:ESP-NOW 单向/点对点通信

构建一个简单的项目,展示如何将消息从一个 ESP32 发送到另一个。

  • sender :一个 ESP32 将成为“发送端”;

  • receiver: 另一个 ESP32 将成为“接收端”。

在这里插入图片描述

发送一个结构,其中包含类型为char、int、float和boolean的变量。然后,您可以修改结构以发送适合您的项目的任何变量类型(例如传感器读数,或用于打开或关闭某些东西的布尔变量)。

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

发送端 程序中包含的内容:

  • 初始化 ESP-NOW;
  • 发送数据时注册一个回调函数——数据发送发送消息时将执行函数。这可以告诉我们消息是否成功传递;
  • 添加对等设备(接收器)。为此,您需要知道接收方的 MAC 地址;
  • 向对等设备发送消息。

接收端 程序中包括:

  • 初始化 ESP-NOW;
  • 注册接收回调函数(数据接收). 这是一个将在收到消息时执行的函数。
  • 在该回调函数中,将消息保存到变量中以使用该信息执行任何任务。

ESP-NOW 与设备接收消息或发送消息时调用的回调函数一起使用(您会收到消息是成功传递还是失败)。

ESP-NOW 函数功能

函数名称描述
esp_now_init()初始化 ESP-NOW。在初始化 ESP-NOW 之前,您必须先初始化 Wi-Fi。
esp_now_add_peer()调用此函数以配对设备并将peer MAC 地址作为参数传递。
esp_now_send()使用 ESP-NOW 发送数据
esp_now_register_send_cb()注册发送数据时触发的回调函数。发送消息时,将调用一个函数——此函数返回传递是否成功。
esp_now_register_rcv_cb()注册接收数据时触发的回调函数。当通过 ESP-NOW 接收到数据时,将调用一个函数。

有关这些功能的更多信息,请阅读ESP-IDF 编程指南中的 ESP-NOW 文档

ESP32 发送器

// Sender发送端
#include <esp_now.h>
#include <WiFi.h>

//  ESP32 接收器 MAC 地址
uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; //将该变量替换为您自己的 MAC 地址。

// 创建一个包含我们要发送的数据类型的结构体
typedef struct struct_message {
  char a[32];
  int b;
  float c;
  bool d;
} struct_message;

// 创建struct_message结构体类型的变量存储数据
struct_message myData;
// 创建esp_now_peer_info_t类型变量存储有关peer方的信息。
esp_now_peer_info_t peerInfo;

// 数据发送回调函数-此函数仅打印消息是否成功发送
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() {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA); // 设置为WiFi站点

  // 初始化 ESP-NOW
  if (esp_now_init() != ESP_OK) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }

  // 注册发送消息时调用的回调函数 OnDataSent
  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);
}

ESP32 接收器

// Receiver接收端

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

// 创建一个结构体接收数据
typedef struct struct_message {
    char a[32];
    int b;
    float c;
    bool d;
} struct_message;

// 
struct_message myData;

// 创建一个回调函数,当 ESP32 通过 ESP-NOW 接收到数据时将被调用
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("Bool: ");
  Serial.println(myData.d);
  Serial.println();
}
 
void setup() {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);// 将设备设置为 Wi-Fi Station

  // 初始化 ESP-NOW
  if (esp_now_init() != ESP_OK) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }
  
  // 注册在接收到数据时调用的回调函数 OnDataRecv
  esp_now_register_recv_cb(OnDataRecv);
}
 
void loop() {

}

还有更多与 ESP-NOW 相关的功能可以使用。

例如:管理peers、删除peers、扫描从属设备等……在 Arduino IDE 中转到文件>示例> ESP32 > ESPNow 并选择其中一个示例查看完整示例。


参考资料

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Naiva

你的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值