☰
ESP32 ESP-NOW实战:无路由器设备直连通信与组网指南
2026/10/7 1:41:40 网站建设 项目流程

最近在搞一个多节点环境监测的小项目,三块 ESP32 分布在房间不同角落,想做个简易的无线传感器网络。一开始按习惯直接走 MQTT + 路由器,但现场根本没有现成的无线网络环境,额外拉一台路由器又觉得太笨重。后来试了试 ESP-NOW,发现这套方案在特定场景下真的非常省事——不需要配 IP、不需要握手建链、不需要路由器转发,两块板子上电就能互相发数据,延迟还低。这篇文章就基于我实际踩坑和调通的经历,把 ESP-NOW 的原理、环境搭建、点对点通信、组网设计以及常见的坑一次说清楚,给正在用 Arduino IDE 玩 ESP32 的朋友一份能直接照着抄的参考。

适合谁看?如果你手头有两块以上 ESP32,想在不依赖 WiFi 路由器的情况下做设备间通信,或者正在做遥控小车、无线传感器节点、多板协同控制这类项目,那这篇内容应该能帮你少走不少弯路。就算你刚接触 ESP32,只要跟着步骤把环境配好,也能在十几分钟内跑通第一组 ESP-NOW 通信。

1. 先搞明白 ESP-NOW 是什么,以及为什么选它

1.1 ESP-NOW 的核心机制

ESP-NOW 是乐鑫针对 ESP8266 / ESP32 系列芯片设计的一种轻量级无线通信协议。你可以把它理解成一种“无连接”的数据报服务:发送方只要知道接收方的 MAC 地址,就能直接把数据包发过去,不需要像常规 WiFi 那样先扫描、关联、通过路由器协商加密和分配 IP 地址。

这种设计带来的直接好处有三个:第一是快,连接建立几乎零耗时,数据从应用层到发出一般在毫秒级;第二是省资源,不需要维护复杂的 TCP/IP 协议栈状态,内存占用和 CPU 开销都很低;第三是稳,在没有路由器信号的环境下,ESP-NOW 依靠设备之间的直连也能工作,特别适合临时组网和移动场景。

从协议栈角度看,ESP-NOW 工作在数据链路层之上,底层仍然使用 2.4GHz WiFi 的物理层,所以它的通信距离和普通 WiFi 大致相当,空旷环境下几十米没问题,室内隔一两堵墙也能跑,具体取决于天线和发射功率。每包数据最大可以承载 250 字节,这个大小正好容纳十几到几十个传感器数据,非常合适。

1.2 和 WiFi、蓝牙、MQTT 相比怎么选

很多刚开始接触 ESP32 的朋友会有个疑问:既然 ESP32 支持 WiFi 和蓝牙,为什么还要专门学 ESP-NOW?我的建议是不要把它当成 WiFi 的替代品,而是当成一个“短距离设备直连”的补充方案。

如果做的是需要上云、需要远程访问、需要手机随时连接的项目,那常规 WiFi + MQTT 依然是首选,毕竟 ESP-NOW 没有 IP 层,无法直接对接互联网服务。但如果只是几块开发板之间互传数据,比如遥控器控制小车、多个传感器节点往主控回传数据、两块板子做双向对话,ESP-NOW 的体验要比 WiFi 和蓝牙都舒服很多。

我自己整理过一个选型对照表,基本能代表我的实际感受:

通信方式是否需要路由器连接耗时典型延迟单包大小适合场景
ESP-NOW不需要几乎为零毫秒级250 字节板间直连、传感器组网、遥控
常规 WiFi TCP/UDP需要数秒级几十毫秒接近 MTU上云、局域网大量数据传输
MQTT需要数秒级几十毫秒以上取决于 Broker物联网云端采集
蓝牙 BLE不需要秒级十几到几十毫秒20 字节左右手机交互、低功耗外设

除了连接速度,还有一点非常重要:ESP-NOW 在发送端和接收端都不需要复杂的握手协议。WiFi 模式下如果路由器重启,所有设备要重新关联,应用层可能还要处理重连逻辑,而 ESP-NOW 直接把数据丢给对方,发完就完事,逻辑简单太多了。

2. 准备工作与开发环境搭建

2.1 硬件选型建议

玩 ESP-NOW 最省心的硬件就是 ESP32 开发板。市面上常见的 NodeMCU-32S、ESP32 DevKitC、ESP32-S3、ESP32-C3 等都可以跑 ESP-NOW。有一点要注意:ESP32-S2 和部分 ESP32-C 系列虽然也能用 ESP-NOW,但官方支持情况会略有差异,有些版本需要单独更新底层库。如果不确定,直接买经典的 ESP32 DevKitC 或者 NodeMCU-32S,资料最多,踩坑最少。

另外建议至少准备两块开发板,因为 ESP-NOW 的本质是设备间通信,单块板子只能做自我测试,没法完整验证收发链路。如果只是先了解概念,也可以在一块板子上写一个“自发自收”的测试程序,让模块同时注册发送和接收回调,把数据发给自己,但这只能验证协议栈是否正常,不能代表真实通信环境。

天线和电源这种细节容易被忽略。ESP32 板载天线附近尽量不要布置金属物体和密集排线,否则信号衰减会很厉害。供电方面,ESP-NOW 发送瞬间电流比较大,如果用劣质 USB 线或者从电脑前置 USB 口供电,可能出现电压跌落导致重启或丢包,建议使用质量好一点的 USB 线,或者外接 5V 电源。

2.2 Arduino IDE 安装 ESP32 支持

我平时主要用 Arduino IDE 开发 ESP32,虽然 PlatformIO 功能更强,但从零起步还是 Arduino IDE 最快。打开 Arduino IDE,在“文件 -> 首选项 -> 附加开发板管理器网址”里添加 Espressif 官方地址:

https://espressif.github.io/arduino-esp32/package_esp32_index.json

然后打开“工具 -> 开发板 -> 开发板管理器”,搜索 esp32,找到 Espressif Systems 官方发布的 esp32 包,点安装。这步会下载比较多的文件,耗时取决于网络情况,耐心等它装完。安装完成后,在“开发板”菜单里就能看到 ESP32 系列了,选自己手上对应的型号即可。

很多人会卡在这一步,最常见的表现是开发板管理器里搜索不到 esp32,或者安装到一半报错。建议优先检查附加开发板管理器网址是不是完整复制、前后有没有多余空格;如果网址没问题但还是失败,可以试着把 Arduino IDE 升级到较新版本,旧版 IDE 对 JSON 格式的支持不太好,容易解析失败。

2.3 用一个小例子验证环境

环境装好后,不要急着写 ESP-NOW 程序。先烧一个最简单的 LED 闪烁例程,确认编译下载链路没问题。在 Arduino IDE 里选择板子型号和一个未被占用的串口,打开“文件 -> 示例 -> 01.Basics -> Blink”,把 LED_BUILTIN 换成板载 LED 引脚,点上传。

这一步通过之后,再写一个简单的串口打印程序,确认开发板的串口监视器能正常输出信息。串口波特率我一般设 115200,这也是 ESP32 默认日志输出的常用波特率。环境验证通过后,再进入下一节的内容,不然程序写好了却烧不进去,排查起来会非常痛苦。

3. ESP-NOW 发射端与接收端代码解析

3.1 发射端怎么写

ESP-NOW 的使用套路很固定,总共分四步:初始化 WiFi 模式、初始化 ESP-NOW、添加对端设备、发送数据。我先贴一个最精简的发送端示例:

#include <WiFi.h> #include <esp_now.h> // 接收端设备的 MAC 地址 uint8_t peerMac[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; typedef struct message { int id; float value; } message; message myData; void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) { Serial.print("发送状态:"); Serial.println(status == ESP_NOW_SEND_SUCCESS ? "成功" : "失败"); } void setup() { Serial.begin(115200); WiFi.mode(WIFI_STA); if (esp_now_init() != ESP_OK) { Serial.println("ESP-NOW 初始化失败"); return; } esp_now_register_send_cb(OnDataSent); esp_now_peer_info_t peerInfo; memcpy(peerInfo.peer_addr, peerMac, 6); peerInfo.channel = 0; peerInfo.encrypt = false; peerInfo.ifidx = (wifi_interface_t)ESP_IF_WIFI_STA; if (esp_now_add_peer(&peerInfo) != ESP_OK) { Serial.println("添加对端失败"); return; } myData.id = 1; myData.value = 25.6f; } void loop() { esp_now_send(peerMac, (uint8_t *)&myData, sizeof(myData)); delay(1000); }

这个例子里有几个关键点。第一,WiFi.mode(WIFI_STA)是必须的,即使不连接任何路由器,也要把 WiFi 初始化成 station 模式,ESP-NOW 依赖这个底层接口。第二,esp_now_peer_info_t结构体用来描述对端信息,里面最重要的就是 MAC 地址。第三,发送用esp_now_send,参数是对端 MAC、数据指针和数据长度。

有一个细节很容易踩坑:数据长度不能超过 250 字节。如果自定义结构体太大,要么拆包发送,要么改用更紧凑的数据格式。我在项目里一般用手动排列的uint8_t数组或者精心设计过的结构体,控制好字节数。

3.2 接收端怎么写

接收端同样需要先初始化 WiFi 和 ESP-NOW,然后注册一个接收回调。数据到达时会自动触发回调,在回调里解析数据即可。示例代码:

#include <WiFi.h> #include <esp_now.h> typedef struct message { int id; float value; } message; message myData; void OnDataRecv(const uint8_t *mac, const uint8_t *incomingData, int len) { memcpy(&myData, incomingData, sizeof(myData)); Serial.print("收到节点 "); Serial.print(myData.id); Serial.print(" 数值 "); Serial.println(myData.value); } void setup() { Serial.begin(115200); WiFi.mode(WIFI_STA); if (esp_now_init() != ESP_OK) { Serial.println("ESP-NOW 初始化失败"); return; } esp_now_register_recv_cb(OnDataRecv); } void loop() { // 接收回调会自动运行,这里可以处理其他逻辑 }

注意,接收端不需要调用esp_now_add_peer,因为 ESP-NOW 的数据包本身包含了发送方 MAC 地址,接收方可以直接根据来源 MAC 来决定要不要处理。这在实际组网时很灵活:既可以所有节点都收,也可以只处理白名单里的设备。

结构体对齐也是一个容易忽略的坑。我用自定义结构体传输数据时,发送端和接收端如果编译器对齐方式不一致,解析出来的数据就会错位。解决办法有两个:一是两端使用完全相同的结构体定义,在同一个 Arduino 环境下编译基本没问题;二是在结构体上加上__attribute__((packed)),强制紧凑排列,这样更稳妥。

3.3 双向通信:带应答模式

单向发送跑通后,双向通信其实只是把发送逻辑和接收逻辑同时放到两块板上。每块板子既注册发送回调,也注册接收回调,既是发送端也是接收端。这种模式非常适合做遥控器和执行端之间的双向状态确认。

比如遥控器发送指令给小车,小车收到后立刻回一个状态包,遥控器收到回包后再更新 UI 或 LED 状态。因为 ESP-NOW 本身没有 ACK 机制,发送回调里的ESP_NOW_SEND_SUCCESS只代表数据已经交给了底层协议栈并发出去了,并不代表对端一定成功解析。所以如果业务上要求严格确认,需要在应用层自己设计应答包。

我自己做双向通信时有一个习惯:发送端每秒钟发一次数据,接收端每收到一次就立刻回一个确认包。发送端检查如果连续三秒没收到确认包,就认为链路异常,触发本地告警或者重连逻辑。这套方案虽然简单,但在实际测试中很可靠。

4. 从点对点扩展到组网设计

4.1 发送失败与重发机制

ESP-NOW 的esp_now_send返回值本身只代表数据是否成功提交给协议栈,真正的发送结果要靠发送回调里的status参数判断。如果状态是ESP_NOW_SEND_FAIL,表示数据在传输过程中出了问题,常见原因是信道干扰、接收方不在线或者距离过远。

默认情况下,ESP-NOW 不会自动重发。这一点非常重要,很多教程没有强调,导致实际项目里数据丢失却不自知。如果我做的是传感器数据采集这类允许偶尔丢包的应用,就不做重发,靠提高发送频率来弥补;但如果做的是遥控指令这类不能丢的应用,我一般会在应用层做超时重发,比如连续 5 秒没有收到接收端确认,就把指令再发一遍。

发送间隔也要控制好。虽然 ESP-NOW 本身很轻量,但如果你在一个for循环里疯狂调用esp_now_send发送大量小包,底层协议栈会来不及处理,回调里会频繁报失败。我的经验是保守一点,单设备建议发送间隔不要低于 10 毫秒,实际项目里经常用到 20 到 50 毫秒。如果数据量大,可以考虑批量组包发送,比如把 5 个传感器数据拼成一个结构体一次发出。

4.2 一对多、多对一、多对多拓扑

ESP-NOW 的优势之一就是组网灵活,同一块板子可以同时添加多个对端设备。目前官方资料显示,ESP32 作为发送端最多支持大约 10 个加密对端,如果关闭加密,可以支持更多对端。实际使用中,控制在对端 10 个以内最稳妥。

一对多是最简单的场景:主控板把所有子节点的 MAC 地址都添加为 peer,然后逐个调用esp_now_send,就可以像点名一样给每个节点发数据。多对一更简单,所有子节点把主控的 MAC 地址添加为 peer,主控只需要注册接收回调,不需要添加任何 peer,就能收到所有子节点的数据。

多对多的实现方式可以用广播地址FF:FF:FF:FF:FF:FF。把数据发给广播地址,所有同一信道下注册了接收回调的 ESP32 都能收到。这种方式的优点是简单,但缺点是所有设备都会处理这份数据,需要在数据包结构里包含接收者标识,非目标设备收到后直接丢弃。比如在结构体里加一个targetId字段,每块板子根据自己的编号决定是否处理。

4.3 与 WiFi 同时使用时的注意事项

ESP32 的 WiFi 和 ESP-NOW 共用同一个 2.4GHz 射频前端,所以理论上可以同时使用,但有一个容易踩的坑:信道必须一致。如果你让 ESP32 连接了一个 WiFi 路由器,路由器工作在第 6 信道,那么 ESP-NOW 发送也必须使用第 6 信道,否则对方收不到。

这里有一个很隐蔽的细节:当你调用WiFi.begin()连接路由器后,ESP32 会自动切换到路由器所在的信道。此时如果你之前手动初始化 ESP-NOW 时给peerInfo.channel设置了其他值,就可能出现 ESP-NOW 发送失败。解决方法是把peerInfo.channel设置成 0,表示自动跟随当前 WiFi 信道。如果两块板子都不连路由器,它们都会使用默认的 0 信道,通常也能正常通信。

我在实际项目中经常让主控同时做两件事:通过 WiFi 把采集到的数据上传到云端,同时通过 ESP-NOW 和各子节点通信。这种场景下一定要用WiFi.mode(WIFI_STA)模式,不要进入WIFI_AP_STA混合模式,除非你确实需要同时开热点。混合模式会占用更多资源,某些固件版本下还会和 ESP-NOW 产生冲突。

5. 实战:一个传感器数据回传小项目

5.1 需求与协议设计

光讲 API 不落地没什么意义,我拿一个实际做过的温湿度采集项目举例。项目需求很简单:两个传感器节点分别放在阳台和客厅,每隔 5 秒采集一次温湿度,把数据回传给一个主控节点,主控节点用 OLED 显示屏显示最新读数。

因为要传两个浮点数和一个节点编号,我设计了这样一个结构体:

typedef struct sensor_data { uint8_t nodeId; // 节点编号 float temperature; // 温度 float humidity; // 湿度 uint32_t timestamp; // 采集时间戳,毫秒 } sensor_data;

算一下大小:uint8_t占 1 字节,两个float各占 4 字节,uint32_t占 4 字节,总共 13 字节。就算加上编译器对齐的网络封包开销,也远小于 250 字节的限制,所以不需要考虑分包。

这里有个设计经验:时间戳字段很多人会省略,但我强烈建议保留。有了发送端的本地时间戳,接收端才能判断数据是不是太久没更新,从而识别“链路还通,但传感器已经挂了”这类异常情况。这在长时间运行的项目里非常实用。

5.2 完整代码框架

传感器节点(发送端)的代码框架如下:

#include <WiFi.h> #include <esp_now.h> #include <DHT.h> #define DHTPIN 4 #define DHTTYPE DHT22 DHT dht(DHTPIN, DHTTYPE); uint8_t masterMac[] = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}; typedef struct sensor_data { uint8_t nodeId; float temperature; float humidity; uint32_t timestamp; } sensor_data; sensor_data data; void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) { if (status != ESP_NOW_SEND_SUCCESS) { Serial.println("上次发送失败"); } } void setup() { Serial.begin(115200); dht.begin(); WiFi.mode(WIFI_STA); esp_now_init(); esp_now_register_send_cb(OnDataSent); esp_now_peer_info_t peerInfo; memcpy(peerInfo.peer_addr, masterMac, 6); peerInfo.channel = 0; peerInfo.encrypt = false; esp_now_add_peer(&peerInfo); data.nodeId = 1; } void loop() { data.temperature = dht.readTemperature(); data.humidity = dht.readHumidity(); data.timestamp = millis(); esp_now_send(masterMac, (uint8_t *)&data, sizeof(data)); delay(5000); }

主控节点的代码就是在前面接收端例程基础上,加上 OLED 显示逻辑。OLED 我一般用 U8g2 库,初始化之后在接收回调里更新显示变量,主循环只负责display.refresh()。这里有一个注意点:接收回调是在协议栈的上下文中执行的,不要在回调里跑耗时的操作,比如delay、Serial.print大段内容或者动态分配内存,否则会影响后续数据包的接收。我通常只用回调把数据拷贝到全局变量,并置一个dataUpdated标志,具体显示逻辑放到loop()里处理。

只要注意上述几点,两三个节点同时回传数据基本不会互相干扰。因为每个节点有不同的nodeId,主控完全可以区分数据来源;即使两个节点同一瞬间发数据,由于底层射频的 CSMA 机制,通常也不会发生严重碰撞,万一偶尔撞包,下一轮 5 秒后的重传就会补上。

5.3 数据校验与协议扩展

中文环境下做数据传输,很多朋友会忽略字节序和数据一致性的问题。比如用结构体直接传输时,结构体里的uint32_t在发送端和接收端都按小端字节序存储,正常情况下没问题;但如果你混合使用了不同平台或不同编译器,或者将来想用 Lua、Python 等解析数据,就需要自己定义字段顺序和字节序,不能直接套结构体。

所以我提供一个更通用的建议:关键数据可以用数组手动打包,比如用memcpy把浮点数转成字节数组再拼接到发送缓冲区。这种方式写起来稍微麻烦一点,但可以保证两端协议完全一致,也方便做校验。

校验字段的设计也是一个改进思路。如果传输的是传感器数据,可以在结构体里加一个简单的 CRC8 或者累加和字段,接收端解析完后先校验再决定是否丢弃。ESP-NOW 底层其实有 CRC 校验,射频层会丢弃损坏的包,所以大多数时候不需要额外校验,但在强干扰环境下,应用层校验多一层保险。

6. 常见问题排查表与避坑心得

6.1 发送失败最常见的三种原因

我把实际使用中遇到过的情况整理成一张速查表,省得大家出问题时漫无目的乱试。

现象可能原因解决办法
esp_now_init()返回失败WiFi 模式未设置先调用WiFi.mode(WIFI_STA)
发送回调一直报FAILMAC 地址填错用WiFi.macAddress()或esp_efuse_mac_get_default()打印确认
发送回调报FAIL,但 MAC 正确信道不一致让所有设备信道统一,或在不连路由器时保持默认信道
上电后一段时间能收,以后收不到供电不稳导致射频异常换电源线、加外部稳压电容
离远一点就丢包天线位置、发射功率尽量调整板子方向,必要时设置WiFi.setTxPower(WIFI_POWER_19_5dBm)

其中 MAC 地址填错是新手最常犯的错。ESP32 的 MAC 地址形如AA:BB:CC:DD:EE:FF,在代码里写成{0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF},必须保持顺序一致。我一开始就试过把某个地址的冒号位置看错,结果发送回调稳定报失败,查了大半天才发现是0xCE写成了0xDE,非常憋屈。

发射功率也值得一提。默认状态下 ESP32 的 WiFi 发射功率通常不是最大值,如果你在做远距离传输测试,可以用:

WiFi.setTxPower(WIFI_POWER_19_5dBm);

把它提高到最高档。注意最大功率意味着更高功耗,电池供电的节点要仔细权衡。我测下来,从默认功率提到最高,通信距离大约能增加两成到三成,但发送电流会明显上升,电池项目里不太划算。

6.2 接收端收不到数据,怎么排查

接收端收不到数据,多数情况下是这几个原因:

第一,接收端没有初始化 ESP-NOW,漏了esp_now_init()。这看起来像废话,但真的有朋友把发送端初始化成功后就以为接收端不用初始化,结果回调一直不触发。

第二,接收端和发送端不在同一个信道。如果发送端连接了一个 WiFi 路由器,路由器自动跳到第 6 信道,而接收端没有连接任何路由器,它可能仍然停留在默认信道,两端就“错过”了。解决方法是把两块板子同时连同一个路由器,或者都用esp_wifi_set_channel固定信道。

第三,接收回调里做了耗时操作。前面说过,回调函数中不要用delay或Print大字符串,否则底层协议栈缓冲可能溢出,后续数据就无法及时处理。正确的做法是回调内只做标志位设置和内存拷贝。

我还遇到过一种比较隐蔽的情况:OLED 或者其他外设使用了和 WiFi 射频冲突的引脚,导致 ESP-NOW 接收质量严重下降。这种问题通常只影响特定板型和特定外设组合,排查时要先把外设断开,看能不能正常接收,再用最小化方式逐步恢复。

6.3 关于加密、配对与安全

ESP-NOW 支持对传输数据加密,使用方式是生成一个 PSK,添加到 peer 时把peerInfo.encrypt设为true,并填充lmk密钥。加密能防止同信道的其他设备直接解析你的数据,但如果只是个人项目,加密意义不大,反而多一道配置,容易出错。我一般建议先在无加密模式下跑通,后续再按需升级。

还有一个容易被忽略的地方:ESP-NOW 对端信息保存在 RAM 里,板子重启后需要重新添加 peer。如果项目要求掉电恢复后自动通信,代码里就没有什么特殊逻辑,因为setup()里本来就会重新初始化,Peers 重新添加即可,不需要持久化到 Flash。

安全方面,如果你在公开场合部署 ESP-NOW 网络,至少要做到两点:一是数据包中加入设备标识和校验,防止误收;二是如果传输敏感指令,一定要开启加密。虽然 ESP-NOW 短距离直连本身暴露面不大,但 2.4GHz 频段很容易被嗅探,不要心存侥幸。

6.4 内存、栈空间和稳定性

ESP-NOW 本身内存开销不大,但它和 WiFi 共存时会占用一定的协议栈缓冲区。如果程序里同时启用 WiFi 连接、MQTT 客户端和 ESP-NOW,某些库定义的大缓冲区会把内存吃得很紧,严重时导致启动失败或重启。

我的做法是尽量精简库的依赖,比如 MQTT 客户端可以换轻量级的 PubSubClient,而不是一上来就装重量级的全功能库。另外 Arduino 的loop()里避免用大量动态字符串拼接,字符串操作最容易引入内存碎片,长期运行后会莫名其妙地崩溃。

如果你做的是 7x24 小时长期运行的项目,建议加一个看门狗定时器,比如每 60 秒检查一次最近的发送/接收时间戳,如果超时没有活动,就主动重启。这种“粗放但有效”的手段,在无人工值守的环境中很管用。

7. 我用 ESP-NOW 半年后的一些体会

聊了这么多,最后分享一点个人感受。ESP-NOW 最大的价值不是替代 WiFi,也不是替代蓝牙,而是在“设备少、距离近、要求快、不想配置路由器”的场景里,提供了几乎零成本的通信方案。它的学习曲线比 MQTT 平缓很多,代码量少,调试也直观,特别适合刚开始接触无线通信的玩家。

我踩过最大的坑其实不是技术本身,而是思维惯性。一开始总觉得所有无线通信都应该先连网、再建连接、再传数据,这是被 WiFi 和手机 App 的开发习惯惯出来的。ESP-NOW 用下来之后,我发现很多本地场景根本不需要走 IP 栈,直接裸传反而更稳定。这种“最多余一层,就会多一些麻烦”的经验,也让我在设计其他项目时,多了一层“协议最小化”的思考。

如果你正好手头有两块 ESP32,建议别光看文章,直接动手烧一个发送端和一个接收端,把上面第一组代码跑通,再慢慢改成自己的协议。通信这种东西,光看文档和自己上手跑一遍,理解深度完全不一样。等跑通了那一下,你会发现原来设备之间聊天可以这么简单。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询