← 返回传感器图鉴

光敏电阻 LDR

最后更新 2026-06-20
⏱ 约 5 分钟 🟢 软件/低风险
🛒 器材清单
器材数量参考
光敏电阻1
10kΩ 电阻1

价格随渠道波动,以购买页实时为准。

想做一个"天黑了自动亮、天亮了自动灭"的小夜灯,第一个问题是:怎么让单片机知道现在是亮还是暗?最便宜的答案,就是一颗光敏电阻——几毛钱一颗,配一个电阻、占用 ESP32 一个模拟引脚,就能感知明暗。它不像专门的光照芯片那样给你标准的 lux 数值,但要做"有光/没光"这种开关判断,便宜又够用。

工作原理

光敏电阻(LDR,Light Dependent Resistor)的材料常是硫化镉这类光敏半导体。它的特性一句话概括:光越强,阻值越小;光越暗,阻值越大。在全黑环境里它可能高达几百千欧甚至兆欧级,被强光照射时能掉到几百欧到几千欧。

问题在于:它是个电阻,本身不输出电压,单片机的 ADC 只会读电压、不会直接读电阻。所以要把"阻值变化"翻译成"电压变化"。办法就是经典的分压电路——拿一个固定的 10kΩ 电阻和它串联,从中间引一根线出来:

  • 光敏电阻在上、固定电阻在下时,光变强 → LDR 阻值变小 → 它分掉的电压变少 → 中间点电压升高
  • 反过来接,方向就相反。

中间这个分压点的电压,就随光强连续变化。ESP32 用 ADC 把这个电压采样成一个数字(模拟与数字的区别),数值大小就反映了当前光强。这是最朴素、也最省钱的光感方案。

接线

经典分压接法,固定电阻取 10kΩ(普通环境下比较均衡):

3.3V ── 光敏电阻 ──┬── 10kΩ ── GND
                   │
                ADC 引脚(如 GPIO34)
元件 一端接 另一端接
光敏电阻 3.3V 分压点(ADC 引脚)
10kΩ 固定电阻 分压点(ADC 引脚) GND
ESP32 ADC 引脚 分压点 ——

ESP32 选输入引脚有讲究:用 ADC1 的脚(GPIO3239 这一组),别用 ADC2 的脚(GPIO0、2、4、1215、2527 等),因为 ADC2 在 Wi-Fi 开启时会被占用、读不出来。GPIO3439 还是纯输入脚,正好适合做传感器输入。这里用 GPIO34。

完整代码

下面这段在 ESP32 上读 LDR 分压点的原始 ADC 值,并把它打到串口,方便边遮边看数:

const int LDR_PIN = 34;   // 接分压点的 ADC1 引脚

void setup() {
  Serial.begin(115200);
  // ESP32 ADC 衰减设置:默认量程偏小,会在高电压区"撞顶"。
  // ADC_11db 把可测范围拉到约 0~3.3V,覆盖整个分压区间。
  analogSetPinAttenuation(LDR_PIN, ADC_11db);
}

void loop() {
  int raw = analogRead(LDR_PIN);  // 12 位 ADC,原始值范围 0~4095
  Serial.print("LDR raw = ");
  Serial.println(raw);
  delay(300);
}

几个要点:

  • analogRead 返回 0~4095,因为 ESP32 的 ADC 是 12 位(2 的 12 次方 = 4096 个台阶)。
  • analogSetPinAttenuation(..., ADC_11db) 是最容易被忽略的一行。不设衰减时,ESP32 默认能测的电压范围偏窄,光强一变化电压一高就"顶满"在 4095 不动了。设成 11db 才能覆盖到接近 3.3V 的范围。
  • 这里只读原始值、不换算 lux,因为 LDR 给不了准确的 lux(原因见下文标定一节)。

你应该看到什么

打开串口监视器(波特率 115200),盯着不停滚动的 LDR raw 数字,做两个动作:

  • 用手把光敏电阻完全遮住:数值往一个方向明显变化(按上面的接法,遮光时 LDR 阻值变大、分压点电压降低,读数变小)。
  • 拿手机手电筒照它:数值往反方向大幅变化(照光时 LDR 阻值变小、读数变大)。

只要遮和照之间数字有清晰、可重复的差距(比如室内从 1200 跳到 3000),接线就是对的。如果数字纹丝不动,或者只在某个值附近抖一两个数,那就是没接对——往下看故障排查。

标定与读数解读

最关键的一点:LDR 给的是"相对值",不是标准 lux。同一颗 LDR 换个固定电阻、换个接法、甚至换个房间,读数都不一样。所以不存在"网上抄一个阈值直接用",必须自己在你的实际环境里标定:

  1. 把项目放在它将来真实工作的位置(床头、窗边等)。
  2. 模拟"暗"的状态(关灯/遮光),记下这时的 raw 值,比如 800。
  3. 模拟"亮"的状态(开灯/白天),记下 raw 值,比如 2800。
  4. 取中间偏一点作为阈值,比如 1600,写进判断逻辑:"低于 1600 算暗、高于算亮"。

读数方向也要先确认清楚:按本页接法是"越亮读数越大",但只要把 LDR 和固定电阻上下对调,方向就反过来。先用串口看清自己这套是哪个方向,再写 if,别凭想象。

📌 说明

ESP32 的 ADC 还有非线性问题——读数和真实电压不是一条完美直线,尤其在两端附近会偏。做"明暗开关"这种粗判断完全不影响;但别指望用原始值反推出精确光照强度,那不是 LDR + ESP32 ADC 该干的活。

选型 / 避坑

🚧 避坑

LDR 只给相对值,必须自己实测标定阈值:遮住读一次、照亮读一次,取中间。换电阻、换环境都要重标。另外 ESP32 ADC 一定记得设衰减(ADC_11db)并用 ADC1 引脚,否则要么读数撞顶在 4095,要么开 Wi-Fi 后直接读不出来。

要直接拿到标准 lux 数值、要精度,别用 LDR,换数字的 BH1750——它走 I2C,直接吐出 lux,省去标定。

LDR 的价值在另一头:

  • 便宜,几毛钱一颗,配一个电阻就能用。
  • 接线极简单,一个模拟引脚搞定。
  • 响应特性适合做"有光/没光"这种开关式判断,不追求读数精确。

一句话取舍:要"读出多亮"用 BH1750,要"判断亮不亮"用 LDR。更多模拟传感器的读法见 L4 传感器与 AI

故障排查

现象 可能原因 怎么查
读数完全不变(一直 0 或一直 4095) ADC 引脚没接到分压点,或固定电阻、LDR 有一个没接好 万用表量分压点对 GND 电压,应随遮光/照光变化
读数总在某个值附近抖、遮照都没反应 引脚悬空,或接到了非 ADC 引脚 确认接的是 GPIO34~39 这类 ADC1 引脚
遮光读数反而变大 LDR 和固定电阻上下接反了 不一定是错,确认方向后照实际写 if 即可
开 Wi-Fi 后读数变乱/读不出 用了 ADC2 引脚(被 Wi-Fi 占用) 改用 ADC1 引脚(GPIO32~39)
强光下数值顶满 4095 不动 没设 ADC 衰减,量程不够 analogSetPinAttenuation(pin, ADC_11db)

进阶 / 变体

光控开关加滞回:直接用单一阈值判断,会在临界光线附近反复横跳(灯一闪一闪)。做法是设两个阈值——低于 1400 才"判暗开灯"、高于 1800 才"判亮关灯",中间这段保持不动。这种"滞回"能挡掉抖动,让小夜灯切换得干脆。

双 LDR 循迹:给小车底部装两颗 LDR,分别对着地面左右两侧。黑线吸光、白底反光,两颗读数会出现差值——哪边读数偏"暗"就说明那边压到黑线了,据此修正方向。这是最廉价的循迹方案。

典型应用

  • 光控小夜灯:天黑读数低于阈值自动点亮,配合滞回防止闪烁。
  • 循迹小车:双 LDR 对比左右地面反射,判断是否偏离黑线。
  • 光控玩具:盖上盒子(变暗)触发动作,揭开(变亮)停止,做互动机关。

小结

LDR 是"光越强阻值越小"的元件,配一个固定电阻组成分压电路,ESP32 用 ADC 读分压点电压就能感知明暗。它最大的特点是便宜、接线简单,但只给相对值、必须自己标定阈值,还要留意 ESP32 ADC 的衰减设置和引脚选择。要"判断亮不亮"它够用,要"读出多少 lux"请上 BH1750

相关:ADC 原理 · 分压电路 · 模拟与数字 · BH1750 光照传感器 · 更多传感器

参数以 datasheet 为准;本页公开资料整理,接线与代码请结合实物验证。

内容有错、看不懂、或想看下一期?告诉我们 →

本文为公开资料的学习整理,非亲测。涉接线/花钱/合规的步骤请结合实物与官方最新资料验证,风险自负。见免责声明