18、ESP32 ESP-NOW 点对点通信

ops/2024/10/19 0:22:06/

        ESP-NOW 是乐鑫自主研发的无连接通信协议,具有短数据包传输功能。该协议使多个设备能够以简单的方式相互通信。

ESP-NOW 功能

ESP-NOW 支持以下功能:

  • 加密和未加密的单播通信;
  • 混合加密和未加密的对等设备;
  • 最多可携带 250 字节 的有效载荷;
  • 发送回调功能,可以设置用于通知应用层传输成功或失败。

ESP-NOW 技术还存在以下局限性:

  • 有限的加密对等体。Station 模式最多支持 10 个加密对等体,在 SoftAP 或 SoftAP + Station 模式下最多 6 个;
  • 支持多个未加密的对等体,但其总数应小于 20 个,包括加密的对等体;
  • 有效负载限制为 250 字节

        简单来说,ESP-NOW 是一种快速通信协议,可用于在 ESP32 开发板之间交换小消息(最大 250 字节)。


ESP-NOW 通信

1、 单向通信,这种配置非常容易实现,适合将数据从一块板发送到另一块板

 2、一对多通信,一个 ESP32 向不同的 ESP32 发送相同或不同的命令,适合构建类似遥控器的东西

3、多对一通信,将多个传感器节点的数据收集到一个 ESP32 中。可以配置为Web服务器,以显示来自所有其他板的数据

ESP32 获取 MAC 地址

        要通过 ESP-NOW 进行通信,需要知道 ESP32 的 MAC 地址,这样就可以知道要将数据发送到哪个设备。

        每个 ESP32 都有唯一的 MAC 地址,这就是我们识别每块开发板的方式,以便使用 ESP-NOW 向其发送数据。

// 次示例返回 MAC 地址#include <Arduino.h>
#include <WiFi.h>void setup()
{Serial.begin(115200);WiFi.mode(WIFI_MODE_STA);Serial.println(WiFi.macAddress());
}void loop()
{
}

 ESP-NOW 双向通信

        使用 ESP-NOW,每块板可以同时是发送方和接收方。因此也可以构建一个类似网络的连接。

函数名称和说明
esp_now_init()初始化 ESP-NOW。在初始化 ESP-NOW 之前,必须先初始化 Wi-Fi
esp_now_add_peer()调用此函数以配对设备并将对等 MAC 地址作为参数传递
esp_now_send()使用 ESP-NOW 发送数据
esp_now_register_send_cb()注册发送回调函数。发送消息时调用此函数返回传递是否成功
esp_now_register_rcv_cb()注册接收回调函数。当通过 ESP-NOW 接收数据时触发

发送设备内容:

  1. 初始化 ESP-NOW;
  2. 注册发送回调函数 OnDataSent,函数将在发送消息时执行,告诉我们消息是否成功传递;
  3. 添加对等设备(接收 ESP32),需要知道接收方 MAC 地址;
  4. 向对等设备发送消息。

接收设备内容:

  1. 初始化 ESP-NOW;
  2. 注册接收回调函数 OnDataRecv,在收到消息时将执行;
  3. 在回调函数中,将消息保存到变量中,以使用该信息执行任何任务。
// 发送设备代码
// 发送四个类型的数据#include <Arduino.h>
#include <esp_now.h>
#include <WiFi.h>// CC:7B:5C:25:7B:BC
// 08:D1:F9:EB:52:E8uint8_t broadcastAddress[] = {0xCC, 0x7B, 0x5C, 0x25, 0x7B, 0xBC};// 发送的数据结构
typedef struct struct_message
{char a[32];int b;float c;bool d;
} struct_message;struct_message myData;esp_now_peer_info_t peerInfo;// 发送数据回调函数
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status)
{// 打印消息是否成功传递Serial.print("Last Packet Send Status:");Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}void setup()
{Serial.begin(115200);WiFi.mode(WIFI_STA);    // Wi-Fi Stationif (esp_now_init() != ESP_OK){Serial.println("Error initializing ESP-NOW");return;}esp_now_register_send_cb(OnDataSent);   // 注册发送数据的回调函数memcpy(peerInfo.peer_addr, broadcastAddress, 6);    // 复制 MAC 地址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, "THIS IS A CHAR");myData.b = random(1, 20);myData.c = 1.2;myData.d = false;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(5000);
}
// 接收设备代码#include <Arduino.h>
#include <esp_now.h>
#include <WiFi.h>// 接收数据结构体
typedef struct struct_message
{char a[32];int b;float c;bool d;
} struct_message;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.mode(WIFI_STA); // Wi-Fi Stationif (esp_now_init() != ESP_OK){Serial.println("Error initializing ESP-NOW");return;}// 注册接收数据回调函数esp_now_register_recv_cb(OnDataRecv);
}void loop()
{
}


http://www.ppmy.cn/ops/36872.html

相关文章

OceanBase 分布式数据库【信创/国产化】- OceanBase 配置项和系统变量概述

本心、输入输出、结果 文章目录 OceanBase 分布式数据库【信创/国产化】- OceanBase 配置项和系统变量概述前言OceanBase 数据更新架构OceanBase 配置项和系统变量概述配置项配置项分类配置项查询系统变量系统变量分类系统变量查询配置项与系统变量的区分OceanBase 分布式数据库…

刷题之子序列中的 k 种字母

子序列中的 k 种字母 https://kamacoder.com/problempage.php?pid1028 #include<iostream> #include<string> #include<vector> #include<cmath> using namespace std; #define mod 1000000007int main() {int n0;int k0;cin>>n>>k;stri…

五种IO模型

在《Unix网络编程》一书中提到了五种IO模型&#xff0c;分别是&#xff1a;阻塞IO、非阻塞IO、多路复用IO、信号驱动IO以及异步IO。 下面就分别来介绍一下这5种IO模型的异同。 1.阻塞IO模型&#xff1a;当用户调用阻塞函数时&#xff0c;内核会监测有无数据就绪&#xff0c;有…

贪吃蛇大作战(C语言--实战项目)

朋友们&#xff01;好久不见。经过一段时间的沉淀&#xff0c;我这篇文章来和大家分享贪吃蛇大作战这个游戏是怎么实现的。 &#xff08;一&#xff09;.贪吃蛇背景了解及效果展示 首先相信贪吃蛇游戏绝对称的上是我们00后的童年&#xff0c;不仅是贪吃蛇还有俄罗斯⽅块&…

Unity C#的底层原理概述

文章目录 前言IL与IL2CPP总结 前言 看到底层二字&#xff0c;会感到很高深&#xff0c;好似下一秒就要踏入深渊。实际上&#xff0c;对于C#底层的理解非常简单&#xff0c;比冒泡排序这种基础算法还要简单。 底层的两种机制&#xff1a;Mono和IL2CPP。 IL2CPP其中的"2&qu…

《QT实用小工具·六十》Qt 多列时间轴控件

1、概述 源码放在文章末尾 Qt 多列时间轴控件。 可与多段字符串格式自由转换&#xff0c;也可手动添加列表项。 专门用来以时间轴作为事件线发展顺序的故事大纲。 特点 时间背包功能&#xff1a;记录所有物品或属性发生的变化&#xff0c;随时回溯 时间可输入任意内容&…

2023黑马头条.微服务项目.跟学笔记(二)

2023黑马头条.微服务项目.跟学笔记 二 app端文章查看&#xff0c;静态化freemarker,分布式文件系统minIO今日简介学习内容1.文章列表加载1.1 需求分析1.2 表结构分析思考:表的垂直拆分1.3 导入文章数据库1.3.1 导入数据库1.3.2 导入对应的实体类总结1.4 实现思路1.4.1 sql练习1…

Android:弹出对话框方式梳理一览(一)

Android&#xff1a;弹出对话框方式梳理一览&#xff08;一&#xff09; Guide&#xff5c;导言 在Android开发中&#xff0c;对话框可能是我们与用户交互的非常常用的方式&#xff0c;包括弹出一个小界面&#xff0c;可能在实际场景中都非常实用。本篇文章主要就是对Android弹…