分享使用Arduino IDE的ESP32 ESP-NOW入门教程

这篇教程介绍了如何使用 ESP32 ESP-NOW 协议在 ESP32 设备间进行无线通信,包括单向和双向通信。ESP-NOW 提供低功耗、安全的点对点通信,无需 WiFi 或路由器。文章详细阐述了协议特点、配置步骤、代码示例以及如何保护通信安全。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ESP32 ESP-NOW 是专门为其 ESP8266 和 ESP32 微控制器开发的无线通信协议。它为 ESP32 设备提供低功耗、安全、低成本、直接的无线通信解决方案。借助 ESP-NOW,多个 ESP32 设备可以相互通信,无需 WiFi 或路由器,从而创建设备的网状网络。

在本教程中,我们将学习使用 ESP32 ESP-NOW 在 ESP32 设备之间进行无线通信。无论您想要发送传感器数据、控制 ESP 输出还是建立双向通信,本指南都将为您提供必要的步骤。

ESP-NOW 协议介绍

使用 ESP-NOW,我们可以在 ESP MCU 设备之间进行单向甚至双向通信,而无需使用 Wi-Fi 网络。它允许低开销的点对点无线数据传输,但数据包较小。最多可传输 250 字节的数据。因此,如果需要传输大量数据,那么使用此协议就没用了。

使用 ESP-NOW,连接协议得到简化,从而降低了功耗,因为数据传输所需的时间更少。此外,ESP-NOWESP-NOW使用与 Wi-Fi 相同的 2.4 GHz 频段,但不需要连接或干扰本地网络连接。它是一种快速、方便的通信协议,适用于传输较小量的数据。

ESP32 ESP-NOW 主要特性

  1. 一对一的数据传输(加密和未加密)。
  2. 支持加密和未加密的对等设备。对于加密设备,工作站模式下最多有 10 个对等点,SoftAP 或两种模式的混合模式下最多有 6 个对等点。但是,对于未加密的设备,最多允许有 19 个设备,且不限制其运行模式。
  3. 最多可以以小数据包的形式传输 250 字节的数据。
  4. 它生成一个回调函数,通知应用层数据是否传输成功。

要初始化 ESP-NOW 连接,我们必须首先配对 ESP32 板。无论任何一块板重新启动,该连接都将保持,并且传输将继续顺利进行。

在本教程中,我们将演示一个 Arduino 草图,通过该草图我们将数据从一个 ESP32 板无线传输到另一块板(单向通信)。在此之前,让我们首先看一下可以使用该通信协议的一些配置。

ESP32 ESP-NOW 单向通信

在单向通信中,一个对等设备充当发送方/主设备,另一台充当接收方/从设备。在这种情况下,我们可以对发送方-接收方进行多种配置。

  • 一块 ESP32 板向另一块 ESP32 板发送数据

如下图所示,一块 ESP32 板充当发送器,另一块板接收数据,因此充当接收器。
用途:发送传感器数据,控制 ESP 输出,包括 LED、继电器、蜂鸣器等。

ESP NOW 单向通信配置1

  • 一块 ESP32 发送器板向其他各种 ESP32 接收器板发送数据

在这种情况下,一个 ESP32 板将充当发送器/主设备,并将数据发送到多个充当接收器/从设备的 ESP32 板。
用途:遥控

ESP NOW 单向通信配置2

  • 一块 ESP32 板从其他各种 ESP32 发送器板接收数据

最后,在这种情况下,一个 ESP32 板(接收器/从机)从多个 ESP32 板(发送器/主机)接收数据。
用途:接收来自各种传感器的传感器数据。

ESP NOW 单向通信配置3

ESP-NOW 双向通信

ESP-NOW 协议还支持对等设备之间的双向通信。在这种情况下,ESP32板可以同时充当发送器(主)和接收器(从)。我们可以有两个 ESP32 板来传输数据,如下所示:

ESP NOW 双向通信配置1

或者甚至有一个 ESP32 板网络传输数据:

ESP NOW 双向通信配置2

ESP-NOW 有用的功能

以下是 ESP-NOW 函数的列表,这些函数在将 ESP-NOW 与 ESP32 结合使用时非常方便且经常使用。要查看更多信息,请查看官方 ESP-NOW 文档。

  • esp_now_init() :该函数将初始化 ESP-NOW 协议。请记住在初始化 ESP-NOW 通信协议之前启动 Wi-Fi。
  • esp_
<think>好的,用户想了解在Linux网络编程中如何给in6_addr结构体的s6_addr成员赋值。我需要先回忆一下相关的知识。 首先,in6_addr结构体用于存储IPv6地址,定义在头文件<netinet/in.h>中。s6_addr是一个unsigned char数组,长度为16,对应IPv6的128位地址。每个字节代表地址的一部分,通常IPv6地址用十六进制表示,分8组,每组4个字符,例如2001:0db8:85a3:0000:0000:8a2e:0370:7334。 接下来,用户需要知道如何给这个数组赋值。常见的方法有几种: 1. 使用inet_pton函数将字符串形式的IPv6地址转换为二进制格式,并存储到in6_addr结构体中。这是最常用的方法,特别是处理用户输入的地址时。 2. 手动对每个字节赋值,这适用于程序生成的地址,或者需要构造特定地址的情况。这时候需要了解IPv6地址的字节顺序,注意网络字节序是大端模式,但s6_addr数组是按顺序存储的,不需要转换,因为IPv6地址的结构本身已经是网络字节序的排列。 另外,可能需要提到初始化结构体的步骤,比如声明struct in6_addr变量,然后使用上述方法填充s6_addr成员。 还要注意错误处理,例如inet_pton的返回值,确保转换成功。同时,如果手动赋值,需要确保每个字节的值正确,避免越界访问数组。 可能需要举例说明两种方法的具体代码,比如使用inet_pton的例子,以及手动赋值的例子,比如环回地址::1对应的数组值。 还要检查是否有其他方法,比如使用宏或者辅助函数,但标准方法主要是inet_pton和手动赋值。 最后,要确保回答结构清晰,分步骤说明,让用户能够理解并正确应用。</think>在Linux网络编程中,`in6_addr`结构体用于表示IPv6地址,其`s6_addr`成员是存储实际地址数据的核心部分。以下是详细赋值方法: --- ### 一、理解结构体定义 ```c #include <netinet/in.h> struct in6_addr { unsigned char s6_addr[16]; // 128位IPv6地址(16字节) }; ``` --- ### 二、赋值方法详解 #### 方法1:使用`inet_pton()`函数(推荐) **作用**:将人类可读的IPv6字符串转换为二进制格式,并存入`s6_addr`。 ```c #include <arpa/inet.h> struct in6_addr addr; const char* ipv6_str = "2001:db8::1"; // 示例IPv6地址 // 转换并赋值 if (inet_pton(AF_INET6, ipv6_str, &addr.s6_addr) != 1) { // 错误处理:转换失败(如格式错误) } ``` #### 方法2:手动逐个字节赋值 **适用场景**:直接构造特定二进制地址(如全零、环回地址等)。 ```c struct in6_addr addr; // 示例:环回地址 ::1 unsigned char loopback[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}; memcpy(addr.s6_addr, loopback, 16); // 或直接按索引赋值 memset(addr.s6_addr, 0, 16); // 全零地址 :: addr.s6_addr[15] = 1; // 最后一个字节设为1(对应::1) ``` #### 方法3:使用预定义宏 某些系统提供宏简化常见地址操作: ```c // 示例:设置环回地址 #include <netinet/in.h> struct in6_addr addr = IN6ADDR_LOOPBACK_INIT; ``` --- ### 三、关键注意事项 1. **字节顺序**: - IPv6地址本身是网络字节序(大端序),但`s6_addr`直接按内存顺序存储,无需额外转换。 - 手动赋值时需确保逻辑正确性(如分段填充)。 2. **地址范围验证**: - 手动赋值需确保每个字节值在`0x00-0xFF`之间。 3. **兼容性处理**: - 混合IPv4映射地址(如`::ffff:192.168.1.1`)需特殊处理前12字节。 --- ### 四、完整代码示例 ```c #include <stdio.h> #include <string.h> #include <arpa/inet.h> #include <netinet/in.h> int main() { // 方法1示例 struct in6_addr addr1; const char* str_ip = "2001:db8::1234"; if (inet_pton(AF_INET6, str_ip, addr1.s6_addr) != 1) { perror("inet_pton failed"); return -1; } // 方法2示例 struct in6_addr addr2; memset(addr2.s6_addr, 0, 16); // :: addr2.s6_addr[15] = 0x01; // ::1 return 0; } ``` --- 通过上述方法,您可以根据实际需求灵活地为`in6_addr.s6_addr`赋值。推荐优先使用`inet_pton()`处理字符串输入,手动赋值适用于底层协议实现等特殊场景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值