使用 ESP-NOW 协议在 XIAO 系列板上运行
本文将向您介绍 ESP-NOW 协议,并教您如何使用 XIAO ESP32 系列通过该协议进行通信。过程非常简单。为了让大家能够利用 XIAO ESP32 系列使用 ESP-NOW 协议进行通信,我们准备了三种 XIAO ESP32 型号:C6、C3 和 S3,它们将互相通信,赶快开始这段旅程吧!
顺便提一下,如果您刚刚获取了这些开发板,请点击以下链接,它将教您如何开始使用:
什么是 ESP-NOW 协议?
官方定义:ESP-NOW 是由 Espressif 定义的一种无线通信协议,能够实现智能设备的直接、快速和低功耗控制,无需路由器。它可以与 Wi-Fi 和蓝牙低能耗(Bluetooth LE)共存,支持多种 SoC 系列,如 Lexin ESP8266、ESP32、ESP32-S 和 ESP32-C。ESP-NOW 广泛应用于智能家电、遥控器和传感器等领域。
以下是 ESP-NOW 的特点:
- 根据 MAC 地址连接方式,可以在没有网络的情况下快速配对,设备可以通过单对多、单对单、多对单和多对多等方式进行连接。
- ESP-NOW 是基于数据链路层的无线通信协议,简化了五层 OSI 上层协议为一层,不需要添加数据包头,也不需要逐层解包。它极大地缓解了网络拥塞时数据包丢失所造成的延迟,并且具有更高的响应速度。
与 Wi-Fi 和蓝牙相比:
- Wi-Fi:ESP-NOW 支持设备间的点对点通信,因此具有更低的功耗和更高的传输速度,同时也拥有更长的通信距离。
- 蓝牙:ESP-NOW 不需要配对过程,使用起来更简单、更方便,功耗更低,传输速度更高。
不过,ESP-NOW 更适用于需要快速、可靠、低功耗和点对点通信的应用场景,而蓝牙和 Wi-Fi 更适用于复杂的网络环境和设备较多的场景。
硬件准备
在本项目中,为了考虑到某些用户可能只拥有 XIAO ESP32S3、XIAO ESP32C3 或 XIAO ESP32C6,我们使用三种 XIAO ESP32 型号(XIAO ESP32S3、XIAO ESP32C3 和 XIAO ESP32C6)来相互通信。您只需要稍微修改代码,就可以使用上述任意两种或三种型号进行实际操作。接下来我们来看一下代码是如何实现的,让我们开始吧!
如果您还没有两块 XIAO ESP32 系列的开发板,下面是购买链接:
功能实现
首先,让我们了解一下代码的一般框架。这个实例使用了三块 XIAO ESP32 板,XIAO ESP32S3 作为发送端,XIAO ESP32C6 和 XIAO ESP32C3 作为接收端。当然,这只是本代码中的角色分配。接下来通过我的解释,如果你想修改、增加或删除接收端和发送端的角色,将会非常简单。让我们开始吧!
第 1 部分:XIAO ESP32S3 发送端代码
#include <Arduino.h>
#include "WiFi.h"
#include "esp_now.h"
#define ESPNOW_WIFI_CHANNEL 0
#define MAX_ESP_NOW_MAC_LEN 6
#define BAUD 115200
#define MAX_CHARACTERS_NUMBER 20
#define NO_PMK_KEY false
typedef uint8_t XIAO;
typedef int XIAO_status;
//您需要输入您的 XIAO ESP32 系列 MAC,无法直接复制!!!
static uint8_t Receiver_XIAOC3_MAC_Address[MAX_ESP_NOW_MAC_LEN] = {0x64, 0xe8, 0x33, 0x89, 0x80, 0xb8};
static uint8_t Receiver_XIAOC6_MAC_Address[MAX_ESP_NOW_MAC_LEN] = {0xf0, 0xf5, 0xbd, 0x1a, 0x97, 0x20};
esp_now_peer_info_t peerInfo;
esp_now_peer_info_t peerInfo1;
typedef struct receiver_meesage_types{
char Reveiver_device[MAX_CHARACTERS_NUMBER];
char Reveiver_Trag[MAX_CHARACTERS_NUMBER];
}receiver_meesage_types;
receiver_meesage_types XIAOC3_RECEIVER_INFORATION;
receiver_meesage_types XIAOC6_RECEIVER_INFORATION;
typedef struct message_types{
char device[MAX_CHARACTERS_NUMBER];
char Trag[MAX_CHARACTERS_NUMBER];
}message_types;
message_types Personal_XIAOC3_Information;
message_types Personal_XIAOC6_Information;
void espnow_init();
void espnow_deinit();
void SenderXIAOS3_MACAddress_Requir();
void SenderXIAOS3_Send_Data();
void SenderXIAOS3_Send_Data_cb(const XIAO *mac_addr,esp_now_send_status_t status);
void Association_ReceiverXIAOC3_peer();
void Association_ReceiverXIAOC6_peer();
void ReceiverXIAOC3_Recive_Data_cb(const esp_now_recv_info *info, const uint8_t *incomingData, int len);
void ReceiverXIAOC6_Recive_Data_cb(const esp_now_recv_info *info, const uint8_t *incomingData, int len);
void setup(){
Serial.begin(BAUD);
while(!Serial);
SenderXIAOS3_MACAddress_Requir();
SenderXIAOS3_MACAddress_Requir();
espnow_init();
esp_now_register_send_cb(SenderXIAOS3_Send_Data_cb);
Association_ReceiverXIAOC6_peer();
Association_ReceiverXIAOC3_peer();
esp_now_register_recv_cb(ReceiverXIAOC3_Recive_Data_cb);
esp_now_register_recv_cb(ReceiverXIAOC6_Recive_Data_cb);
}
void loop(){
SenderXIAOS3_Send_Data();
delay(100);
}
void SenderXIAOS3_Send_Data_cb(const XIAO *mac_addr,esp_now_send_status_t status){
char macStr[18];
Serial.print("Packet to: ");
snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x",
mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
Serial.println(macStr);
delay(500);
Serial.print(" send status:\t");
Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
Serial.println("");
}
void Association_ReceiverXIAOC3_peer(){
Serial.println("Attempting to associate peer for XIAOC3...");
peerInfo.channel = ESPNOW_WIFI_CHANNEL;
peerInfo.encrypt = NO_PMK_KEY;
memcpy(peerInfo.peer_addr, Receiver_XIAOC3_MAC_Address, 6);
esp_err_t addPressStatus = esp_now_add_peer(&peerInfo);
if (addPressStatus != ESP_OK)
{
Serial.print("Failed to add peer");
Serial.println(addPressStatus);
}else
{
Serial.println("Successful to add peer");
}
}
void Association_ReceiverXIAOC6_peer(){
Serial.println("Attempting to associate peer for XIAOC6...");
peerInfo1.channel = ESPNOW_WIFI_CHANNEL;
peerInfo1.encrypt = NO_PMK_KEY;
memcpy(peerInfo1.peer_addr, Receiver_XIAOC6_MAC_Address, 6);
esp_err_t addPressStatus = esp_now_add_peer(&peerInfo1);
if (addPressStatus != ESP_OK)
{
Serial.print("Failed to add peer");
Serial.println(addPressStatus);
}else
{
Serial.println("Successful to add peer");
}
}
void SenderXIAOS3_Send_Data(){
strcpy(Personal_XIAOC3_Information.device, "XIAOS3");
strcpy(Personal_XIAOC3_Information.Trag, "Hello,i'm sender");
strcpy(Personal_XIAOC6_Information.device, "XIAOS3");
strcpy(Personal_XIAOC6_Information.Trag, "Hello,i'm sender");
esp_err_t XIAOS3_RECEIVER_INFORATION_data1 = esp_now_send(Receiver_XIAOC3_MAC_Address, (uint8_t *)&Personal_XIAOC3_Information, sizeof(message_types));
esp_err_t XIAOS3_RECEIVER_INFORATION_data2 = esp_now_send(Receiver_XIAOC6_MAC_Address, (uint8_t *)&Personal_XIAOC6_Information, sizeof(message_types));
if (XIAOS3_RECEIVER_INFORATION_data1 == ESP_OK || XIAOS3_RECEIVER_INFORATION_data2 == ESP_OK)
{
Serial.println("Sent with success: XIAOS3_RECEIVER_INFORATION_data1 and XIAOS3_RECEIVER_INFORATION_data2");
}
delay(4000);
}
void ReceiverXIAOC3_Recive_Data_cb(const esp_now_recv_info *info, const uint8_t *incomingData, int len) {
memcpy(&XIAOC3_RECEIVER_INFORATION, incomingData, sizeof(XIAOC3_RECEIVER_INFORATION));
Serial.print("Bytes received: ");
Serial.println(len);
Serial.print("Reveiver_device: ");
Serial.println(XIAOC3_RECEIVER_INFORATION.Reveiver_device);
Serial.print("Reveiver_Trag: ");
Serial.println(XIAOC3_RECEIVER_INFORATION.Reveiver_Trag);
Serial.println();
}
void ReceiverXIAOC6_Recive_Data_cb(const esp_now_recv_info *info, const uint8_t *incomingData, int len) {
memcpy(&XIAOC6_RECEIVER_INFORATION, incomingData, sizeof(XIAOC6_RECEIVER_INFORATION));
Serial.print("Bytes received: ");
Serial.println(len);
Serial.print("Reveiver_device: ");
Serial.println(XIAOC6_RECEIVER_INFORATION.Reveiver_device);
Serial.print("Reveiver_Trag: ");
Serial.println(XIAOC6_RECEIVER_INFORATION.Reveiver_Trag);
Serial.println();
}
void SenderXIAOS3_MACAddress_Requir(){
WiFi.mode(WIFI_STA);
WiFi.setChannel(ESPNOW_WIFI_CHANNEL);
XIAO mac[MAX_ESP_NOW_MAC_LEN];
while(!WiFi.STA.started()){
Serial.print(".");
delay(100);
}
WiFi.macAddress(mac);
Serial.println();
Serial.printf("const uint8_t mac_self[6] = {0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x};", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
Serial.println();
}
void espnow_init(){
XIAO_status espnow_sign = esp_now_init();
if(espnow_sign == ESP_OK)
{
Serial.println("the esp now is successful init!");
}else
{
Serial.println("the esp now is failed init");
}
}
void espnow_deinit(){
XIAO_status espnow_sign = esp_now_deinit();
if(espnow_sign == ESP_OK){
Serial.println("the esp now is successful deinit!");
}else
{
Serial.println("the esp now is failed deinit!");
}
}
第 1 部分 解决方案代码
包含库:
#include "WiFi.h"
#include "esp_now.h"
核心函数:
espnow_init()
- 角色:初始化 ESP-NOW 功能
- 返回值:初始化成功:[ESP_OK];失败:[ESP_FAIL]
espnow_deinit()
- 角色:反初始化 ESP-NOW 功能,所有与配对设备相关的信息将被删除
- 返回值:初始化成功:[ESP_OK]
SenderXIAOS3_MACAddress_Requir()
- 角色:将 Wi-Fi 模式设置为 STA,并获取 MAC 地址以便打印在串口上
SenderXIAOS3_Send_Data()
- 角色:发送特定的消息
SenderXIAOS3_Send_Data_cb()
- 角色:这是一个回调函数,当它执行时,会打印消息是否成功发送以及发送到哪个 MAC 地址
Association_ReceiverXIAOC3_peer()
和Association_ReceiverXIAOC6_peer
- 角色:添加对等节点,如果需要更多接收器,可以创建节点,并编写与发送端和接收端匹配的消息
esp_now_register_send_cb()
- 角色:注册回调函数,以验证数据是否已经发送到 MAC 层
- 返回值:MAC 层成功接收到数据:[ESP_NOW_SEND_SUCCESS],否则:[ESP_NOW_SEND_FAIL]
ReceiverXIAOC3_Recive_Data_cb()
- 角色:接受来自发送端的数据的回调函数
ReceiverXIAOC6_Recive_Data_cb()
- 角色:接受来自发送端的数据的回调函数
esp_now_register_recv_cb()
- 角色:注册回调函数,以验证数据是否已经发送到 MAC 层
- 返回值:MAC 层成功接收到数据:[ESP_NOW_SEND_SUCCESS],否则:[ESP_NOW_SEND_FAIL]
默认变量:
#define ESPNOW_WIFI_CHANNE
- 角色:发送端和接收端所在的 Wi-Fi 通道
#define MAX_ESP_NOW_MAC_LEN
- 角色:MAC 地址长度
#define MAX_CHARACTERS_NUMBER
- 角色:接收或发送的最大字符数
#define BAUD 115200
- 角色:设置串口的波特率
static uint8_t Receiver_XIAOC3_MAC_Address[MAX_ESP_NOW_MAC_LEN]
和static uint8_t Receiver_XIAOC6_MAC_Address
- 角色:存储我的 XIAO ESP32C3 和 XIAO ESP32C6 的 MAC 地址,它们作为接收端。
- 补充:请注意,这些是我的 MAC 地址,不能写入其他地址。
NO_PMK_KEY
- 角色:选择不加密的配对方式
第 2 部分 XIAO ESP32C3 接收端代码
#include<Arduino.h>
#include "WiFi.h"
#include "esp_now.h"
#define ESPNOW_WIFI_CHANNEL 0
#define MAX_ESP_NOW_MAC_LEN 6
#define BAUD 115200
#define MAX_CHARACTERS_NUMBER 20
#define NO_PMK_KEY false
typedef uint8_t XIAO;
typedef int status;
//您需要输入您的 XIAO ESP32 系列 MAC,无法直接复制!!!
static uint8_t XIAOS3_Sender_MAC_Address[MAX_ESP_NOW_MAC_LEN] = {0xcc, 0x8d, 0xa2, 0x0c, 0x57, 0x5c};
esp_now_peer_info_t peerInfo_sender;
typedef struct receiver_meesage_types{
char Reveiver_device[MAX_CHARACTERS_NUMBER];
char Reveiver_Trag[MAX_CHARACTERS_NUMBER];
}receiver_meesage_types;
receiver_meesage_types XIAOC3_RECEIVER_INFORATION;
typedef struct message_types{
char Sender_device[MAX_CHARACTERS_NUMBER];
char Sender_Trag[MAX_CHARACTERS_NUMBER];
}message_types;
message_types XIAOS3_SENDER_INFORATION;
void Receiver_MACAddress_requir();
void espnow_init();
void espnow_deinit();
void ReceiverXIAOC3_Recive_Data_cb(const uint8_t * mac, const uint8_t *incomingData, int len);
void ReceiverXIAOC3_Send_Data();
void ReceiverXIAOC3_Send_Data_cb(const XIAO *mac_addr,esp_now_send_status_t status);
void Association_SenderXIAOS3_peer();
void setup() {
Serial.begin(BAUD);
while(!Serial);
Receiver_MACAddress_requir();
espnow_init();
esp_now_register_recv_cb(ReceiverXIAOC3_Recive_Data_cb);
esp_now_register_send_cb(ReceiverXIAOC3_Send_Data_cb);
Association_SenderXIAOS3_peer();
}
void loop() {
ReceiverXIAOC3_Send_Data();
delay(1000);
}
void espnow_init(){
status espnow_sign = esp_now_init();
if(espnow_sign == ESP_OK)
{
Serial.println("the esp now is successful init!");
}else
{
Serial.println("the esp now is failed init");
}
}
void espnow_deinit(){
status espnow_sign = esp_now_deinit();
if(espnow_sign == ESP_OK){
Serial.println("the esp now is successful deinit!");
}else
{
Serial.println("the esp now is failed deinit!");
}
}
void Receiver_MACAddress_requir(){
WiFi.mode(WIFI_STA);
WiFi.setChannel(ESPNOW_WIFI_CHANNEL);
XIAO mac[MAX_ESP_NOW_MAC_LEN];
while(!WiFi.STA.started()){
Serial.print(".");
delay(100);
}
WiFi.macAddress(mac);
Serial.println();
Serial.printf("const uint8_t mac_self[6] = {0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x};", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
Serial.println();
}
void ReceiverXIAOC3_Recive_Data_cb(const esp_now_recv_info *info, const uint8_t *incomingData, int len) {
memcpy(&XIAOS3_SENDER_INFORATION, incomingData, sizeof(XIAOS3_SENDER_INFORATION));
Serial.print("Bytes received: ");
Serial.println(len);
Serial.print("Sender_device: ");
Serial.println(XIAOS3_SENDER_INFORATION.Sender_device);
Serial.print("Sender_Trag: ");
Serial.println(XIAOS3_SENDER_INFORATION.Sender_Trag);
Serial.println();
}
void ReceiverXIAOC3_Send_Data_cb(const XIAO *mac_addr,esp_now_send_status_t status){
char macStr[18];
Serial.print("Packet to: ");
snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x",
mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
Serial.println(macStr);
delay(500);
Serial.print(" send status:\t");
Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
Serial.println("");
}
void ReceiverXIAOC3_Send_Data(){
strcpy(XIAOC3_RECEIVER_INFORATION.Reveiver_device, "XIAOC3");
strcpy(XIAOC3_RECEIVER_INFORATION.Reveiver_Trag, "I'm get it");
esp_err_t XIAOC3_RECEIVER_INFORATION_data1 = esp_now_send(XIAOS3_Sender_MAC_Address, (uint8_t *)&XIAOC3_RECEIVER_INFORATION, sizeof(receiver_meesage_types));
if (XIAOC3_RECEIVER_INFORATION_data1 == ESP_OK)
{
Serial.println("Sent with success: XIAOC3_RECEIVER_INFORATION_data1");
}
delay(4000);
}
void Association_SenderXIAOS3_peer(){
Serial.println("Attempting to associate peer for XIAOC6...");
peerInfo_sender.channel = ESPNOW_WIFI_CHANNEL;
peerInfo_sender.encrypt = NO_PMK_KEY;
memcpy(peerInfo_sender.peer_addr, XIAOS3_Sender_MAC_Address, 6);
esp_err_t addPressStatus = esp_now_add_peer(&peerInfo_sender);
if (addPressStatus != ESP_OK)
{
Serial.print("Failed to add peer");
Serial.println(addPressStatus);
}else
{
Serial.println("Successful to add peer");
}
}
第 2 部分 解决方案代码
包含库:
#include "WiFi.h"
#include "esp_now.h"
核心函数:
espnow_init()
- 角色:初始化 ESP-NOW 功能
- 返回值:初始化成功:[ESP_OK];失败:[ESP_FAIL]
espnow_deinit()
- 角色:反初始化 ESP-NOW 功能,所有与配对设备相关的信息将被删除
- 返回值:初始化成功:[ESP_OK]
Receiver_MACAddress_requir()
- 角色:将 Wi-Fi 模式设置为 STA,并获取 MAC 地址以便打印在串口上
ReceiverXIAOC3_Send_Data()
- 角色:发送特定的消息
ReceiverXIAOC3_Recive_Data_cb()
- 角色:这是一个回调函数,当它执行时,会打印消息是否成功发送以及发送到哪个 MAC 地址
Association_SenderXIAOS3_peer()
- 角色:为 XIAO ESP32S3 添加一个通道节点,以便向其发送消息
esp_now_register_send_cb()
- 角色:注册回调函数,以验证数据是否已经发送到 MAC 层
- 返回值:MAC 层成功接收到数据:[ESP_NOW_SEND_SUCCESS],否则:[ESP_NOW_SEND_FAIL]
ReceiverXIAOC3_Send_Data_cb()
- 角色:这是一个回调函数,当它执行时,会打印消息是否成功发送以及发送到哪个 MAC 地址
esp_now_register_recv_cb()
- 角色:注册回调函数,以验证数据是否已经发送到 MAC 层
- 返回值:MAC 层成功接收到数据:[ESP_NOW_SEND_SUCCESS],否则:[ESP_NOW_SEND_FAIL]
默认变量:
#define ESPNOW_WIFI_CHANNE
- 角色:发送端和接收端所在的 Wi-Fi 通道
#define MAX_ESP_NOW_MAC_LEN
- 角色:MAC 地址长度
#define MAX_CHARACTERS_NUMBER
- 角色:接收或发送的最大字符数
#define BAUD 115200
- 角色:设置串口的波特率
static uint8_t XIAOS3_Sender_MAC_Address[MAX_ESP_NOW_MAC_LEN]
- 角色:存储我的 XIAO ESP32S3 的 MAC 地址
- 补充:请注意,这些是我的 MAC 地址,不能写入其他地址!
NO_PMK_KEY
- 角色:选择不加密的配对方式
第 3 部分 XIAO ESP32C6 接收端代码
#include<Arduino.h>
#include "WiFi.h"
#include "esp_now.h"
#define ESPNOW_WIFI_CHANNEL 0
#define MAX_ESP_NOW_MAC_LEN 6
#define BAUD 115200
#define MAX_CHARACTERS_NUMBER 20
#define NO_PMK_KEY false
typedef uint8_t XIAO;
typedef int status;
//您需要输入您的 XIAO ESP32 系列 MAC,无法直接复制!!!
static uint8_t XIAOS3_Sender_MAC_Address[MAX_ESP_NOW_MAC_LEN] = {0xcc, 0x8d, 0xa2, 0x0c, 0x57, 0x5c};
esp_now_peer_info_t peerInfo_sender;
typedef struct receiver_meesage_types{
char Reveiver_device[MAX_CHARACTERS_NUMBER];
char Reveiver_Trag[MAX_CHARACTERS_NUMBER];
}receiver_meesage_types;
receiver_meesage_types XIAOC6_RECEIVER_INFORATION;
typedef struct message_types{
char Sender_device[MAX_CHARACTERS_NUMBER];
char Sender_Trag[MAX_CHARACTERS_NUMBER];
}message_types;
message_types XIAOS3_SENDER_INFORATION;
void Receiver_MACAddress_requir();
void espnow_init();
void espnow_deinit();
void ReceiverXIAOC6_Recive_Data_cb(const uint8_t * mac, const uint8_t *incomingData, int len);
void ReceiverXIAOC6_Send_Data();
void ReceiverXIAOC6_Send_Data_cb(const XIAO *mac_addr,esp_now_send_status_t status);
void Association_SenderXIAOS3_peer();
void setup() {
Serial.begin(BAUD);
while(!Serial);
Receiver_MACAddress_requir();
espnow_init();
esp_now_register_recv_cb(ReceiverXIAOC6_Recive_Data_cb);
esp_now_register_send_cb(ReceiverXIAOC6_Send_Data_cb);
Association_SenderXIAOS3_peer();
}
void loop() {
ReceiverXIAOC6_Send_Data();
delay(1000);
}
void espnow_init(){
status espnow_sign = esp_now_init();
if(espnow_sign == ESP_OK)
{
Serial.println("the esp now is successful init!");
}else
{
Serial.println("the esp now is failed init");
}
}
void espnow_deinit(){
status espnow_sign = esp_now_deinit();
if(espnow_sign == ESP_OK){
Serial.println("the esp now is successful deinit!");
}else
{
Serial.println("the esp now is failed deinit!");
}
}
void Receiver_MACAddress_requir(){
WiFi.mode(WIFI_STA);
WiFi.setChannel(ESPNOW_WIFI_CHANNEL);
XIAO mac[MAX_ESP_NOW_MAC_LEN];
while(!WiFi.STA.started()){
Serial.print(".");
delay(100);
}
WiFi.macAddress(mac);
Serial.println();
Serial.printf("const uint8_t mac_self[6] = {0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x};", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
Serial.println();
}
void ReceiverXIAOC6_Recive_Data_cb(const esp_now_recv_info *info, const uint8_t *incomingData, int len) {
memcpy(&XIAOS3_SENDER_INFORATION, incomingData, sizeof(XIAOS3_SENDER_INFORATION));
Serial.print("Bytes received: ");
Serial.println(len);
Serial.print("Sender_device: ");
Serial.println(XIAOS3_SENDER_INFORATION.Sender_device);
Serial.print("Sender_Trag: ");
Serial.println(XIAOS3_SENDER_INFORATION.Sender_Trag);
Serial.println();
}
void ReceiverXIAOC6_Send_Data_cb(const XIAO *mac_addr,esp_now_send_status_t status){
char macStr[18];
Serial.print("Packet to: ");
snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x",
mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
Serial.println(macStr);
delay(500);
Serial.print(" send status:\t");
Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
Serial.println("");
}
void ReceiverXIAOC6_Send_Data(){
strcpy(XIAOC6_RECEIVER_INFORATION.Reveiver_device, "XIAOC6");
strcpy(XIAOC6_RECEIVER_INFORATION.Reveiver_Trag, "I'm get it");
esp_err_t XIAOC6_RECEIVER_INFORATION_data1 = esp_now_send(XIAOS3_Sender_MAC_Address, (uint8_t *)&XIAOC6_RECEIVER_INFORATION, sizeof(receiver_meesage_types));
if (XIAOC6_RECEIVER_INFORATION_data1 == ESP_OK)
{
Serial.println("Sent with success: XIAOC6_RECEIVER_INFORATION_data1");
}
delay(4000);
}
void Association_SenderXIAOS3_peer(){
Serial.println("Attempting to associate peer for XIAOC6...");
peerInfo_sender.channel = ESPNOW_WIFI_CHANNEL;
peerInfo_sender.encrypt = NO_PMK_KEY;
memcpy(peerInfo_sender.peer_addr, XIAOS3_Sender_MAC_Address, 6);
esp_err_t addPressStatus = esp_now_add_peer(&peerInfo_sender);
if (addPressStatus != ESP_OK)
{
Serial.print("Failed to add peer");
Serial.println(addPressStatus);
}else
{
Serial.println("Successful to add peer");
}
}
第 3 部分 解决方案代码
包含库:
#include "WiFi.h"
#include "esp_now.h"
核心函数:
espnow_init()
- 角色:初始化 ESP-NOW 功能
- 返回值:初始化成功:[ESP_OK];失败:[ESP_FAIL]
espnow_deinit()
- 角色:反初始化 ESP-NOW 功能,所有与配对设备相关的信息将被删除
- 返回值:初始化成功:[ESP_OK]
Receiver_MACAddress_requir()
- 角色:将 Wi-Fi 模式设置为 STA,并获取 MAC 地址以便打印在串口上
ReceiverXIAOC6_Send_Data()
- 角色:发送特定的消息
ReceiverXIAOC6_Recive_Data_cb()
- 角色:这是一个回调函数,当它执行时,会打印消息是否成功发送以及发送到哪个 MAC 地址
Association_SenderXIAOS3_peer()
- 角色:为 XIAO ESP32S3 添加一个通道节点,以便向其发送消息
ReceiverXIAOC6_Send_Data_cb()
- 角色:这是一个回调函数,当它执行时,会打印消息是否成功发送以及发送到哪个 MAC 地址
esp_now_register_send_cb()
- 角色:注册回调函数,以验证数据是否已经发送到 MAC 层
- 返回值:MAC 层成功接收到数据:[ESP_NOW_SEND_SUCCESS],否则:[ESP_NOW_SEND_FAIL]
esp_now_register_recv_cb()
- 角色:注册回调函数,以验证数据是否已经发送到 MAC 层
- 返回值:MAC 层成功接收到数据:[ESP_NOW_SEND_SUCCESS],否则:[ESP_NOW_SEND_FAIL]
NO_PMK_KEY
- 角色:选择不加密的配对方式
默认变量:
#define ESPNOW_WIFI_CHANNE
- 角色:发送端和接收端所在的 Wi-Fi 通道
#define MAX_ESP_NOW_MAC_LEN
- 角色:接收端 MAC 地址的长度
#define MAX_CHARACTERS_NUMBER
- 角色:接收或发送的最大字符数
#define BAUD 115200
- 角色:设置串口的波特率
static uint8_t XIAOS3_Sender_MAC_Address[MAX_ESP_NOW_MAC_LEN]
- 角色:存储我的 XIAO ESP32S3 的 MAC 地址
- 补充:请注意,这些是我的 MAC 地址,不能写入其他地址!
NO_PMK_KEY
- 角色:选择不加密的配对方式
演示效果
以下是使用 ESPNOW 协议进行 XIAO ESP32 通信的结果:
发送端 XIAO ESP32S3 结果
接收端 XIAO ESP32C3 结果
接收端 XIAO ESP32C6 结果
ESPNOW 总结
低功耗:
- 适用于电池供电的设备,可以在不连接 Wi-Fi 的情况下进行通信。
快速连接:
- 设备可以快速建立连接,无需复杂的配对过程。
多对多通信:
- 支持多设备之间的通信,允许一个设备向多个设备发送数据。
安全性:
- 支持加密功能,确保数据传输的安全。
短距离通信:
- 通常用于短距离(几十米)的无线通信。
故障排除
问题 1:无法连接,程序没有报告任何错误
- 检查您的 XIAO ESP32 的 MAC 地址是否正确
- 确认您的 XIAO ESP32 所连接的 Wi-Fi 通道是否一致
- 重置您的 XIAO ESP32,并重新打开串口监视器
问题 2:接收到消息,但不完整
- 在检测发送端和接收端时,可能存在结构体成员相似的问题
资源
- [Espressif 官方文档] ESPRESSIF ESP-IDF ESP-NOW
技术支持与产品讨论
感谢您选择我们的产品!我们在这里为您提供不同的支持,确保您使用我们的产品时获得最佳体验。我们提供多种沟通渠道,以满足不同的需求和偏好。