跳转到内容

光照传感器集成

光照传感器集成

本节介绍如何在 ESP32 中集成 BH1750 光照传感器,包括 I2C 配置、数据读取和代码实现。学习完成后,您将能够:

  • 理解 I2C 通信协议的基本原理
  • 安装和配置 BH1750 库
  • 编写光照强度读取代码
  • 处理多 I2C 设备的共存问题

在开始本节之前,请确保:

  • 已完成硬件接线
  • 了解 I2C 通信的基本概念(地址、SDA、SCL)
  • 已完成 DHT22 传感器集成
  • 已安装 PlatformIO 或 Arduino IDE

I2C(Inter-Integrated Circuit)是一种同步、多主从的串行通信协议,由 Philips 在 1982 年开发。

特点

  • 仅需两根线:SDA(数据线)和 SCL(时钟线)
  • 支持多个设备和多个主机
  • 每个设备有唯一地址(7 位或 10 位)
  • 速度标准模式 100kHz,快速模式 400kHz

在 IoT 中的应用

  • 连接传感器(BH1750、BME280、MPU6050)
  • 连接显示模块(OLED SSD1306、LCD1602)
  • 连接 ADC/DAC 扩展芯片

ESP32 有两组 I2C 控制器,默认引脚如下:

信号默认引脚可配置引脚
SDAGPIO 21任意 GPIO
SCLGPIO 22任意 GPIO

ESP32 的优势在于所有 GPIO 都可作为 I2C 引脚,这提供了极大的布线灵活性。

1. 打开 工具 → 管理库
2. 搜索 "BH1750" by Christopher Laws
3. 安装最新版本
; platformio.ini
[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
monitor_speed = 115200
lib_deps =
adafruit/DHT sensor library@^1.4.4
adafruit/Adafruit Unified Sensor@^1.1.9
claws/BH1750@^1.3.0
#include <Wire.h>
#include <BH1750.h>
BH1750 lightMeter; // 创建 BH1750 对象
void setup() {
Serial.begin(115200);
Wire.begin(); // 初始化 I2C 总线
lightMeter.begin(); // 初始化 BH1750
Serial.println("BH1750 Light Sensor Test");
Serial.println("------------------------");
}
void loop() {
float lux = lightMeter.readLightLevel();
Serial.print("Light: ");
Serial.print(lux);
Serial.print(" lux");
// 添加描述性标签
if (lux < 50) {
Serial.println(" (Dim / Indoor)");
} else if (lux < 500) {
Serial.println(" (Normal Office)");
} else if (lux < 1000) {
Serial.println(" (Bright Office)");
} else if (lux < 10000) {
Serial.println(" (Overcast Outdoor)");
} else {
Serial.println(" (Direct Sunlight)");
}
delay(1000); // BH1750 支持更快的采样率
}
#include <Wire.h>
#include <BH1750.h>
BH1750 lightMeter; // 默认模式:连续高分辨率模式
void setup() {
Serial.begin(115200);
Wire.begin();
// 配置 BH1750 模式
// 可选模式:
// - BH1750_CONTINUOUS_HIGH_RES_MODE: 连续高分辨率模式 (1 lux 精度)
// - BH1750_CONTINUOUS_HIGH_RES_MODE_2: 连续高分辨率模式2 (0.5 lux 精度)
// - BH1750_CONTINUOUS_LOW_RES_MODE: 连续低分辨率模式 (4 lux 精度, 更快)
// - BH1750_ONE_TIME_HIGH_RES_MODE: 单次高分辨率模式 (省电)
if (lightMeter.begin(BH1750_CONTINUOUS_HIGH_RES_MODE)) {
Serial.println("BH1750 initialized successfully");
} else {
Serial.println("Error: BH1750 not found!");
while (1); // 停止执行
}
}
void loop() {
float lux = lightMeter.readLightLevel();
if (lux < 0) {
Serial.println("Error reading BH1750!");
} else {
Serial.print("Brightness: ");
Serial.print(lux, 1);
Serial.println(" lux");
}
delay(2000);
}

BH1750 有两种可能的 I2C 地址:

#include <Wire.h>
#include <BH1750.h>
// ADDR 引脚接 GND → 地址 0x23 (默认)
BH1750 lightMeter1;
// ADDR 引脚接 VCC → 地址 0x5C
BH1750 lightMeter2;
void setup() {
Serial.begin(115200);
Wire.begin();
// 使用自定义地址初始化
lightMeter1.begin(BH1750_ONE_TIME_HIGH_RES_MODE, 0x23);
lightMeter2.begin(BH1750_ONE_TIME_HIGH_RES_MODE, 0x5C);
Serial.println("Two BH1750 sensors initialized");
}
void loop() {
// 读取第一个传感器
float lux1 = lightMeter1.readLightLevel();
delay(150); // 切换传感器间的短暂延迟
// 读取第二个传感器
float lux2 = lightMeter2.readLightLevel();
Serial.print("Sensor 1 (0x23): ");
Serial.print(lux1, 1);
Serial.print(" lux, Sensor 2 (0x5C): ");
Serial.print(lux2, 1);
Serial.println(" lux");
delay(2000);
}

在调试或添加新 I2C 设备时,使用此代码扫描所有连接的 I2C 设备:

#include <Wire.h>
void setup() {
Serial.begin(115200);
Wire.begin();
Serial.println("I2C Scanner");
}
void loop() {
byte error, address;
int deviceCount = 0;
Serial.println("Scanning I2C devices...");
for (address = 1; address < 127; address++) {
Wire.beginTransmission(address);
error = Wire.endTransmission();
if (error == 0) {
Serial.print("I2C device found at address 0x");
if (address < 16) Serial.print("0");
Serial.print(address, HEX);
Serial.println();
deviceCount++;
} else if (error == 4) {
Serial.print("Error at address 0x");
if (address < 16) Serial.print("0");
Serial.println(address, HEX);
}
}
if (deviceCount == 0) {
Serial.println("No I2C devices found!");
} else {
Serial.print("Total: ");
Serial.print(deviceCount);
Serial.println(" device(s)");
}
Serial.println("--------------------");
delay(5000); // 每 5 秒扫描一次
}

将 DHT22 和 BH1750 集成到同一个项目中:

#include <Wire.h>
#include <BH1750.h>
#include <DHT.h>
// DHT22 配置
#define DHTPIN 4
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);
// BH1750 配置
BH1750 lightMeter;
// 传感器数据结构
struct EnvironmentData {
float temperature;
float humidity;
float lux;
unsigned long timestamp;
};
void setup() {
Serial.begin(115200);
// 初始化 I2C 总线
Wire.begin();
// 初始化 DHT22
dht.begin();
// 初始化 BH1750
if (!lightMeter.begin()) {
Serial.println("BH1750 initialization failed!");
} else {
Serial.println("All sensors initialized");
}
}
void loop() {
EnvironmentData data;
data.timestamp = millis();
// 读取 DHT22
data.humidity = dht.readHumidity();
data.temperature = dht.readTemperature();
// 读取 BH1750
data.lux = lightMeter.readLightLevel();
// 检查传感器状态
bool dhtError = isnan(data.temperature) || isnan(data.humidity);
bool bh1750Error = (data.lux < 0);
if (dhtError) {
Serial.println("DHT22 read error");
}
if (bh1750Error) {
Serial.println("BH1750 read error");
}
if (!dhtError && !bh1750Error) {
// 构建 JSON 格式输出
Serial.print("{\"temp\":");
Serial.print(data.temperature, 1);
Serial.print(",\"hum\":");
Serial.print(data.humidity, 1);
Serial.print(",\"lux\":");
Serial.print(data.lux, 0);
Serial.println("}");
}
delay(3000); // 每 3 秒采集一次
}
Terminal window
# 使用 I2C 扫描确认 BH1750 已被识别

预期输出

I2C device found at address 0x23
Total: 1 device(s)

光照测试方法

测试条件预期 lux 值验证结果
完全遮盖传感器0-5 lux
室内自然光100-500 lux
日光灯下300-1000 lux
手机闪光灯照射1000-5000 lux
阳光直射10000-65000 lux

症状:读取返回 -1 或 I2C 扫描找不到设备

可能原因

  • I2C 地址错误
  • 供电不足
  • SDA/SCL 接线反接

解决方案

  1. 运行 I2C 扫描确认设备地址
  2. 检查供电电压(应为 3.3V)
  3. 交换 SDA 和 SCL 线缆

症状:相同光照条件下读数波动 > 20%

可能原因

  • 传感器窗口有污渍
  • I2C 总线噪声
  • 电源不稳定

解决方案

  1. 清洁传感器窗口
  2. 缩短 I2C 线缆长度
  3. 在 VCC 和 GND 间添加滤波电容

症状:单独测试正常,同时连接后 BH1750 读取异常

可能原因

  • I2C 总线与 DHT22 中断冲突
  • 间距过近导致电磁干扰

解决方案

  1. 在 I2C 线上添加 4.7kΩ 上拉电阻
  2. 将 DHT22 和 BH1750 分开一定距离
  3. 读取 DHT22 和 BH1750 之间添加短暂延时
  • 推荐: 对光照值进行滑动平均滤波(取最近 5 次读数的平均值)
  • 推荐: 根据环境选择合适的 BH1750 测量模式(室内用高分辨率,户外用低分辨率)
  • 推荐: 多传感器布局时避免遮挡
  • 避免: 传感器放置在窗口正对阳光的位置(会导致读数饱和)
  • 避免: I2C 总线长度超过 50cm(信号衰减)
  • 避免: 在同一个 I2C 总线上连接过多设备(超过 5-8 个建议添加多路复用器)

本节要点总结:

  1. BH1750 光照传感器:I2C 接口,地址 0x23(默认)或 0x5C
  2. 测量范围:1-65535 lux,覆盖从黑暗到阳光直射的广泛应用场景
  3. 多种模式:连续/单次、高/低分辨率模式可选
  4. 集成要点:使用 Wire 库初始化 I2C 总线,调用 readLightLevel() 获取数据
  5. I2C 调试:使用 I2C 扫描工具快速排查设备连接问题