BH1750 数字光照传感器
| 器材 | 数量 | 参考 |
|---|---|---|
| BH1750 模块(GY-302) | 1 | — |
价格随渠道波动,以购买页实时为准。
想让屏幕背光随环境亮度自动调暗调亮,或者让阳台的补光灯在天阴下来时自动补光——第一步都是先知道"现在到底有多亮"。如果用光敏电阻(LDR),读出来是个 0~4095 之间的数,800 算亮还是 2000 算亮?换一颗电阻、换一块板子,这个数还会变,根本没法跨设备复用。
BH1750 解决的就是这件事:它直接吐给你一个带单位的数字——勒克斯(lux)。室内办公照度大概 300~500 lux,阴天户外 1000 lux,正午暴晒 10 万 lux,这些都是世界通用的标准值。读到 "350 lux",无论换哪块板子都是同一个亮度,背光阈值直接写死成数字就行。
工作原理
BH1750 内部是一颗对可见光敏感的光电二极管,它把照射进来的光强转换成微小的电流——光越强,电流越大。这股电流送进芯片内置的 ADC(模数转换) 变成数字量,再经过芯片内部按 datasheet 校准好的换算公式,直接算出对应的 lux 值,最后通过 I2C 总线交给单片机。
关键差别在"谁来换算":
- 光敏电阻 LDR:只是一个阻值随光变化的电阻。它给的是相对的模拟电压,要变成 lux 得自己拿照度计一点点标定,而且每颗电阻特性都有偏差,温度一变还会漂。详见 /sensor/ldr/。
- BH1750:换算这一步在芯片出厂时就标定好了,封装在内部。直接读出 lux,拿来即用,跨设备一致,精度也高得多。
它对人眼可见光谱的响应做了拟合(接近人眼感受),所以测出来的 lux 和"人觉得亮不亮"比较吻合,特别适合做照度相关的自动控制。想深入看 I2C 和 ADC 的底层机制,参考 /principle/i2c/ 和 /principle/adc/。
接线
BH1750(GY-302 模块)板载稳压,VCC 接 3.3V 即可,I2C 走 SDA/SCL 两根线。ADDR 引脚决定芯片在总线上的地址:
| BH1750 | ESP32 | 说明 |
|---|---|---|
| VCC | 3.3V | 模块自带稳压,接 3.3V 最稳 |
| GND | GND | 公共地 |
| SDA | GPIO21 | I2C 数据线 |
| SCL | GPIO22 | I2C 时钟线 |
| ADDR | 接 GND | 地址 = 0x23(默认) |
| ADDR | 接 VCC | 地址 = 0x5C |
GY-302 模块上 SDA/SCL 通常已带上拉电阻,多数情况下不用额外加。如果总线上挂了多个设备或读不到数据,可在 SDA、SCL 各接一颗 4.7kΩ 上拉到 3.3V,原理见 /principle/pullup/。
ADDR 引脚是用来在同一条 I2C 总线上挂两颗 BH1750 的:一颗 ADDR 接地走 0x23,另一颗 ADDR 接高电平走 0x5C,互不冲突。
完整代码
用现成的 BH1750 库(Arduino 库管理器里搜 "BH1750",claws/BH1750 这个最常用),几行就能跑:
#include <Wire.h>
#include <BH1750.h>
// 默认地址 0x23(ADDR 接地);若 ADDR 接高电平改成 0x5C
BH1750 lightMeter(0x23);
void setup() {
Serial.begin(115200);
Wire.begin(21, 22); // ESP32 指定 SDA=21, SCL=22
// 连续高分辨率模式:分辨率 1 lx,约 120ms 一次测量
if (lightMeter.begin(BH1750::CONTINUOUS_HIGH_RES_MODE)) {
Serial.println("BH1750 已就绪");
} else {
Serial.println("BH1750 初始化失败,检查接线和地址(0x23/0x5C)");
}
}
void loop() {
float lux = lightMeter.readLightLevel(); // 直接读出 lux,无需换算
Serial.print("光照: ");
Serial.print(lux);
Serial.println(" lux");
delay(1000);
}
CONTINUOUS_HIGH_RES_MODE 是连续高分辨率模式,分辨率 1 lx、一次测量约 120ms,是最常用的档位。库还提供 HIGH_RES_MODE_2(0.5 lx,弱光更细腻)和 LOW_RES_MODE(4 lx,更快),按需要选。readLightLevel() 返回的就是 lux 浮点值,不用任何标定换算。
你应该看到什么
打开串口监视器(115200 波特率),正常情况下每秒打印一行:
BH1750 已就绪
光照: 312.50 lux
光照: 318.33 lux
光照: 45.00 lux ← 用手挡住传感器开窗
光照: 1583.00 lux ← 拿手机手电筒照
拿手挡住、用手电筒照、走到窗边,数值会明显跟着变。对照一下:手机手电直射近处能轻松冲到几千甚至上万 lux,遮住后掉到几十 lux,这就说明传感器工作正常。
读数解读
BH1750 的量程约 1 ~ 65535 lux,覆盖从夜晚到烈日的绝大多数场景。常见环境对照:
| 场景 | 大致照度(lux) |
|---|---|
| 满月夜晚 | 约 1 |
| 路灯下的夜街 | 5 ~ 20 |
| 室内一般照明 | 100 ~ 300 |
| 办公室/教室 | 300 ~ 500 |
| 阴天的室外 | 1000 ~ 2000 |
| 日出日落时分 | 400 ~ 1000 |
| 晴天阴影处 | 10000 ~ 20000 |
| 正午直射阳光 | 50000 ~ 100000+ |
定阈值时拿这张表当参考:做室内自动背光,把"暗"判到 200 lux 以下、"亮"判到 500 lux 以上,留一段缓冲带避免在临界点反复跳变(这叫迟滞,控制里很常用)。
选型 / 避坑
| 需求 | 选谁 | 理由 |
|---|---|---|
| 直接读 lux、要精度、跨设备一致 | BH1750 | 内部已校准,数字输出 |
| 只要"亮/暗"相对判断、极致便宜 | 光敏电阻 LDR | 几毛钱,但要自己标定、会漂,见 /sensor/ldr/ |
| 要识别颜色(RGB)/ 色温 | TCS34725 | 带 RGB+Clear 四通道,能算颜色 |
I2C 扫不到设备:先确认地址——ADDR 接地是 0x23,接高电平是 0x5C,库里地址填错就 begin 失败。再查 SDA/SCL 有没有接反、上拉是否到位。可以先跑一个 I2C 扫描程序看总线上到底出现哪个地址。
读数饱和/卡在最大值:强光(比如正午阳光、激光笔)超过量程时读数会顶到 65535 附近不再变化。这不是坏,是超量程了。需要测强光场景可改用低分辨率模式或加遮光/减光片。
进阶 / 变体
自动背光控制:把 lux 映射到 PWM 占空比。环境越暗、屏幕背光越低(省电又护眼),越亮则调高保证可读。加迟滞和平滑滤波(取最近几次的平均),避免人影一晃就闪屏。
植物补光阈值控制:设定一条目标照度线,比如多肉需要全天累计足够光照。当实测 lux 低于阈值(阴天、傍晚)就开补光灯,高于阈值就关。进阶可以累加每天的光照"时间×强度"做光照积分,更接近植物真实需求。
自动窗帘:清晨 lux 上升到设定值自动拉开窗帘,正午过强时半闭遮光,傍晚关闭。配合时间判断能避免阴天误动作。
想把这类"传感器读数 → 自动决策"做成一个完整闭环项目,配合 OLED 显示和 AI 辅助开发,参考 /guide/l2-oled/ 和 /guide/l4-sensor-ai/。
典型应用
- 屏幕/灯具自动调光(手机、电视、智能台灯都靠它)
- 智能窗帘按光照自动开合
- 植物补光灯的开关与时长控制
- 室内照度记录、考勤教室照明达标检测
- 摄影测光、环境光数据采集
小结 · 相关
BH1750 的核心价值是"直接给你带单位的标准 lux",省掉了光敏电阻必须自己标定的麻烦,精度高、跨设备一致,量程从月光覆盖到烈日。接线就是 I2C 四线加一个决定地址的 ADDR,代码用 BH1750 库三五行搞定。做任何"亮度自动控制"的项目,它都是首选。
相关阅读:/sensor/ldr/(便宜的相对方案)、/principle/i2c/、/principle/adc/、/principle/pullup/、/guide/l4-sensor-ai/,更多器件见 /sensor/ 与 /principle/、/guide/。
参数以 datasheet 为准;本页公开资料整理,接线与代码请结合实物验证。