avatar

松果工作室

欢迎光临

  • 首页
  • freeRTOS
  • ESP
  • 开发手册
  • 快速笔记
  • 个人收藏
  • 工具
Home ESPNOW
文章

ESPNOW

Posted 2023-11-12 Updated 2023-11- 12
By YCP
17~22 min read

帧格式

默认比特率为1Mbps
-----------------------------------------------------------------------
··MAC 报头··|··分类代码··|··组织标识符··|··随机值··|··供应商特定内容··|··FCS··
-----------------------------------------------------------------------
··24 字节······1 字节········3 字节······4 字节······7~255 字节······4···
-----------------------------------------------------------------------

  • 分类代码:分类代码:分类代码字段用于指示各个供应商的类别
  • 组织标识符:包含一个唯一的标识符,为乐鑫指定的MAC地址的前三个字节
  • 随机值:防止重放攻击
  • 供应商特定内容:供应商特定内容包含供应商特定字段,如下所示:

-----------------------------------------------------------------------
|···元素 ID···|···长度···|···组织标识符···|···类型···|···版本···|···正文···|
-----------------------------------------------------------------------
···1 字节········1 字节·······3 字节········1 字节·····1 字节·· ·0-250 字节
-----------------------------------------------------------------------

  • 元素 ID:元素 ID 字段可用于指示特定于供应商的元素。
  • 长度:长度是组织标识符、类型、版本和正文的总长度。
  • 组织标识符:组织标识符包含一个唯一标识符 (比如 0x18fe34),为乐鑫指定的 MAC 地址的前三个字节。
  • 类型:类型字段设置为 4,代表 ESP-NOW。
  • 版本:版本字段设置为 ESP-NOW 的版本。
  • 正文:正文包含 ESP-NOW 数据。

初始化和反初始化

esp_now_init()&&esp_now_deinit():ESP-NOW 数据必须在 Wi-Fi 启动后传输,因此建议在初始化 ESP-NOW 之前启动 Wi-Fi,并在反初始化 ESP-NOW 之后停止 Wi-Fi, 当调用 esp_now_deinit() 时,配对设备的所有信息都将被删除.

添加配对设备

  • 在将数据发送到其他设备之前,请先调用esp_now_add_peer()将其添加到配对设备列表中。配对设备的最大数量是 20。如果启用了加密,则必须设置 LMK。ESP-NOW 数据可以从 Station 或 Softap 接口发送。 确保在发送 ESP-NOW 数据之前已启用该接口。在发送广播数据之前必须添加具有广播 MAC 地址的设备。配对设备的信道范围是从 0 ~14。如果信道设置为 0,数据将在当前信道上发送。否则,必须使用本地设备所在的通道。

发送 ESP-NOW 数据

  • 调用esp_now_send()发送 ESP-NOW 数据,调用esp_now_register_send_cb注册发送回调函数。如果 MAC 层成功接收到数据,则该函数将返回ESP_NOW_SEND_SUCCESS事件。否则,它将返回ESP_NOW_SEND_FAIL。ESP-NOW 数据发送失败可能有几种原因,比如目标设备不存在、设备的信道不相同、动作帧在传输过程中丢失等。应用层并不一定可以总能接收到数据。如果需要,应用层可在接收 ESP-NOW 数据时发回一个应答 (ACK) 数据。如果接收 ACK 数据超时,则将重新传输 ESP-NOW 数据。可以为 ESP-NOW 数据设置序列号,从而删除重复的数据。
  • 如果有大量 ESP-NOW 数据要发送,则调用esp_now_send()一次性发送不大于 250 字节的数据。 请注意,两个 ESP-NOW 数据包的发送间隔太短可能导致回调函数返回混乱。因此,建议在等到上一次回调函数返回 ACK 后再发送下一个 ESP-NOW 数据。发送回调函数从高优先级的 Wi-Fi 任务中运行。因此,不要在回调函数中执行冗长的操作。相反,将必要的数据发布到队列,并交给优先级较低的任务处理。

接收 ESP-NOW 数据

  • 调用esp_now_register_recv_cb注册接收回调函数。当接收 ESP-NOW 数据时,需要调用接收回调函数。接收回调函数也在 Wi-Fi 任务任务中运行。因此,不要在回调函数中执行冗长的操作。 相反,将必要的数据发布到队列,并交给优先级较低的任务处理。

读取Mac地址

#include <WiFi.h>

void setup() {
  Serial.begin(9600);
  Serial.println();
#ifdef ESP8266
  Serial.print("ESP8266 Board MAC Address:  ");
  Serial.println(WiFi.macAddress());
#elif defined ESP32
  WiFi.mode(WIFI_MODE_STA);
  Serial.print("ESP32 Board MAC Address:  ");
  Serial.println(WiFi.macAddress());
#endif
}

void loop() {

}

ESPNOW发送

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

// 设置掌控板声音传感器与光线传感器引脚编号
const int soundPin = 36;
const int lightPin = 39;

// 设置数据结构体
typedef struct struct_message {
  String board_name;
  double light;
  double sound;
} struct_message;

struct_message myData;

// 接收设备的 MAC 地址
uint8_t broadcastAddress[] = {0x24, 0x6F, 0x28, 0x88, 0x62, 0x80};

// 数据发送回调函数
void OnDataSent(const uint8_t *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);
  Serial.print("Send status: ");
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
  Serial.println();
}

void setup() {
  Serial.begin(9600);

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

  // 设置发送数据回调函数
  esp_now_register_send_cb(OnDataSent);

  // 绑定数据接收端
  esp_now_peer_info_t peerInfo;
  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() {
  // 设置要发送的数据
  myData.board_name = "mPython_#1";
  myData.light = analogRead(lightPin);
  myData.sound = analogRead(soundPin);

  // 发送数据
  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(1000);
}

ESPNOW接收函数

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

// 设置数据结构体
typedef struct struct_message {
  String board_name;
  double light;
  double sound;
} struct_message;

struct_message myData;

// 数据接收回调函数
void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
  memcpy(&myData, incomingData, sizeof(myData));
  Serial.print("board_name: ");
  Serial.println(myData.board_name);
  Serial.print("light: ");
  Serial.println(myData.light);
  Serial.print("sound:");
  Serial.println(myData.sound);
  Serial.println();
}

void setup() {
  Serial.begin(9600);

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

  // 设置接收数据回调函数
  esp_now_register_recv_cb(OnDataRecv);
}

void loop() {

}
坑和笔记
ESP
License:  CC BY 4.0
Share

Further Reading

Dec 23, 2024

其他笔记

EC800K AT连接移远云 配置过程 # 配置产品信息(初次连接需配置) AT+QIOTCFG="productinfo","pxxxxt","cDVTxxxxxxxxWGVB" # 连接开发者中心 AT+QIOTREG=1 # 查询当前连接状态(+QIOTSTATE: 8为正常) AT+QI

Jun 21, 2024

环形滤波算法

#include <stdio.h> #include <stdlib.h> #define BUFFER_SIZE 10 // 缓冲区大小 #define THRESHOLD 180

Jun 17, 2024

STM32 ADC采集的三种方式

采样周期 单个采集模式 ADC_Settings: 程序使用 uint16_t ADC_Read(

OLDER

低功耗蓝牙BLE

NEWER

玩客云配置

Recently Updated

  • ESP32(八) 简单的webserver
  • ESP32(七) NVS
  • ESP32(四) STA & AP
  • 多级菜单
  • ESP32(五) ESP32 OTA

Trending Tags

WCH Linux Elec freeRTOS STM ESP Flutter Others SwiftUI

Contents

©2025 松果工作室. Some rights reserved.

Using the Halo theme Chirpy