ESP-NOW介绍
ESP-NOW 是 Espressif Systems 针对其 ESP8266 和 ESP32 芯片开发的一种低功耗无线通信协议。它允许设备之间进行直接的点对点通信,而不需要中间的路由器或接入点。这种协议使用 Wi-Fi 控制帧进行数据传输,具有非常低的延迟和功耗,非常适合需要快速响应和低能耗的应用。
具体来讲ESP-NOW有下列优点:
低功耗:ESP-NOW 的设计初衷之一是低功耗。它通过使用 Wi-Fi 的控制帧进行通信,显著降低了能耗。
低延迟:ESP-NOW 的通信延迟很低,通常在几毫秒内。这使得它非常适合实时性要求高的应用,例如传感器数据采集和远程控制。
点对点通信:设备之间可以直接通信,无需依赖中间的路由器或接入点。这简化了网络架构,提高了通信效率和可靠性。
** 多对多通信**:ESP-NOW 允许一个设备同时与多个设备通信,支持最多 20 个对等设备。这使得它非常适合构建复杂的传感器网络或智能家居系统。
加密支持:ESP-NOW 支持加密通信,可以确保数据传输的安全性,防止数据被截获或篡改。
同时esp32也会有一些缺点,使用时请大家根据实际情况,选择合适的通信方式。
通信距离有限:由于使用的是 Wi-Fi 控制帧,通信距离可能比传统 Wi-Fi 要短。
带宽有限:适用于小数据量的传输,不适合大数据量的高速传输。
网络稳定性:在某些情况下,网络环境的干扰可能会影响通信的稳定性。
代码介绍
这里我将在VsCode中使用platformio来为大家讲解ESP-NOW通信具体如何通过代码来实现
首先,我们需要两个esp32单片机,一个作为接收端,另一个作为发射端。然后,我们需要知道接收端的Mac地址,才能够知道发送端的信息应该发送给谁。我以使接收端的板载LED闪烁为例为大家讲解esp-now通信。
获取Mac地址
#include <Arduino.h>
#include <esp_now.h>
#include <WiFi.h>
void setup() {
Serial.begin(115200);//初始化串口
String macAddress = WiFi.macAddress();//获取mac地址
Serial.print(macAddress);//通过串口打印mac信息
}
void loop() {
}
点击上传代码,打开串口监视器即可以得到esp32的mac地址,如果串口没有输出的话,可以按一下单片机上的复位按键,重新运行程序。
如图所示,这是我的单片机的mac地址,实际使用时需要在前面加上0x,表示16进制。
发送端代码详解
下面我将逐段逐句为大家讲解代码:
引入头文件:
#include <Arduino.h>
#include <esp_now.h>
#include <WiFi.h>
创建一个结构体变量,配置peer信息:
这里的peer我们可以简单理解为通信的设备
// 创建一个结构体变量,用于配置 peer 信息
esp_now_peer_info_t peerInfo;
// 定义发送数据类型结构体
typedef struct struct_message {
int LED; // LED 状态:1 表示点亮,0 表示熄灭
} struct_message;
// 创建一个结构体变量,用于存储发送的数据
struct_message myData;
定义接收设备的mac地址:
// 定义接收设备的 MAC 地址
uint8_t peerMac[] = {0xD0, 0xEF, 0x76, 0xEF, 0xCF, 0xAC};
初始化代码:
在setup函数里对espnow以及串口通信进行初始化。
void setup() {
Serial.begin(115200); // 初始化串口通信
WiFi.mode(WIFI_STA); // 设置 WiFi 模式为 STA 模式
// 初始化 ESP-NOW
if (esp_now_init() != ESP_OK) {
Serial.println("Error initializing ESP-NOW");
return;
}
// 设置对等设备信息
memcpy(peerInfo.peer_addr, peerMac, 6); // 将接收设备的 MAC 地址复制到 peerInfo 中
peerInfo.ifidx = WIFI_IF_STA; // 设置 WiFi 接口为 STA 模式
peerInfo.channel = 0; // 设置通道为 0(默认通道)
peerInfo.encrypt = false; // 不加密
// 添加对等设备到 ESP-NOW
if (esp_now_add_peer(&peerInfo) != ESP_OK) {
Serial.println("Failed to add peer");
return;
}
myData.LED = 0; // 初始 LED 状态为点亮
}
循环发送数据包并且转换LED灯的状态:
在loop函数中我们发送数据包,并且通过返回值检测发送是否成功,再将LED灯的状态取反保证其在0和1之间切换。
void loop() {
// 发送数据包
esp_err_t result = esp_now_send(peerMac, (uint8_t*)&myData, sizeof(myData));
// 打印发送结果
if (result == ESP_OK) {
Serial.println("Send success");
} else {
Serial.println("Send fail");
}
delay(1000); // 每 1 秒发送一次
// 取反 LED 状态,确保在 0 和 1 之间切换
myData.LED = ~myData.LED & 0x01;
delay(1000); // 每 2 秒发送一次
}
发送端完整代码:
#include <Arduino.h>
#include <esp_now.h>
#include <WiFi.h>
// 创建一个结构体变量,用于配置 peer 信息
esp_now_peer_info_t peerInfo;
// 定义发送数据类型结构体
typedef struct struct_message {
int LED; // LED 状态:1 表示点亮,0 表示熄灭
} struct_message;
// 创建一个结构体变量,用于存储发送的数据
struct_message myData;
// 定义接收设备的 MAC 地址
uint8_t peerMac[] = {0xD0, 0xEF, 0x76, 0xEF, 0xCF, 0xAC};
void setup() {
Serial.begin(115200); // 初始化串口通信
WiFi.mode(WIFI_STA); // 设置 WiFi 模式为 STA 模式
// 初始化 ESP-NOW
if (esp_now_init() != ESP_OK) {
Serial.println("Error initializing ESP-NOW");
return;
}
// 设置对等设备信息
memcpy(peerInfo.peer_addr, peerMac, 6); // 将接收设备的 MAC 地址复制到 peerInfo 中
peerInfo.ifidx = WIFI_IF_STA; // 设置 WiFi 接口为 STA 模式
peerInfo.channel = 0; // 设置通道为 0(默认通道)
peerInfo.encrypt = false; // 不加密
// 添加对等设备到 ESP-NOW
if (esp_now_add_peer(&peerInfo) != ESP_OK) {
Serial.println("Failed to add peer");
return;
}
myData.LED = 0; // 初始 LED 状态为点亮
}
void loop() {
// 发送数据包
esp_err_t result = esp_now_send(peerMac, (uint8_t*)&myData, sizeof(myData));
// 打印发送结果
if (result == ESP_OK) {
Serial.println("Send success");
} else {
Serial.println("Send fail");
}
delay(1000); // 每 1 秒发送一次
// 取反 LED 状态,确保在 0 和 1 之间切换
myData.LED = ~myData.LED & 0x01;
delay(1000); // 每 2 秒发送一次
}
接收端代码详解
接收端的代码与发送端类似,我们需要定义结构体变量、配置peer信息、接收mac地址、初始化串口及espnow、接受数据包。所以这里我直接放上完整的接收端代码,我们需要注意的是接收端的代码必须有回调函数,然而发射端不一定需要,因为接收端每一次收到信息之后就会调用回调函数。
#include <Arduino.h>
#include <esp_now.h>
#include <WiFi.h>
// 定义一模一样的结构体来存储接收到的数据
typedef struct struct_message {
int LED; // LED 状态:1 表示点亮,0 表示熄灭
} struct_message;
// 创建一个一模一样的结构体变量来存储接收到的数据
struct_message myData;
// 回调函数,当接收到数据时调用
void OnDataRecv(const uint8_t* mac, const uint8_t* incomingData, int len) {
// 将接收到的数据复制到 myData 结构体变量中
memcpy(&myData, incomingData, sizeof(myData));
// 打印接收到的数据长度和LED状态
Serial.print("Bytes received: ");
Serial.println(len);
Serial.print("LED state: ");
Serial.println(myData.LED);
// 根据接收到的数据控制 LED 的亮灭
if (myData.LED == 1) {
digitalWrite(2, HIGH); // 点亮 LED
} else {
digitalWrite(2, LOW); // 熄灭 LED
}
}
void setup() {
Serial.begin(115200); // 初始化串口通信
// 设置板载 LED 引脚为输出模式
pinMode(2, OUTPUT);
// 初始化 WiFi 模块,进入 STA 模式
WiFi.mode(WIFI_STA);
// 初始化 ESP-NOW,并检查是否成功
if (esp_now_init() != ESP_OK) {
Serial.println("Error initializing ESP-NOW");
return;
}
// 注册接收数据的回调函数 当esp32接收到了数据之后会再次调用回调函数以刷新数据
esp_now_register_recv_cb(OnDataRecv);
Serial.println("ESP-NOW Initialized");
}
void loop() {
// 空的主循环逻辑
}
实验现象
通过ESP-NOW实现单片机间的通信
总结
通过LED闪烁这一个简单的实验,我们学习了espnow通信,为我们日后的物联网开发学习打下来坚实的基础,如果有不懂的地方可以私信。
版权归原作者 HHYXL 所有, 如有侵权,请联系我们删除。