ESP32 使用NOW进行一对一双向通讯互发数据的例子

image-20240522154918851

实现效果

在之前的例程中,实现了ESP32NOW一对一的单向通讯,一个ESP32负责发送数据,一个ESP32负责接收数据。
https://lingshunlab.com/book/esp32/esp32-now-introduce-and-one-way-communication

现在,这个例程要实现ESP32NOW一对一的双向通讯,每个ESP32既要负责发送数据,又要负责接收数据。

注意!数据能够相互传送的条件是他们的数据结构必须是一样的,并且数据大小不能超过250字节。

确认MAC地址

首先,找到各自ESP32的MAC地址,可以使用以下链接的程序找到ESP32的MAC地址(或者在初始化NOW之前改变当前的ESP32的MAC地址,本文并不关注这一点)

ESP32/ESP8266 MAC地址的获取与设定

上传获取MAC地址的程序,查看串口输出,可以看到类似的信息,
例如,在我的ESP32上这就是MAC地址:E0:5A:1B:6B:49:9C

image-20240521105001159

用同样的方法获取其他ESP32的MAC地址,并且记录区分好每一块ESP32,经常搞错地址而导致通讯失败。

程序修改

双向通讯的程序其实非常简单,就是把在ESP32NOW一对一 单向通讯的发送和接受数据的2个程序,合并成一个程序,并且互相定义接受端的mac地址即可,例如:
ESP32-A的接收端MAC地址写ESP32-B的
ESP32-B的接收端MAC地址写ESP32-A的

完整代码

以下是已经合成完整的代码,

切记把broadcastAddress中的地址替换成你各自接收端的ESP32的MAC地址。

然后分别把程序上传到ESP32。

// Welcome to lingshunlab.com
// 完整说明 :https://lingshunlab.com/book/esp32/esp32-now-introduce-and-one-way-communication

// 加载需要的库 
#include <esp_now.h>
#include <WiFi.h>

// 定义接收端的mac地址,这里的地址请替换成你的接收端ESP32的MAC地址
uint8_t broadcastAddress[] = {0xC8, 0xF0, 0x9E, 0xF1, 0x35, 0xF0};

// 接收数据的结构示例
// 在C中使用 typedef struct 定义一个结构体类型,名为struct_message
// 必须与发送方的结构相匹配一致
typedef struct struct_message {
    char a[40];
    int b;
    float c;
    bool d;
} struct_message;

// 创建 结构为struct_message的myData变量
struct_message myData;

// 声明对等网络信息实体类变量
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 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模式为WIFI_STA
  WiFi.mode(WIFI_STA);

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

  // 配置对等(对等点)网络
  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;
  }

  // 当ESPNOW初始化成功,我们将会注册一个回调函数(callback,CB)
  // 获得数据包的发送情况
  esp_now_register_send_cb(OnDataSent);

  // 当ESPNOW初始化成功,我们将会注册一个回调函数(callback,CB)
  // 获得回收的包装信息
  esp_now_register_recv_cb(OnDataRecv);
}

void loop() {
    // 赋值需要发送的变量数据 
    // 可以设置不同的数值,在串口中查看数据,确认是否互相能通讯
  strcpy(myData.a, "Welcome to Lingshunlab.com via A or B");
  myData.b = random(1,20);
  myData.c = 11.11;
  myData.d = false;

  // 通过ESPNOW发送信息
  esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));

  // 根据 result 返回结果判断是否发送成功
  if (result == ESP_OK) {// 当 发送成功 时
    Serial.println("Sent with success");
  }
  else { // 当 发送失败 时
    Serial.println("Error sending the data");
  }
  delay(2000);
}

两个ESP32都连接电脑,配置好串口,即可看到两个ESP32在互发信息。

image-20240522153114928