联网与通信

第 24 课:ESP-NOW——两块板子对话

不用路由器、不用网络,两块板子隔空直接说话

这节课需要两块板子。 你只有一块的话可以跳过——它不影响后面的任何课程。

我是吴老师。先说清楚,这节课你要多花几十块钱。 我不绕弯子。

但我要告诉你:这是整个套件里最有"科技感"的一节课。 前面所有课,你的板子都在跟"别人"打交道——跟路由器、跟服务器、跟手机。只有这节课,是两块板子面对面说话。

而且方式很硬核:不连路由器、不连 WiFi、不连互联网,什么都不用。

一、先把两块板子的事说完

为什么非要两块? 因为"说话"这件事,一个人干不了。你对着空气喊,那不叫通信。办法就两个:

  1. 再买一块。就买跟现在一样的 ESP32-C3 开发板,几十块钱。跟同学合买也行——你俩一人一块,还能互相烧程序、互相检查接线,比一个人闷头搞强多了。
  2. 跳过这节课。真的可以,它不挡你后面的任何一节课。第 25 课的蓝牙你一块板子就能做,第 26 课往后全是实战课题,也用不上两块板子。

我建议买。 理由不是"这课很重要",而是——两块板子能玩的东西,比一块板子多出一大截。 一个是"探测器",一个是"报警器",中间什么都不用连。很多东西只有这样才做得出来。

二、不用路由器?那怎么说话

先看这张对比图。这张图你得看明白,它是这节课的全部。

对比图:上网课要经过路由器和服务器绕一大圈,ESP-NOW 是两块板子靠 MAC 地址直接对话

上面那条路,是你前四节课一直在走的:

板 A → 路由器 → 服务器 → 板 B。

看它绕了多大一圈。 板 A 说一句话,得先给路由器,路由器给它转上互联网,跑到某台服务器上,服务器再原路送回你家,交给板 B。

这条路很好用——你家在北京,板 B 在广州都行。但它有个前提:路由器得有、网得通、服务器不能挂、信号得覆盖到、板 B 也得连上同一个网——五样,少一样就全完蛋。

下面那条路,就是 ESP-NOW:板 A 直接跟板 B 说。

没有路由器,没有服务器,没有互联网。两个巴掌大的小板子,隔着一间屋子,就那么把话说了。

它是怎么做到的? 简单说:ESP-NOW 用的还是 WiFi 那套无线电,但不用 WiFi 那套"入网规矩"。

你可以这么想:WiFi 上网像去学校食堂吃饭——你得先办卡、排队、刷卡、被系统认出来,才能拿到饭。ESP-NOW 像两个同学在操场上喊话——不用办卡,直接喊。

(正式叫法是"点对点"或者"对等网络"。你以后查资料看到 peer-to-peer、P2P,就是这个意思。)

那它靠什么认出对方?

靠 MAC 地址。

第 20 课你连路由器的时候见过这个名字。每块板子的 WiFi 芯片,出厂就带一个 MAC 地址,全世界唯一。 跟你手机、你家的路由器一样,也是一串 XX:XX:XX:XX:XX:XX 这样的东西。

ESP-NOW 认的就是这串号。 板 A 想跟板 B 说话,就得把板 B 的 MAC 地址写进自己的程序里

这就带出一个必然的后果:你得先把两块板子的 MAC 读出来。

记住这句话,它是这节课所有麻烦的源头。 我先把话撂这儿:你后面要是收不到消息,十有八九是这串地址写错了。

三、动手(一):先把两块板子的 MAC 读出来

这一步千万别跳。 而且两块板子都要做,各自读出各自的。

接线很简单——两块板子都不用接任何模块,插上数据线就行。

C++
#include <WiFi.h>

void setup() {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);          // 先切到"上网模式",再读 MAC

  Serial.print("我的 MAC 地址是:");
  Serial.println(WiFi.macAddress());
}

void loop() {
}

这块板子烧一遍,打开串口,抄下来。 再换另一块板子,同样的程序再烧一遍,抄下来。

拿张纸,或者记事本,写清楚:

MAC 地址
板 A(探测器) __:__:__:__:__:__
板 B(报警器) __:__:__:__:__:__

这里有个小坑: 如果你读出来是 00:00:00:00:00:00别慌,不是你板子坏了——先调用 WiFi.mode(WIFI_STA) 再读一遍。这行代码看着没用,其实是在告诉芯片"把 WiFi 打开,我要用"。

什么时候需要核对 MAC? 任何时候你觉得"地址可能写错了",就把这个程序再烧一遍。它是个工具,不是一次性的。

四、动手(二):一块发,一块收

现在最关键的一句话:两块板子要烧不同的程序。

这是新手最容易犯的错,而且错得毫无痕迹。

你很自然就会想:"两块板子嘛,程序当然一样。"——然后两块都在发,没人收。现象是:两块板子都在串口里刷"我发了",对面一点动静都没有。

一块当"探测器"(发),一块当"报警器"(收)。程序不一样。

板 A(探测器)的程序

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

// ⚠ 换成你抄下来的"板 B"的 MAC 地址
uint8_t receiverMAC[] = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF};

void setup() {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);

  if (esp_now_init() != ESP_OK) {
    Serial.println("ESP-NOW 初始化失败");
    return;
  }

  esp_now_peer_info_t peer = {};
  memcpy(peer.peer_addr, receiverMAC, 6);
  peer.channel = 0;
  peer.encrypt = false;
  esp_now_add_peer(&peer);     // 把对方"加为联系人"
}

void loop() {
  uint8_t data = 1;            // 1 = 有情况
  esp_now_send(receiverMAC, &data, sizeof(data));
  Serial.println("已发出:1");
  delay(1000);
}

esp_now_add_peer 那一步。 这一步就是在说:"板 B 的地址我记住了,以后发给它。" 跟手机里存个联系人是一个意思。

板 B(报警器)的程序

先接上灯和蜂鸣器:

模块 针脚 接到
LED 模块 VCC / GND / Signal 3.3V / GND / GPIO3
蜂鸣器 VCC / GND / I/O 3.3V / GND / GPIO4
C++
#include <WiFi.h>
#include <esp_now.h>

unsigned long lastAlarm = 0;

// 收到消息就会自动跑这个函数
void onReceive(const uint8_t *mac, const uint8_t *data, int len) {
  Serial.print("收到来自:");
  for (int i = 0; i < 6; i++) {
    Serial.printf("%02X", mac[i]);
    if (i < 5) Serial.print(":");
  }
  Serial.println();

  if (len > 0 && data[0] == 1) {
    digitalWrite(3, HIGH);      // 灯亮
    digitalWrite(4, HIGH);      // 蜂鸣器响
    lastAlarm = millis();
    Serial.println("→ 报警!");
  }
}

void setup() {
  Serial.begin(115200);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  WiFi.mode(WIFI_STA);

  Serial.print("我的 MAC:");
  Serial.println(WiFi.macAddress());   // 顺便再确认一次

  if (esp_now_init() != ESP_OK) {
    Serial.println("ESP-NOW 初始化失败");
    return;
  }
  esp_now_register_recv_cb(onReceive);   // 挂号:收到了就叫我
}

void loop() {
  if (millis() - lastAlarm > 500) {      // 响半秒就停,免得吵死人
    digitalWrite(3, LOW);
    digitalWrite(4, LOW);
  }
}

两块板子都插上电。 板 B 的串口应该开始刷:

纯文本
收到来自:AA:BB:CC:DD:EE:FF
→ 报警!

灯亮半秒、蜂鸣器响半秒,一秒一次。

成了。这就是两块板子隔空说话。

你可以走两步试试。 拿到隔壁房间,看看还响不响。空旷处厂家标称能到几十甚至上百米,但你家有墙——能穿一两道墙就不错了。到底多远,你自己实测一遍,这个数字是你自己测出来的,比任何参数表都靠谱。

收不到?按这个顺序查

ESP-NOW 出问题,现象比联网课还干净:什么都没发生。 所以更得按顺序来。

① 先看两边串口。 板 A 那边在刷"已发出"吗?板 B 那边有没有动静?

  • 板 A 都没在发 → 问题在板 A,先别管板 B
  • 板 A 在发,板 B 没收到 → 往下走

② 一个字符一个字符核对 MAC 地址。 在数组里写的顺序是 {0xAA, 0xBB, 0xCC, ...}照抄串口打印的顺序,一位都不能差。少一位、错一位、0x 漏了——都不报错,就是不通。 这是最常见的失败原因,没有之一

③ 确认两块板子烧的不是同一个程序。 板 B 的串口里有没有打印 我的 MAC:?有的话,它是接收端,对的。板 A 那边不应该打印 MAC——如果你两边都打印了,说明你烧混了。

④ 确认两块板子都没连路由器。 这一步很反直觉,但很重要:ESP-NOW 和 WiFi 用同一个无线电,得在同一个信道上。 你要是让一块板子连了你家 WiFi、另一块没连,它俩可能根本不在一个频道上。

最省事的做法:两块都别连路由器。 刚才的代码里我们只 WiFi.mode(WIFI_STA)没调 WiFi.begin(),就是故意的——两块板子都在默认信道上,一定能碰上。

⑤ 拔了重插,串口重开。 听起来很蠢,但**"板子没复位"这种问题真的存在**。两块板子同时断电、重新上电,很多时候就通了。

⑥ 最后再怀疑代码。 改一个地方,测一次。别一口气改五处——这条跟第 23 课是同一个规矩。

五、这东西能干嘛

我给你几个真实场景,你感受一下:

野外。 山里、地里、渔船上——那儿根本没有 WiFi。 你想让几十米外的传感器把数据传回来,ESP-NOW 就是最省事的办法。

地下室、车库、老房子。 信号差、穿墙难、路由器够不着。但两块板子之间隔个十来米,直连没问题。

一屋子的设备。 一个遥控器板子,同时给十几个灯板子发指令。用广播地址(FF:FF:FF:FF:FF:FF)一句话全收到,比挨个点名快得多。

你要记住一个事实:很多实际场景里,"没有网络"才是常态。

我们在教室里用 WiFi 用得太顺手,容易产生一种错觉——觉得哪儿都有网。 但你真去干点活就会发现:地下车库没信号、大棚里没信号、船上没信号。这时候,"不依赖网络的通信"就不是炫技,是刚需。

顺便说个反直觉的点:ESP-NOW 其实比 WiFi 省电得多。 因为它不用跟路由器保持连接、不用"入网"那一套握手,发完就睡。 你要是用电池供电,这个差别很大。

自测

单选题ESP-NOW 和前面几节课的联网方式,最大的区别是什么?
单选题板 A 在串口里一直刷"已发出:1",板 B 什么反应都没有。最该先查什么?
单选题为什么这节课建议两块板子都不要连路由器?
问答题为什么这节课的程序,两块板子不能烧一样的?
拓展一块板子能不能同时给好几块板子发消息?广播是怎么做到的?

这个问题课上不讲,留给你自己找答案——**问 AI 是最好的办法**。

提示:搜"ESP-NOW 广播地址 FF:FF:FF:FF:FF:FF"、"esp_now_add_peer 群发"。想一想:如果广播是"喊一嗓子谁都能听见",那安全吗?——你的指令会不会被别人的板子收走?

拓展为什么 ESP-NOW 比一直连着 WiFi 省电那么多?

这个问题课上不讲,留给你自己找答案——**问 AI 是最好的办法**。

提示:搜"ESP-NOW 低功耗 唤醒"、"WiFi 省电模式 DTIM"。想一想:"保持连接"这件事本身就是耗电的——你得一直听着路由器说话,生怕漏了一句。ESP-NOW 发完就睡,这个差别在电池供电的设备上有多大?

本节你要动手做的事

  • [ ] 先确认你有两块板子。没有的话,这节课可以跳过(真的不影响后面的课
  • [ ] 两块板子各烧一遍"读 MAC"的程序,把自己的 MAC 抄在纸上——这一步不能跳
  • [ ] 板 B 接好 LED(GPIO3)和蜂鸣器(GPIO4
  • [ ] 把板 B 的 MAC 填进板 A 的代码里,一个字符一个字符核对
  • [ ] 烧两份不同的程序:板 A 当探测器,板 B 当报警器
  • [ ] 看着灯亮、蜂鸣器响——两块板子隔空说话,通了
  • [ ] 拿着板子走两步,走到隔壁房间,看多远还响——这个距离是你自己测出来的
  • [ ] 故意把 MAC 的最后一位改错,跑一遍,看看是什么现象——下次真写错时你就能认出来

这节课你多花了几十块钱。 我不说"很值"这种空话,我说两个事实:

第一,你已经做出了一个不依赖任何外部设施的通信系统。 没有路由器、没有服务器、没有互联网——断电重来一遍,它照样能用。 世界上很多真正在干活的设备,就是这么工作的。

第二,你现在有"两头"了。 一块板子只能自言自语,两块板子就能互相触发。"探测器"和"报警器"分开放在两个地方——这个结构,你后面做项目会一直用。

下一节我们换一种无线:不用第二块板子,用你的手机。

而且我要先给你破个误解——关于蓝牙,你脑子里想的那个,多半是错的。