实战课题
第 27 课:红外感应灯
手一凑近就亮,拿开等几秒才灭——一个装在纸皮底座上的近场感应灯
我是吴老师。这节课的第一个字,是"泼冷水"。
上一课结尾我打过预防针,现在正式说:
这个红外感应灯,做不到"人走过来就自动亮"。
我知道你脑子里的画面是什么——你走进房间,灯"啪"地亮了;你一走,灯灭了。 商场、酒店、楼道,都是这个效果。
但你手上这个模块做不到。 不是代码写得不好,不是接线不对,是它的物理原理就不支持。
第 14 课我把这件事掰开讲过:它是红外反射式的——发一束红外光出去,看有没有光弹回来。它的有效距离只有几厘米。
几厘米是什么概念? 你把手掌摊开,从远处慢慢往模块跟前凑——凑到大概一拳的距离,它才"看见"你。
看这张图,两行对比一下:
| 红外反射(你手上这个) | 人体红外 PIR(商场那个) | |
|---|---|---|
| 靠什么工作 | 发一束光,看反不反射 | 感受人体发出的热量 |
| 能探多远 | 几厘米 | 几米 |
| 分得清人吗 | 分不清,纸箱、书本、你的手都一样 | 分得出(人体温度和墙不一样) |
看第二行那个差距。 差了一百倍。
所以这一课,我们先认清这个模块的"能力边界",再决定拿它做什么。
第 14 课结尾我说过:新手最容易犯的错,不是写错代码,是选错了零件,然后花一整天去调试一个物理上就不可能实现的东西。
把你想做的效果,跟你手里的零件对一遍——这是这个课题教你的第一件事。
一、那它能做什么
它能做"手一凑近就亮"的灯。
想想这个场景你熟不熟:
- 晚上回家,摸黑找钥匙孔 / 玄关柜上的开关
- 半夜起来,想看一下床头柜上的药盒,又不想开大灯
- 书桌下面太暗,手伸过去就有一盏灯亮
- 衣柜门一开,里面的灯亮
共同点是什么? 都是**"手边几十厘米以内"**的事。这正是红外模块的地盘。
我们做的东西长这样:一个纸皮底座上立着红外模块,旁边一颗 LED。你把手往模块前面一伸(大概 5 厘米),灯亮;手拿开,过 3 秒它自己灭。
为什么要"过 3 秒"才灭? 如果手一拿开马上灭,你找东西的时候得一直举着手——那是折磨,不是产品。
"保持 3 秒"是这个课题里最像"产品"的地方,第五节专门讲。
二、这个课题的三个环节
| 环节 | 这个课题里是什么 | 具体到引脚 |
|---|---|---|
| 传感器(看) | 红外模块,一直在问"前面有没有东西" | 读 GPIO4(数字量) |
| 判断(想) | 板子比一下:看见了吗?上次看见是多久以前? | if 加一个时间判断 |
| 执行器(做) | LED 模块,亮或者灭 | 写 GPIO3 |
注意第一行那三个字:数字量。
第 14 课的重点就是这个——红外是"门卫",不是"体温计"。它只回答"有 / 没有",读它用 digitalRead,得到的是 HIGH 或 LOW。
所以它接的是 OUT。
这里我得拦你一下,因为上一个课题留下的习惯会害你。
你刚做完小夜灯,手上那个光敏模块是四个针:
AODOGNDVCC。所以你可能下意识地在红外模块上找AO。红外模块只有三个针:
OUTGNDVCC。 没有AO,也没有DO。它只有一个输出,而且那个输出是数字的。别照搬上一个模块的接法。 拿到一个新模块,第一件事是看它板上印的是哪几个字——这是第 4 课那句"丝印是厂家随便印的,功能是芯片定死的"的实战版。
三、材料清单
套件里拿这些:
| 元件 | 数量 | 干什么用 |
|---|---|---|
| ESP32-C3 主控 + 拓展板 | 1 | 大脑 |
| 红外传感器模块 | 1 | 感知前面有没有东西 |
| LED 灯模块 | 1 | 发光 |
| 母对母杜邦线 | 6 根 | 接线 |
身边自己准备:
| 东西 | 干什么用 |
|---|---|
| 快递纸皮 | 做底座(三块) |
| 剪刀 / 美工刀 | 裁纸皮 |
| 热熔胶枪 + 胶棒 | 粘 |
| 尺子 + 铅笔 | 量尺寸 |
四、接线
先断电。 这句话我每节课都说,因为这节课第一个坑就跟"电"有关。
| 红外模块 | 接到 |
|---|---|
| VCC | 3.3V(看清是 3.3V 那一排,不是别处) |
| GND | GND |
OUT |
GPIO4(数字引脚) |
| LED 灯模块 | 接到 |
|---|---|
| VCC | 3.3V |
| GND | GND |
Signal |
GPIO3 |
为什么 OUT 用 GPIO4? 因为第 14 课用的就是这个脚,跟你按钮那节课是同一个脚。这不是巧合——红外和按钮是同一类东西,都是"数字输入",都是门卫。
拓展板上那几排针,插之前拿眼睛对一下丝印。 那几排挨得很近,
3.3V、5V、GND挤在一起,母对母的线头又都是塑料壳。这是下一个坑的伏笔,先记住这句话。
五、分步实现
第 1 步:先看它"看见"没有
最丑的版本,只有读取和打印:
void setup() {
Serial.begin(115200);
pinMode(4, INPUT);
}
void loop() {
Serial.println(digitalRead(4));
delay(100);
}烧进去,打开串口。先看模块板上那个小指示灯(第 14 课说过,检测到东西的时候它会变)。
然后把手掌从远处慢慢往模块跟前凑。
凑到某个距离,你会看到两件事同时发生:
- 模块板上的小指示灯变了
- 串口里的数字也跳了
记下两件事:
- 大概几厘米的时候它才认?(多半是 3~8 厘米)
- "有东西"的时候数字是 1 还是 0?
第二件事必须你自己测,别背。
第 14 课我就强调过:方向以你实测为准。 我手上这块是"有东西 = 0",你那块可能一样,也可能不一样。唯一可靠的办法是拿手挡一下看数字怎么变。
下面的代码我按"有东西 = 低电平"写。如果你量出来是反的,就把
LOW改成HIGH。 这是第 5 课那句"先测,再猜"。
第 2 步:看见了就亮
void setup() {
Serial.begin(115200);
pinMode(4, INPUT);
pinMode(3, OUTPUT);
}
void loop() {
int seen = digitalRead(4); // 1. 读
if (seen == LOW) { // 2. 判断(方向以你实测为准)
digitalWrite(3, HIGH); // 3. 亮
} else {
digitalWrite(3, LOW); // 手拿开就灭
}
}烧进去。手凑近——灯亮;手拿开——灯立刻灭。
好玩吧? 但你先别急着做底座,试一下你就知道它有多难用了:
手拿开的那一瞬间,灯就灭了。也就是说,你想照一下抽屉,得一直把手举在模块前面。
这不是产品,这是个玩具。 下一步我们把它变成产品。
第 3 步:让它"记住刚才看见过"
我们要的效果是:手拿开之后,灯再亮 3 秒。
怎么做到?板子得知道"现在几点了"。
这里要用一个新东西:millis()。
millis()是"板子从开机到现在,过了多少毫秒"。它就是一个一直在往前走的数:开机时是 0,过一秒钟变成 1000,过一分钟变成 60000。它只会变大,不会回头,也不会自己归零。
你拿它当秒表用就行。 不用
delay是因为——delay会让板子卡在那儿干等,等的这段时间它什么都看不见。我们要的是"一边等一边继续看"。
unsigned long lastSeen = 0; // 最后一次"看见东西"是几点
void setup() {
Serial.begin(115200);
pinMode(4, INPUT);
pinMode(3, OUTPUT);
}
void loop() {
if (digitalRead(4) == LOW) { // 现在看见了
lastSeen = millis(); // 那就把"此刻"记下来
}
// 距离上次看见,还没过 3000 毫秒(3 秒)?
if (millis() - lastSeen < 3000) {
digitalWrite(3, HIGH); // 那就还亮着
} else {
digitalWrite(3, LOW); // 超过 3 秒了,灭
}
}烧进去。手凑近——亮。手拿开——它还亮着。数三下,它灭了。
现在它像个东西了。
两个小提醒:
- 开机后头 3 秒它会亮一下。 因为
lastSeen一开始是 0,板子以为"刚看见过东西"。这是正常的,别慌。3000这个数你自己改。 改成 1000 就是"亮 1 秒",改成 10000 就是"亮 10 秒"。找东西的话,3~5 秒比较舒服。
第 4 步:拧那个蓝色小电位器
这一步是动手,不是读代码。
模块板上有一个蓝色的小十字电位器——第 14 课讲过,它调的是接收头的灵敏度,也就是"能看多远"。
现在拿一张纸片,固定在离模块大概 5 厘米的地方。然后慢慢拧。
你会看到:
- 往一个方向拧 → 更灵敏,5 厘米的纸片它认了,甚至 10 厘米也认
- 往另一个方向拧 → 更迟钝,纸片得贴到 2 厘米它才认
你拧的不是一个抽象参数,你拧的是这个模块的"视力"。
拧到一个你满意的位置: 手伸过来大概 5 厘米就亮,但旁边桌上放个杯子它不会乱触发。
第 14 课结尾我提醒过一句:拧完记得拧回去,别拧到极端。
为什么?因为拧到极端(要么太灵要么太钝),后面的实验会莫名其妙地不工作,而你已经忘了是你自己拧的。
今天这盏灯,你拧完就别再动了。 拿铅笔在电位器旁边画一个小记号,记下你定在哪——这样下次它"失灵"了,你能一眼看出来是不是被碰过了。
这跟第 11 课的标定、第 14 课的拧电位器,是同一件事:参数得在你的实际环境里调出来,抄不来。
第 5 步:调成你自己的
到这一步,这个作品就基本成型了。你有两个参数可以调:
| 参数 | 在哪 | 效果 |
|---|---|---|
| 灵敏度 | 板上那个蓝色电位器(手动拧) | 手要凑多近才触发 |
| 保持时间 | 代码里的 3000 |
手拿开之后还亮几秒 |
两个都试一遍,找到你最舒服的组合。 这个"调到自己满意"的过程,就是这个作品真正变成"你的"的过程。
六、组装:纸皮底座
目标:让模块"脸朝前"立起来,前面还不能有东西挡着。
第 1 步,裁三块纸皮:
| 编号 | 尺寸 | 干什么 |
|---|---|---|
| ① | 10cm × 8cm | 底板(放桌上) |
| ② | 8cm × 6cm | 立板(模块粘它前面) |
| ③ | 4cm × 6cm | 三角撑(防止往后倒) |
第 2 步,先把三块摆一摆。 别急着上胶——摆一下确认尺寸对得上,纸皮剪短了可补不回来。
第 3 步,粘立板。 把②竖着放在①靠后的位置,底下挤一条热熔胶,按住十几秒。
按住的时候别松手。 热熔胶十几秒就凝,但没凝之前它会滑。你一松手,立板就歪了,干了之后掰不回来(一掰纸皮就毛)。
第 4 步,粘三角撑。 把③竖着贴在立板后面,两条直角边各挤一点胶——一条粘在立板背面,一条粘在底板上。
这一块是整个底座最关键的零件。 没有它,你手一伸过去,模块往后一倒。三角形是最稳的形状(下一课搭冰棒棍支架还要用这个道理)。
第 5 步,粘模块。 在立板朝前那一面挤一小坨胶,把红外模块按上去,两个"眼睛"朝外。
胶点在模块板子的边缘,尤其别糊到那个透明的发射管——它被胶盖住,光就发不出去了。
模块也别粘得太靠下。 粘在立板上半部分,让它的"眼睛"离桌面高一点,免得桌面反光把它晃到(第 14 课讲过,环境光会干扰它)。
第 6 步,等胶干,再通电。 线从底座后面绕出去,插到板子上。做完放到桌上,手一伸——亮了。
这时候你再回头看那句"它做不到人走过来自动亮",是不是就不难受了?
它做到的是另一件事:手边几十厘米的"我看得见你"。 这件事,商场那个 PIR 反而做不到——PIR 站远了才灵,凑近了它反而瞎。
七、排查:如果它一动不动
这一段是这节课最值钱的部分。
你做完了,通电了,结果模块完全没反应:板上的小指示灯不动,串口里的数字一直是同一个值,手凑上去它也不理你。
先别改代码。 代码你刚才跑通过,它大概率没问题。
按下面这个顺序来。
第一步:先看那个小指示灯
凑近看模块板上那个小指示灯。
注意:第 14 课提醒过,不同批次的板子,灯的数量和亮灭规律可能不一样。 如果你那块板上压根没有小灯,直接跳到第二步。
但"完全不亮、完全不动"这件事本身是线索——这个小灯是模块自己驱动的,它不亮,多半说明模块压根没吃到电。
第二步:量模块的电源
万用表拨直流电压档(V⎓)。先短接两支表笔确认表是好的。
- 黑表笔搭拓展板上的
GND - 红表笔搭红外模块上的
VCC针
读数是多少?
- 3.3V 左右 → 模块有电,问题不在供电,去查信号线(跳到后面"如果不是电源"那段)
- 0V → 模块确实没吃到电。往下走。
第三步:顺着这根线往上找
红表笔挪到 VCC 这根线的另一头——插在拓展板上的那一端。注意扎在金属上,不是塑料壳上(母对母的线头是个塑料方块,你得把表笔尖从侧面伸进去顶到里面的金属)。
读数是多少?
- 还是 0V → 问题不在线上,在它插的那个位置。再量一下拓展板上标着
3.3V的那一排针:如果是 3.3V,那板子的电是好的,问题就锁定在"这根线插在哪儿"。 - 如果是 3.3V → 那这根线是好的,问题在模块这头的接触(拔下来重插一次)
第四步:用通断档,把"线坏了"和"插错了"分开
万用表拨通断档()))),先短接表笔听一声"嘀"确认表是好的。
一支表笔搭这根线在模块那一头,另一支搭它在拓展板上那一头。
听到"嘀"了。 说明这根线本身是好的——内部没断。
好,那就只剩一个可能:它插的那个位置不对。
第五步:看一眼它到底插在哪
眼睛顺着这根线看,它插进了拓展板的哪一排。
你会看到——它插在标着 GND 的那一排里。
找到了。
根因
VCC 那根线的另一头,插到了 GND 那一排。
模块的电源和地都接到了"地"上——它等于没接电源。 而所有线看上去都插得好好的,没有一根是悬空的,这就是它骗过你的地方。
拔出来,看清丝印,插回 3.3V。通电——小灯亮了,手一凑,串口数字就跳了。
这个坑,是我在这个课题里故意留的。
为什么选它?因为第 4 课那张表你可能扫过一眼就过了——拓展板上
3.3V、5V、GND三排针挤在一起,母对母的线头又都是塑料方块。 那节课我说过"接线前先找GND认准地"。今天你就是那个没认准的人。 不丢人——丢人的是量都不量,直接换个模块试。
再捋一遍这套排查顺序,它比这个具体的坑重要一百倍:
| 顺序 | 干什么 | 想确认什么 |
|---|---|---|
| 1 | 看模块上的指示灯 | 模块自己觉得它有电吗 |
| 2 | 量模块 VCC 对 GND | 模块到底有没有电 |
| 3 | 量这根线的另一头 | 电有没有送到线的这一端 |
| 4 | 量板子上真正的 3.3V 针 | 电源本身是好的吗 |
| 5 | 通断档量这根线的两头 | 是线坏了,还是插错了 |
| 6 | 看它插在哪个孔里 | 定位到根因 |
注意第 5 步。
"线内部断了"和"线插错位置了",症状一模一样,都是"没反应"。 但这两个的修法完全不同:一个是换线,一个是拔出来重插。
通断档那一"嘀",就是把它俩分开的那一刀。 这也是为什么第 4 课第一件事就是教你们验线——手上有一根坏线,会让后面每一次排查都多绕一圈。
自测
答案与解析
别掉进"代码不够好"这个坑——这是最常见的错误归因。它就几厘米的探测距离,你代码写出花来也变不出几米。能做到"人走到门口自动亮"的是 PIR(人体红外),它靠感受人体发出的热量工作,能探几米。这是两个物理原理完全不同的东西,不是同一件事调调参数。 顺带说:模块用 3.3V 供电就行,这个干扰项是拿电源知识来迷惑你的。
答案与解析
delay(3000) 是个陷阱——它会把板子卡死三秒,这三秒里板子什么都不看、什么都不听,结果就是"手明明伸过去了它却没反应"。正确做法是 millis() 加一个 lastSeen 变量:一边等,一边继续看。而拧电位器调的是"能看多远",跟"亮多久"一点关系都没有——那是两个完全不同的参数,别混。
答案与解析
记住那个总原则:先看电,再看线,再看信号,最后才改代码。 干扰项里"换个模块试"就是典型的碰运气——换了能亮你也不知道为什么,下次照样卡住。通断档那一步特别关键:它能把"线内部断了"和"线插错位置了"分开——这两个症状一模一样,但修法完全不同。
millis() 之后的版本好在哪?答题要点
答题要点应该包含:传感器是红外模块(读 GPIO4,数字量 HIGH/LOW,问的是"前面有没有东西");判断是"digitalRead(4) 是不是低电平"加上"millis() - lastSeen 是不是小于 3000";执行器是 LED(写 GPIO3)。好在哪:① 人不用一直举着手,"手一拿开就灭"是玩具,"拿走还亮几秒"才是能用的东西;② millis() 是非阻塞的——它不会像 delay 那样把板子卡住,板子在"等待"的这几秒里还在继续看,所以手再伸过去能立刻响应。这就是"作品"和"演示"的差别。
拓展手机接电话的时候,你一贴到耳朵边,屏幕就自己黑了。是哪个传感器在干活?它跟这个红外模块是什么关系?
这个问题课上不讲,留给你自己找答案——**问 AI 是最好的办法**。
提示:搜"手机 距离传感器 proximity sensor 原理"。想一想:手机屏幕那么大,为什么这个传感器只要管"几厘米"就够了?它和我们的红外模块,是不是同一类东西?
拓展那如果想做真正的"人走过来自动亮",该怎么办?
这个问题课上不讲,留给你自己找答案——**问 AI 是最好的办法**。
提示:搜"HC-SR501 人体红外 PIR 模块 接线"。想一想:PIR 能探几米,但它有个脾气——人站着不动它就不认了,为什么?(提示:它感受的是"热量变化"。)那商场里的自动门,是怎么做到人站着不动门也不关的?
本节你要动手做的事
- [ ] 亲手验证它的边界:手从远处慢慢凑近,记下它几厘米才认你——这个数你要记一辈子
- [ ] 接好线:红外
VCC→3.3V(看清丝印)、GND→GND、OUT→GPIO4,LEDSignal→GPIO3 - [ ] 跑通"看见就亮",顺便确认方向:是有东西为
LOW还是HIGH - [ ] 加上
millis()保持 3 秒,自己改数值,找到最舒服的那个 - [ ] 拧电位器:固定一张纸片在 5 厘米处,左右拧,亲眼看探测距离被拉长、缩短,然后用铅笔做个小记号
- [ ] 做出底座:裁三块纸皮(10×8 / 8×6 / 4×6),粘成 L 形
- [ ] 跑一遍第五步那个排查表,就算没坏也走一遍——手熟比什么都强
- [ ] 做完自测题
这节课你做的是一个"只有几厘米视野"的灯。
但我希望你带走的东西,比这个灯大得多。
你先知道了它做不到什么,然后才决定拿它做什么。 这个顺序,跟大多数人是反的。多数人是先想好一个效果,然后硬往上套零件,套不上就怀疑自己——"是不是我代码写错了?"
不是你写错了。是那个方案本来就不成立。
以后每拿到一个新模块,先问自己两句话:"它到底在测什么?它的物理极限在哪?" 想清楚这两句,能省你一整天。
还有一件事——你今天第一次用了 millis()。 它看起来只是"记个时间",但它背后是一个特别重要的思路:板子不用停下来等,它可以一边干活一边等。 这个思路,在你后面做联网、做多任务的时候,会反复出现。
下一课我们做倒车雷达——"嘀……嘀……嘀嘀嘀嘀嘀!" 那个声音越急、离墙越近的东西。
那一课你要同时指挥三个模块:超声波测距、蜂鸣器发声、LED 闪。而且你会遇到一个新问题——超声波读出来的数会跳,而蜂鸣器可不会替你忍着。