模块熟悉
第 11 课:光敏传感器——光线有多亮
用手一遮,数字立刻变。模拟输入里最直观的一个
我是吴老师。这节课的模块,是模拟输入里最直观的一个。
为什么这么说?因为按钮你得按、电位器你得拧,而光敏——你只要把手往上一放。
遮住、拿开、遮住、拿开——数字跟着变,因果关系一眼就能看见。
这种"立刻能看到结果"的东西,特别适合用来建立信心。所以我把光敏排在模拟传感器的第一个。
一、先认识它
光敏模块跟麦克风、热敏长得几乎一样——都是四根针,都是 AO DO GND VCC。
所以先认清楚你手上的是哪个。 第 4 课讲过怎么分:看顶上那个元件。
- 光敏:一个有花纹的小圆片(光敏电阻)
- 热敏:一个玻璃珠一样的 NTC
- 麦克风:一个圆形的金属咪头
三个模块丝印完全一样,拿混了不会烧,但读出来的数完全没有意义——而且很难发现,因为程序照样在跑。
接线:四根线,只用一根
| 针脚 | 作用 | 我们用它吗 |
|---|---|---|
AO |
模拟输出,光越强数值越大 | ✅ 用这个 |
DO |
数字输出,比某个亮度亮/暗才翻转 | ❌ 本课不用 |
| GND | 地 | ✅ |
| VCC | 电源 | ✅ |
接线:
| 光敏 | 接到 |
|---|---|
| VCC | 3.3V |
| GND | GND |
AO |
一个模拟引脚(GPIO0 ~ GPIO5) |
注意是 AO,不是 DO。 接错的话,你读到的就只有 0 和 1 两种值了——不是不能用,但那不是"光有多亮",而是"比某个亮度高还是低",信息量差远了。
DO那个"门槛"是靠板上那个蓝色小电位器拧的,不太精确,而且拧了之后你自己都记不住定在哪。我们直接用AO读数,在代码里判断,灵活得多。
二、原理:光在改变电阻
第 10 课讲过电位器:内部是两个电阻分压,你转旋钮改比例,中间点电压就变。
光敏是一模一样的结构,唯一的区别是——
改变电阻的不是你的手,是光。
光敏电阻的这个特性:光越强,电阻越小。
| 光照 | 光敏电阻的阻值 | 分压点的电压 | 读到的数 |
|---|---|---|---|
| 很亮 | 小 | 高 | 大 |
| 很暗 | 大 | 低 | 小 |
注意这个方向:光越强,读数越大。
但这个方向不一定绝对。 它取决于模块内部怎么接的——理论上厂家也可以接成反的。
所以别背"亮 = 大"或"亮 = 小",跑一遍看看实际是哪个方向。 这就是第 5 课那句"先测,再猜"。
好在你手上的模块大概率是"亮 = 大",但你自己验证一遍只需要十秒钟。
三、读出来看看
代码跟第 10 课一模一样:
void setup() {
Serial.begin(115200);
}
void loop() {
Serial.println(analogRead(0)); // 读 GPIO0 上的模拟值
delay(200);
}烧进去,打开串口监视器,然后用手遮住那个小圆片、再拿开。
你会看到数字在变。
现在做一件重要的事:记下两个数。
- 手完全遮住的时候,读数大概是多少?
- 室内光线下(不遮),读数大概是多少?
把这两个数写在你的笔记里。 下一节要用它们。
现在你应该能看出来一件事:这个读数是"没单位"的。
它不是"多少勒克斯",也不是"多少瓦",它只是一个 0~4095 之间的相对数值。同一块模块,在这个房间读 3000,搬到另一个房间可能读 2000——两个房间可能一样亮。
记住这一点,它决定了下一节的内容。
四、从"读数"到"判断":阈值
到现在为止,你只是读到了一个数。但你要做的是让它做点什么——比如"天黑了就开灯"。
问题来了:多少算"天黑了"?
板子不知道。它只知道一个数字。 你得告诉它一条线:
比这条线小,就算黑。
这条线就叫阈值。
代码上是这样:
void loop() {
int light = analogRead(0);
if (light < 2000) { // 比 2000 小 = 天黑了
digitalWrite(3, HIGH); // 开灯
} else {
digitalWrite(3, LOW); // 关灯
}
}看,还是那个闭环:传感器(读光敏)→ 判断(比阈值)→ 执行器(开灯)。
结构跟第 9 课的"按钮点灯"一模一样,只是把按钮换成了光敏、把"按下没按下"换成了"比 2000 大还是小"。
这就是我一直在说的:换的是零件,骨架没变。
五、那个 2000 是哪来的
我要专门讲这个问题,因为它暴露了初学者最常见的一个错误。
上面代码里我写了 2000。这个数不能抄。
为什么?看这张图:
同一块光敏模块,在不同的环境里,读数的范围完全不同。
| 使用环境 | 实际读数范围 |
|---|---|
| 窗边(很亮) | 2800 ~ 3900 |
| 室内(适中) | 1200 ~ 2400 |
| 抽屉里(很暗) | 100 ~ 600 |
现在看看那根"抄来的阈值 2000"会发生什么:
- 在窗边:所有读数都在 2000 以上 → 程序永远判定为"亮",灯永远不亮。你做的是个"天黑开灯",结果它是个死灯。
- 在抽屉里:所有读数都在 2000 以下 → 程序永远判定为"暗",灯永远亮着,白白耗电。
- 只有在"室内"那种环境下,范围刚好跨过阈值,它才正常工作。
所以那个 2000 是从哪来的? 是我随手编的。在你那里能不能用,取决于你的环境。
正确做法:标定
正确流程只有三步:
- 先跑一遍,在你的实际使用环境里读
- 遮住、拿开,看读数的最小值和最大值分别是多少
- 在中间取一个值当阈值
这叫"标定"(calibration)——听着挺专业,其实就是**"先测一遍,再定参数"**。
比如你在自己桌上测出来:亮的时候 3200,遮住的时候 800。
那阈值就取中间偏一点——比如 1800。这样"亮"和"暗"能明确分开,而且留有余量,不会因为光线稍微变一点就乱跳。
这比抄任何教程上的数字都靠谱。
还记得第 5 课那句话吗——"先测,再猜"。这节课的标定,就是它在模拟输入上的应用。
六、它最适合做什么
光敏的经典应用就是光控——天黑了自动开灯、天亮了自动关灯。路灯就是这个原理。
我们后面第 26 课的实战课题,就是做一个"光控小夜灯"——用今天学的东西,加上纸皮做个灯罩,做成一个能拿回家的东西。
不过在那之前,你得先把这个模块摸熟。
有个实际问题你迟早会碰到:读数在"临界点"附近会来回跳。
比如你的阈值定在 1800,而现在的光线刚好让它读 1795、1805、1798、1803……灯就会疯狂闪烁。
解决办法叫"迟滞"——开灯的阈值和关灯的阈值定得不一样:比如低于 1500 才开灯,高于 2500 才关灯,中间留一段"就算变了也不动"。这个技巧在你做小夜灯的时候会用到。
自测
AO 和 DO 两个输出,有什么区别?答案与解析
AO(Analog Output)给你一个 0~4095 的连续值,能反映"到底多亮";DO(Digital Output)只告诉你"比某个亮度亮还是暗",就是 0 和 1。DO 的门槛靠板上那个蓝色小电位器拧,拧了之后你自己都记不住定在哪,所以我们在代码里判断更灵活。
答案与解析
同一块光敏,在窗边可能读 3000 以上,在抽屉里可能只读 500。教程作者是在他的环境里定的那个数,搬到你的环境里可能完全不适用——要么永远触发,要么永远不触发,而且从现象上看不出是阈值的问题。正确做法:先在自己的使用环境里跑一遍,看实际范围再定。
答题要点
答题要点应该包含:标定就是"先测量、再定参数"——拿光敏来说,就是先在自己的使用环境里跑一遍,看遮住和拿开时读数分别是多少,然后在中间取阈值。为什么更靠谱:因为读数是环境相关的,别人的数字是在别人的环境里得出的,不一定适用于你;而标定得到的是你自己的传感器、在你的环境里的真实数据。这个思路(先测再定)在硬件里到处都用,比如后面热敏的温度换算、麦克风的响度阈值,都要标定。
拓展光敏电阻为什么"光越强电阻越小"?它在物理上发生了什么?
这个问题课上不讲,留给你自己找答案——**问 AI 是最好的办法**。
提示:搜"光敏电阻 原理 光电导效应"、"硫化镉 光敏"。想一想:光照射上去,材料内部的电子发生了什么变化?
拓展为什么读数在阈值附近会来回跳?除了"迟滞",还有别的办法吗?
这个问题课上不讲,留给你自己找答案——**问 AI 是最好的办法**。
提示:搜"迟滞 比较器 抖动"、"滑动平均 滤波"。想一想:如果你把最近 10 次的读数取平均再判断,会不会稳一些?代价是什么?
本节你要动手做的事
- [ ] 接好光敏:
VCC→3.3V,GND→GND,AO→ 一个模拟引脚(注意是AO不是DO) - [ ] 跑通读数:遮住手、拿开手,确认变化方向(是光强时数字大,还是反的)
- [ ] 记下你的两个数:完全遮住的读数、室内光下的读数——这两个数是你标定的依据
- [ ] 做个光控灯:用
if判断,让它"暗了就亮"——阈值用你自己测出来的 - [ ] 试试用万用表量
AO脚的电压,遮住和拿开时各是多少?跟读数对得上吗(读数 ÷ 4095 × 3.3 ≈ 电压)
这节课的知识点很少:读一个模拟值、和阈值比一比。
但有个习惯我希望你带走:标定。
"先测,再定"——这四个字,是硬件工程里最朴素、也最有用的原则。
别人给你一个参数,你的第一反应不该是"直接用",而是"他在什么条件下测的?我的条件一样吗?"
这个习惯,在你后面做热敏(要换算温度)、做麦克风(要定响度阈值)、甚至做联网(要填 WiFi 名字密码)的时候,都会用到。
下一节我们学热敏传感器——它跟光敏长得一样、接线一样、代码几乎一样。唯一的区别是:读出来的数,不能直接用。