光照传感器 BH1750 自动调光系统:智能节能照明实战

为什么需要自动调光?

你有没有过这样的经历:晚上躺在床上玩手机,屏幕亮度太高刺得眼睛疼;或者白天在办公室里,显示器亮度太低看不清?

固定亮度的照明设备其实很不人性化。环境光变化时,我们需要手动调节——但大多数人根本懒得这么做。结果就是:要么太亮费电又刺眼,要么太暗伤眼睛。

今天我们要做的,就是一个能"看懂"环境亮度的智能调光系统。它使用 BH1750 数字光照传感器,实时检测周围光线强度,自动调节 LED 或屏幕亮度。

这个项目适合用在:

  • 智能台灯
  • 显示器自动背光调节
  • 手机/平板环境光适配
  • 智能家居照明系统

BH1750 传感器简介

BH1750 是一款数字型光照传感器,来自罗姆半导体(ROHM)。相比模拟光敏电阻,它有这些优势:

特性 BH1750 光敏电阻
输出类型 数字 I2C 模拟电压
测量范围 1-65535 Lux 依赖电路设计
精度 ±20% 较差
波长响应 接近人眼 不一致
校准 出厂校准 需要手动校准
价格 约 3-5 元 约 0.5-1 元

BH1750 的测量范围是 1-65535 Lux,覆盖了从黑暗室内(约 100 Lux)到晴朗户外(约 50000 Lux)的场景。

关键参数:

  • 工作电压:3.0-3.6V(部分模块带稳压,可接 5V)
  • 接口:I2C(默认地址 0x23,可切换到 0x5C)
  • 分辨率:16 位
  • 响应时间:最快 120ms

硬件清单

组件 型号 数量 单价 总价
光照传感器 BH1750FVI 模块 1 ¥4.5 ¥4.5
主控板 Arduino Nano 1 ¥12 ¥12
LED 灯珠 5mm 白光 LED 3 ¥0.3 ¥0.9
限流电阻 220Ω 3 ¥0.1 ¥0.3
面包板 400 孔 1 ¥5 ¥5
杜邦线 公对公 20cm 10 ¥0.2 ¥2
合计 ¥24.7

购买建议:淘宝搜索"BH1750 模块",选择带稳压和上拉电阻的版本,接线更简单。

电路连接

BH1750 使用 I2C 接口,只需要 4 根线:

BH1750 Arduino Nano
VCC 5V(模块带稳压)
GND GND
SCL A5(I2C 时钟)
SDA A4(I2C 数据)

LED 连接(以 3 颗 LED 为例):

  • LED 正极 → 数字引脚 D9(PWM)→ 220Ω电阻 → LED 负极 → GND

接线图说明:

BH1750          Arduino Nano
┌────────┐      ┌────────────┐
│   VCC  │──────│   5V       │
│   GND  │──────│   GND      │
│   SCL  │──────│   A5       │
│   SDA  │──────│   A4       │
└────────┘      └────────────┘

LED (通过 220Ω电阻)
┌────────┐      ┌────────────┐
│   +    │──────│   D9 (PWM) │
│   -    │──────│   GND      │
└────────┘      └────────────┘

代码实现

1. 安装依赖库

使用 Adafruit_BH1750 库,它比原始 I2C 读写更方便:

# Arduino IDE 中搜索 "BH1750" 安装
# 或手动下载:https://github.com/claws/BH1750

2. 完整代码

#include 
#include 

// 定义引脚
#define LED_PIN 9

// 创建传感器对象
BH1750 lightSensor;

// 调光参数
const int MIN_LUX = 50;      // 最低光照阈值(暗环境)
const int MAX_LUX = 1000;    // 最高光照阈值(亮环境)
const int PWM_MIN = 30;      // 最低亮度(避免完全熄灭)
const int PWM_MAX = 255;     // 最高亮度

// 平滑滤波
float smoothedLux = 0;
const float ALPHA = 0.3;     // 滤波系数(0.1-0.5,越小越平滑)

void setup() {
  Serial.begin(9600);

  // 初始化 LED
  pinMode(LED_PIN, OUTPUT);

  // 初始化传感器
  if (lightSensor.begin(BH1750::CONTINUOUS_HIGH_RES_MODE, 0x23)) {
    Serial.println(F("BH1750 初始化成功"));
  } else {
    Serial.println(F("BH1750 初始化失败,检查接线!"));
    while (1);
  }

  // 设置测量时间(68ms 默认,可调整)
  lightSensor.setMeasurementTime(BH1750::MT_69MS);
}

void loop() {
  // 读取光照值
  if (lightSensor.hasValue()) {
    float lux = lightSensor.readLightLevel();

    // 指数移动平均滤波
    smoothedLux = ALPHA * lux + (1 - ALPHA) * smoothedLux;

    // 计算 PWM 值(映射到亮度范围)
    int pwmValue = calculatePWM(smoothedLux);

    // 输出到 LED
    analogWrite(LED_PIN, pwmValue);

    // 串口调试输出
    Serial.print("光照:");
    Serial.print(smoothedLux);
    Serial.print(" Lux | PWM: ");
    Serial.println(pwmValue);
  }

  delay(200);  // 200ms 采样间隔
}

// 根据光照计算 PWM 值
int calculatePWM(float lux) {
  // 限制在有效范围内
  lux = constrain(lux, MIN_LUX, MAX_LUX);

  // 线性映射:光照越强,LED 越亮
  // 注意:人眼对亮度感知是对数的,这里用线性简化
  int pwm = map(lux, MIN_LUX, MAX_LUX, PWM_MIN, PWM_MAX);

  return constrain(pwm, PWM_MIN, PWM_MAX);
}

3. 代码解析

关键部分说明:

  1. 测量模式选择

    • CONTINUOUS_HIGH_RES_MODE:连续高分辨率模式(1 Lux 精度)
    • CONTINUOUS_HIGH_RES_MODE_2:更高分辨率(0.5 Lux)
    • CONTINUOUS_LOW_RES_MODE:低分辨率但更快(4ms)
  2. 平滑滤波
    使用指数移动平均(EMA)滤波,避免亮度跳变:

    smoothedLux = ALPHA * lux + (1 - ALPHA) * smoothedLux;

    ALPHA 越小,变化越平滑,但响应越慢。

  3. 亮度映射
    使用 map() 函数将光照值映射到 PWM 范围。注意人眼对亮度的感知是对数的,如果需要更自然的调光效果,可以用对数映射:

    // 对数映射(更自然)
    float logLux = log10(lux);
    float logMin = log10(MIN_LUX);
    float logMax = log10(MAX_LUX);
    int pwm = map(logLux * 100, logMin * 100, logMax * 100, PWM_MIN, PWM_MAX);

常见问题排查

问题 1:传感器返回 0 或固定值

可能原因:

  • 接线错误(SCL/SDA 接反)
  • I2C 地址不对(尝试 0x5C)
  • 上拉电阻缺失(模块应自带)

解决方法:

// I2C 扫描代码,查找传感器地址
#include 

void setup() {
  Serial.begin(9600);
  Wire.begin();

  Serial.println("I2C 扫描中...");
  for (byte addr = 1; addr < 127; addr++) {
    Wire.beginTransmission(addr);
    if (Wire.endTransmission() == 0) {
      Serial.print("找到设备,地址:0x");
      Serial.println(addr, HEX);
    }
  }
}

void loop() {}

问题 2:亮度变化不平滑

原因: 采样太快或滤波系数太大

解决:

  • 增加 delay() 时间到 500ms
  • 减小 ALPHA 系数到 0.1-0.2
  • 增加采样次数取平均:
    float readAverageLux() {
    float sum = 0;
    for (int i = 0; i < 5; i++) {
      sum += lightSensor.readLightLevel();
      delay(50);
    }
    return sum / 5;
    }

问题 3:LED 闪烁或抖动

原因: PWM 频率或电源问题

解决:

  • 检查电源是否稳定(加 100μF 电容)
  • 确保 LED 限流电阻正确(220Ω 适合 5V)
  • 避免共用电源导致压降

问题 4:测量值与环境不符

校准方法:

// 使用已知光源校准
// 手机 Lux 计 App 作为参考
float calibrationFactor = 1.0;  // 根据实测调整

float calibratedLux = lightSensor.readLightLevel() * calibrationFactor;

进阶扩展

1. 多通道调光

控制 RGB 三色灯,根据时间调整色温:

// 早晨:冷白光(高色温)
// 晚上:暖黄光(低色温)
void setWarmLight(int brightness) {
  analogWrite(LED_RED, brightness);
  analogWrite(LED_GREEN, brightness * 0.8);
  analogWrite(LED_BLUE, brightness * 0.5);
}

2. 加入手动覆盖

添加按钮,允许用户临时覆盖自动调光:

#define BUTTON_PIN 2
bool manualMode = false;

void checkButton() {
  if (digitalRead(BUTTON_PIN) == LOW) {
    manualMode = !manualMode;
    delay(200);  // 防抖
  }
}

3. 连接智能家居

通过 ESP8266/ESP32 将光照数据上传到 Home Assistant:

// ESP32 + BH1750 + MQTT
#include 
#include 

void publishLux(float lux) {
  char payload[10];
  dtostrf(lux, 4, 1, payload);
  mqttClient.publish("home/sensor/lux", payload);
}

实际应用场景

场景 1:智能台灯

  • 白天自动调亮,晚上自动调暗
  • 深夜保持最低亮度(30%),避免完全熄灭

场景 2:显示器背光

  • 配合电脑使用,根据房间亮度调整
  • 减少眼睛疲劳,节能 30-50%

场景 3:植物生长灯

  • 根据自然光补充光照
  • 保持植物接收恒定光照强度

场景 4:汽车仪表照明

  • 隧道进出自动调整
  • 避免突然变亮/变暗影响驾驶

成本与节能分析

成本: 硬件总成本约 25 元,量产可降至 15 元以内。

节能效果: 相比固定亮度照明,自动调光可节能 30-60%。以 10W LED 灯为例:

  • 固定亮度:10W × 8 小时 = 80Wh/天
  • 自动调光:平均 5W × 8 小时 = 40Wh/天
  • 年节省:(80-40) × 365 = 14.6 kWh

按电费 0.6 元/kWh 计算,单灯年节省约 8.8 元。大规模部署(如办公室 100 盏灯)年节省近 900 元。

总结

BH1750 自动调光系统是一个实用且低成本的项目。它解决了固定亮度照明的痛点,既能提升舒适度,又能节能。

核心要点回顾:

  1. BH1750 是数字 I2C 传感器,精度高、使用简单
  2. 使用平滑滤波避免亮度跳变
  3. 根据实际场景调整 MIN_LUX/MAX_LUX 阈值
  4. 可扩展为 RGB 色温调节或智能家居节点

动手试试吧,让你的照明设备真正"看懂"环境!

希望这篇博客文章对您有所帮助!