ESP32 NOW 通信介绍和一对一单向通信应用实例(一发一收)
目录
ESP-NOW 是乐鑫开发的一种无连接通信协议,沒有握手协议(CHAP),具有短包传输的特点。该协议使多个设备能够在不使用Wi-Fi的情况下以简单的方式进行相互通讯,类似于低功耗 2.4GHz 无线连接,设备之间的配对是在它们通信之前就需要配对好在代码中。配对完成后,连接是安全的,持久的,点对点的。换句话说,如果你的一块ESP32板突然断电或重置,当它重新启动时,它就会自动连接到它的已经提前配对好的网路中以继续通信。
凌顺实验室(lingshunlab.com)介绍该通信协议(ESPNOW)特点及应注意之处,并演示ONE-WAY模式的ESPNOW通信代码。
ESP-NOW 协议功的能或特性
- 加密和未加密的单播通信;
- 混合加密和未加密对等设备;
- 最多可承载250 字节的有效载荷;
- 发送回调函数,可设置通知应用层传输成功或失败。
ESP-NOW 协议的限制
-
在有限的加密对等点:
- Station模式最多支持10个设备的加密对等点网络通讯;
- SoftAP或SoftAP+Station模式下最多支持6个设备;
-
多个未加密对等点:
- 其总数应少于 20 个设备
- 有效载荷限制为 250 字节。
凌顺实验室(lingshunlab.com)通过试验2个ESP32开发板在空旷区域中进行单向通讯,相隔30米仍然能很好低接收信息。
在开发过程中,注意以上特性,就能避免踩坑。
准备
2块 ESP32开发板
一块用于接受信号;
一块用于发送信号。
单向通信(one-way)示意图
一块ESP32作为发送端 ,发送信号给另一块作为接收端的ESP32
实验效果
在串口中各自输出2块ESP32的数据,如下图:
ESPNOW 发送端代码关键
1,加载需要的库
#include <esp_now.h>
#include <WiFi.h>
2,需要要知道接收数据的ESP32的MAC地址
// 定义接收端的mac地址,这里的地址请替换成接收端ESP32的MAC地址
uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
获取ESP32 MAC地址的方法请参考:
http://47.119.142.156/book/esp32/esp32-mac-address-get-and-set
3,需要定义与接收端一样的的数据结构体
// 发送数据的结构示例
// 在C中使用 typedef struct 定义一个结构体类型,名为struct_message
// 必须与接收方的结构相匹配一致
typedef struct struct_message {
char a[40];
int b;
float c;
bool d;
} struct_message;
4,初始化ESPNOW
// 设置设备WIFI模式为WIFI_STA
WiFi.mode(WIFI_STA);
esp_now_init();
5,配置并注册对等点(peer)
// 配置对等(对等点)网络
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;
}
6, 声明回调函数
// 当发送信息时,触发的回调函数
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");
}
// 当ESPNOW初始化成功,我们将会注册一个回调函数(callback,CB)
// 获得数据包的发送情况
esp_now_register_send_cb(OnDataSent);
发送端(slave/sender)完整代码
// Welcome to lingshunlab.com
// 完整说明 :http://47.119.142.156/book/esp32/esp32-now-introduce-and-one-way-communication
// 加载需要的库
#include <esp_now.h>
#include <WiFi.h>
// 定义接收端的mac地址,这里的地址请替换成接收端ESP32的MAC地址
uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
// 发送数据的结构示例
// 在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 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;
}
// 当ESPNOW初始化成功,我们将会注册一个回调函数(callback,CB)
// 获得数据包的发送情况
esp_now_register_send_cb(OnDataSent);
// 配置对等(对等点)网络
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(myData.a, "Welcome to Lingshunlab.com");
myData.b = random(1,20);
myData.c = 1.2;
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);
}
ESPNOW 接收端代码关键
接收端的代码相对发送端会简单一些,少了一些步骤,当然这只是在One-Way模式下的代码。
1,加载需要的库
#include <esp_now.h>
#include <WiFi.h>
2,需要定义与接收端一样的的数据结构体
// 发送数据的结构示例
// 在C中使用 typedef struct 定义一个结构体类型,名为struct_message
// 必须与接收方的结构相匹配一致
typedef struct struct_message {
char a[40];
int b;
float c;
bool d;
} struct_message;
3,初始化ESPNOW
// 设置设备WIFI模式为WIFI_STA
WiFi.mode(WIFI_STA);
esp_now_init();
4,声明回调函数
// 当ESPNOW初始化成功,我们将会注册一个回调函数(callback,CB)
// 获得回收的包装信息
esp_now_register_recv_cb(OnDataRecv);
接收端(master/receiver )完整代码
// Welcome to lingshunlab.com
// 完整说明 :http://47.119.142.156/book/esp32/esp32-now-introduce-and-one-way-communication
// 加载需要的库
#include <esp_now.h>
#include <WiFi.h>
// 接收数据的结构示例
// 在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;
// 当收到数据时将执行的回调函数
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;
}
// 当ESPNOW初始化成功,我们将会注册一个回调函数(callback,CB)
// 获得回收的包装信息
esp_now_register_recv_cb(OnDataRecv);
}
void loop() {
}