这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 活动中心 » 有奖活动 » 三分钟快速上手ESP-NOW(ArduinoIDE环境)

共2条 1/1 1 跳转至

三分钟快速上手ESP-NOW(ArduinoIDE环境)

助工
2026-06-19 22:52:47     打赏

摘要:本文主要介绍ESP-NOW的相关功能,以及在Arduino IDE开发的环境下,如何快速上手使用EPS-NOW;


一、ESP-NOW

ESP-NOW是乐鑫定义的一种无线通信协议,能够在无路由器的情况下直接、快速、低功耗地控制智能设备;

能够与 Wi-Fi 和 Bluetooth LE 共存,广泛应用于智能家电、远程控制和传感器等领域;

1781880889243623.png

1、关于 ESP-NOW

相关介绍

ESP_IDF-API文档

Arduino_esp32-API文档

注意事项


ESP-NOW是乐鑫定义的一种无连接Wi-Fi通信协议,与传统的Wi-Fi协议不同;

ESP-NOW将OSI模型中的前5层简化为了一层,因此数据无需经过网络层、传输层、会话层、表示层和应用层进行传输,减少了网络拥塞下因数据丢包引起的延迟,实现了快速响应。

  • 复用了WiFi的射频天线、2.4G无线物理层,但完全抛弃了标准WiFi协议、TCP/IP网络栈,基于802.11物理层的轻量点对点通信协议

  • 目前支持:ESP8266、ESP32、ESP32-S 和 ESP32-C等多系列SoC;


1781877622580442.png


2、ESP-NOW 特性 / 应用

  • 快速响应:开机后,设备无需任何无线连接即可传输数据并控制其他配对设备,响应速度以毫秒为单位。

  • 良好的兼容性:当设备连接到路由器或在热点模式下工作,也可以通过ESP-NOW实现快速稳定的通信。即使路由器出现故障或网络不稳定,设备也可以通过ESP-NOW保持稳定连接。

  • 远距离通信:ESP-NOW支持远距离通信。适用于户外场景,即使有墙壁、地板阻隔,也能使设备保持稳定的连接。

  • 多跳控制:ESP-NOW可以实现设备的多跳控制。通过单播、广播和群控等方式,可以控制数百台设备。


配网

除了Wi-Fi配网和蓝牙配网外,ESP-NOW还提供了一种新的配网方法。

通过蓝牙为第一台设备配网,其他设备不需要配置SSID/密码信息,因为连接到网络的第一台设备可以直接将这些信息发送给其他设备。

用户可以在APP端选择是否允许其他设备访问网络。


升级

ESP-NOW可用于海量数据传输,如固件升级。

从断点处恢复升级:使用ESP-NOW升级固件时,固件会以固定大小分包,逐个写入flash,设备会记录升级后的包。如果升级过程发生中断,设备将仅请求剩余的固件包,并从断点处继续升级操作。

多设备升级:ESP-NOW可支持多台设备同时升级。3分钟内可升级50台设备。

回滚:如果发生升级错误,固件可以回滚到之前的版本。


调试

ESP-NOW可以用来接收设备运行时的日志,便于设备调试;

通过多对多连接,发起者可以接收来自多个响应者的日志,快速诊断设备故障。


数据加密

ESP-NOW可以通过ECDH和AES128-CCM来保护数据安全。

安全性

使用ECDH和所有权证明 (PoP) 字符串授权会话、生成共享密钥;

使用AES256-CTR模式加密配置数据;

使用AES128-CCM模式加密ESP-NOW数据;


ESP32-S3支持的共存场景

1781879928825534.png




二、开发环境搭建

1、下载Arduino IDE

1781879986165863.png


2、安装芯片库

安装esp32库

image-20260611205741230.png





三、硬件设备(功能)

主要使用两款ESP32硬件设备,通过ESP-NOW进行点对点无线数据传输,实现数据回传的功能;

1、A设备(ATOM-S3R_CAM) 将板载IMU传感器的数据,通过ESP-NOW发送至B设备(XIAO_ESP32S3),并在B设备的串口上显示接收到的内容;

2、B设备接收到数据后,再通过ESP-NOW,将接收到的内容发送至A设备的串口上进行显示;


A设备(ATOM-S3R_CAM)

1781880086218753.png



B设备(XIAO_ESP32S3)

1781880142874120.png




四、使用方法

通过ESP-NOW协议实现设备间的数据传输:

相关配置

1781880226369474.png

1781880270649408.png


目前 ESP-NOW 支持两个版本:v1.0 和 v2.0;

v2.0 的设备支持的最大数据包长度为 1470 (ESP_NOW_MAX_DATA_LEN_V2) 字节;

v1.0 的设备支持的最大数据包长度为 250 (ESP_NOW_MAX_DATA_LEN) 字节;

v2.0 设备可以接收来自 v2.0 和 v1.0 设备的数据包;

v1.0 设备只能接收来自 v1.0 设备的数据包;


库默认使用 v2.0 版本;

配对设备的最大数量是20;

(若开启加密,加密设备的数量不超过17,默认值是7)

详见 #include "esp_now.h"





示例代码

使用 ESP32_NOW_Serial.h 封装的API方法;

可通过 WiFi.softAPmacAddress() / WiFi.macAddress() 方法获取当前设备MAC地址;


设备A

#include "ESP32_NOW_Serial.h"
#include "MacAddress.h"
#include "WiFi.h"
#include "esp_wifi.h"

#include <M5Unified.h>	// M5_IMU库

// 0 = AP热点模式,1 = STA站点模式
#define ESPNOW_WIFI_MODE_STATION 1

// ESP-NOW 协议使用的 WiFi 信道 主信道号(1~14)
#define ESPNOW_WIFI_CHANNEL 1

#if ESPNOW_WIFI_MODE_STATION          // ESP-NOW 工作在 WiFi 站点模式
#define ESPNOW_WIFI_MODE WIFI_STA     // WiFi 工作模式
#define ESPNOW_WIFI_IF   WIFI_IF_STA  
#else                                 // ESP-NOW 工作在 WiFi 热点模式
#define ESPNOW_WIFI_MODE WIFI_AP      // WiFi 工作模式
#define ESPNOW_WIFI_IF   WIFI_IF_AP
#endif


// B设备地址:1C:DB:D4:45:3B:54
const MacAddress peer_mac({0x1C, 0xDB, 0xD4, 0x45, 0x3B, 0x54});
ESP_NOW_Serial_Class NowSerial(peer_mac, ESPNOW_WIFI_CHANNEL, ESPNOW_WIFI_IF);

unsigned long lastSend = 0;

// IMU数据采集
void getIMU(){
// 采集并计算 IMU 数据
  if (M5.Imu.update()) {  
    float ax, ay, az;  
    float gx, gy, gz;  
    float mx, my, mz;  

    M5.Imu.getAccel(&ax, &ay, &az);  
    M5.Imu.getGyro(&gx, &gy, &gz);  
    M5.Imu.getMag(&mx, &my, &mz);  

    // 计算姿态角  
    float pitch = atan2(-ax, sqrt(ay * ay + az * az)) * 180 / PI;  
    float roll = atan2(ay, az) * 180 / PI;  

    // 计算方位角  
    float heading = atan2(my, mx) * 180 / PI;  
    if (heading < 0) heading += 360;  

    // 判断运动状态  
    bool isMoving = (abs(gx) > 5) || (abs(gy) > 5) || (abs(gz) > 5);  

    // 通过 ESP-NOW 发送IMU数据
    NowSerial.printf("=== ESP_NOW ===\n");
    NowSerial.printf("俯仰角: %.1f° (%s)\n", pitch, pitch > 45 ? "上仰" : pitch < -45 ? "下俯" : "水平"); 
    NowSerial.printf("横滚角: %.1f° (%s)\n", roll, roll > 45 ? "右倾" : roll < -45 ? "左倾" : "水平");  
    NowSerial.printf("方位角: %.1f° (%s)\n", heading, heading < 45 ? "北" : heading < 135 ? "东" : heading < 225 ? "南" : heading < 315 ? "西" : "北");  
    NowSerial.printf("运动状态: %s\n\n", isMoving ? "运动中" : "静止");
  }  
}


void setup() {

  Serial.begin(115200);
  M5.begin();  
  M5.Imu.init();  
  
  if (!M5.Imu.isEnabled()) {  
    Serial.println("IMU初始化失败");  
    while (1) { }  
  }  
  Serial.println("IMU初始化成功");  

  Serial.print("WiFi 工作模式:");
  Serial.println(ESPNOW_WIFI_MODE == WIFI_AP ? "AP热点" : "STA站点");
  WiFi.mode(ESPNOW_WIFI_MODE);

  Serial.print("通信信道:");
  Serial.println(ESPNOW_WIFI_CHANNEL);
  WiFi.setChannel(ESPNOW_WIFI_CHANNEL, WIFI_SECOND_CHAN_NONE);

  // 等待 WiFi 接口启动完成
  while (!(WiFi.STA.started() || WiFi.AP.started())) {
    delay(100);
  }

  Serial.print("本机MAC地址:");
  Serial.println(ESPNOW_WIFI_MODE == WIFI_AP ? WiFi.softAPmacAddress() : WiFi.macAddress());

  // 启动 ESP-NOW 通信
  Serial.println("启动 ESP-NOW 通信...");
  NowSerial.begin(115200);
  Serial.printf("ESP-NOW 版本:%d 单包最大数据长度:%d\n", ESP_NOW.getVersion(), ESP_NOW.getMaxDataLen());
  Serial.println("----------------------------\n");
  Serial.println("");
  
}

void loop() {

  M5.update();  
// 500ms 发送一次数据
  if (millis() - lastSend >= 500) {
    lastSend = millis();
    getIMU();
  }
    // 接收B设备回传的数据转发到本地串口输出
  while (NowSerial.available()) {
    Serial.write(NowSerial.read());
  }
  delay(1); 
}


设备B

#include "ESP32_NOW_Serial.h"
#include "MacAddress.h"
#include "WiFi.h"
#include "esp_wifi.h"

// 0 = AP热点模式,1 = STA站点模式
#define ESPNOW_WIFI_MODE_STATION 1

// ESP-NOW 协议使用的 WiFi 信道
#define ESPNOW_WIFI_CHANNEL 1

#if ESPNOW_WIFI_MODE_STATION          // ESP-NOW 工作在 WiFi 站点模式
#define ESPNOW_WIFI_MODE WIFI_STA     // WiFi 工作模式
#define ESPNOW_WIFI_IF   WIFI_IF_STA
#else                                 // ESP-NOW 工作在 WiFi 热点模式
#define ESPNOW_WIFI_MODE WIFI_AP      // WiFi 工作模式
#define ESPNOW_WIFI_IF   WIFI_IF_AP   
#endif

String recv_buf =""; // 接收缓冲区

// A设备地址:B4:3A:45:BE:23:14
const MacAddress peer_mac({0xB4, 0x3A, 0x45, 0xBE, 0x23, 0x14});
ESP_NOW_Serial_Class NowSerial(peer_mac, ESPNOW_WIFI_CHANNEL, ESPNOW_WIFI_IF);

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

  Serial.print("WiFi 工作模式:");
  Serial.println(ESPNOW_WIFI_MODE == WIFI_AP ? "AP 热点" : "STA 站点");
  WiFi.mode(ESPNOW_WIFI_MODE);

  Serial.print("通信信道:");
  Serial.println(ESPNOW_WIFI_CHANNEL);
  WiFi.setChannel(ESPNOW_WIFI_CHANNEL, WIFI_SECOND_CHAN_NONE);

  // 等待 WiFi 接口启动完成
  while (!(WiFi.STA.started() || WiFi.AP.started())) {
    delay(100);
  }

  Serial.print("本机 MAC 地址:");
  Serial.println(ESPNOW_WIFI_MODE == WIFI_AP ? WiFi.softAPmacAddress() : WiFi.macAddress());

  // 启动 ESP-NOW 通信
  Serial.println("正在启动 ESP-NOW 通信...");
  NowSerial.begin(115200);
  Serial.printf("ESP-NOW 版本:%d 单包最大数据长度:%d\n", ESP_NOW.getVersion(),    ESP_NOW.getMaxDataLen());
  Serial.println("----------------------------\n");
  Serial.println("");
  
}

void loop() {
// 本地显示 + 拼接帧 + 整组回传
  while (NowSerial.available()) {
    char c = NowSerial.read();
    Serial.write(c);
    recv_buf += c;
      
    // 检测到连续两个换行:一整组IMU数据
    if (recv_buf.endsWith("\n\n")) {
      // 整组数据原样回传给发送端
      NowSerial.print(recv_buf);
      // 清空缓冲区,准备接收下一组
      recv_buf = "";
    }
  }
}





五、效果演示


NOW.gif










关键词: ESP-NOW     arduino    

专家
2026-06-20 08:06:08     打赏
2楼

谢谢分享


共2条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]