模块熟悉

第 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 课一模一样:

C++
void setup() {
  Serial.begin(115200);
}

void loop() {
  Serial.println(analogRead(0));    // 读 GPIO0 上的模拟值
  delay(200);
}

烧进去,打开串口监视器,然后用手遮住那个小圆片、再拿开

你会看到数字在变。

现在做一件重要的事:记下两个数。

  1. 手完全遮住的时候,读数大概是多少?
  2. 室内光线下(不遮),读数大概是多少?

把这两个数写在你的笔记里。 下一节要用它们。

现在你应该能看出来一件事:这个读数是"没单位"的。

它不是"多少勒克斯",也不是"多少瓦",它只是一个 0~4095 之间的相对数值。同一块模块,在这个房间读 3000,搬到另一个房间可能读 2000——两个房间可能一样亮。

记住这一点,它决定了下一节的内容。

四、从"读数"到"判断":阈值

到现在为止,你只是到了一个数。但你要做的是让它做点什么——比如"天黑了就开灯"。

问题来了:多少算"天黑了"?

板子不知道。它只知道一个数字。 你得告诉它一条线:

比这条线小,就算黑。

这条线就叫阈值

阈值就是自己画的一条线,读数高于它算亮,低于它算暗

代码上是这样:

C++
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 是从哪来的? 是我随手编的。在你那里能不能用,取决于你的环境。

正确做法:标定

正确流程只有三步:

  1. 先跑一遍,在你的实际使用环境里读
  2. 遮住、拿开,看读数的最小值和最大值分别是多少
  3. 在中间取一个值当阈值

这叫"标定"(calibration)——听着挺专业,其实就是**"先测一遍,再定参数"**。

比如你在自己桌上测出来:亮的时候 3200,遮住的时候 800。

那阈值就取中间偏一点——比如 1800。这样"亮"和"暗"能明确分开,而且留有余量,不会因为光线稍微变一点就乱跳。

这比抄任何教程上的数字都靠谱。

还记得第 5 课那句话吗——"先测,再猜"。这节课的标定,就是它在模拟输入上的应用。

六、它最适合做什么

光敏的经典应用就是光控——天黑了自动开灯、天亮了自动关灯。路灯就是这个原理。

我们后面第 26 课的实战课题,就是做一个"光控小夜灯"——用今天学的东西,加上纸皮做个灯罩,做成一个能拿回家的东西。

不过在那之前,你得先把这个模块摸熟。

有个实际问题你迟早会碰到:读数在"临界点"附近会来回跳。

比如你的阈值定在 1800,而现在的光线刚好让它读 1795、1805、1798、1803……灯就会疯狂闪烁。

解决办法叫"迟滞"——开灯的阈值和关灯的阈值定得不一样:比如低于 1500 才开灯,高于 2500 才关灯,中间留一段"就算变了也不动"。这个技巧在你做小夜灯的时候会用到。

自测

单选题光敏模块上 AODO 两个输出,有什么区别?
单选题为什么阈值不能照搬教程里的数字?
问答题什么是"标定"?为什么它比抄别人的参数更靠谱?
拓展光敏电阻为什么"光越强电阻越小"?它在物理上发生了什么?

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

提示:搜"光敏电阻 原理 光电导效应"、"硫化镉 光敏"。想一想:光照射上去,材料内部的电子发生了什么变化?

拓展为什么读数在阈值附近会来回跳?除了"迟滞",还有别的办法吗?

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

提示:搜"迟滞 比较器 抖动"、"滑动平均 滤波"。想一想:如果你把最近 10 次的读数取平均再判断,会不会稳一些?代价是什么?

本节你要动手做的事

  • [ ] 接好光敏VCC3.3VGNDGNDAO→ 一个模拟引脚(注意是 AO 不是 DO
  • [ ] 跑通读数:遮住手、拿开手,确认变化方向(是光强时数字大,还是反的)
  • [ ] 记下你的两个数:完全遮住的读数、室内光下的读数——这两个数是你标定的依据
  • [ ] 做个光控灯:用 if 判断,让它"暗了就亮"——阈值用你自己测出来的
  • [ ] 试试用万用表量 AO 脚的电压,遮住和拿开时各是多少?跟读数对得上吗(读数 ÷ 4095 × 3.3 ≈ 电压)

这节课的知识点很少:读一个模拟值、和阈值比一比。

但有个习惯我希望你带走:标定。

"先测,再定"——这四个字,是硬件工程里最朴素、也最有用的原则。

别人给你一个参数,你的第一反应不该是"直接用",而是"他在什么条件下测的?我的条件一样吗?"

这个习惯,在你后面做热敏(要换算温度)、做麦克风(要定响度阈值)、甚至做联网(要填 WiFi 名字密码)的时候,都会用到。

下一节我们学热敏传感器——它跟光敏长得一样、接线一样、代码几乎一样。唯一的区别是:读出来的数,不能直接用。