1. 光的强度(光照度)怎么表示?
Lux 是一个完整的英文单词,中文译为“勒克斯”。 它是国际单位制(SI)中光照度(Illuminance)的单位。
1.1 光照度的详细解释:
- Lux (lx) 衡量的是表面接收到的光通量密度。简单来说,就是有多少光“照射”在某个物体表面上。
- 定义:1 lux 等于 1 流明(lumen)的光通量均匀分布在 1 平方米(square meter)的面积上。即 $1 \text{ lx} = 1 \text{ lm/m}^2$。
1.2 区分“光照度”与“光强度”:
- 光照度 (Illuminance):单位是 Lux (lx)。指的是被照面接收到的光的多少。例如:你的书桌桌面有多亮。BH1750 传感器测量的就是这个值。
- 发光强度 (Luminous Intensity):单位是 坎德拉 (Candela, cd)。指的是光源本身在特定方向上发光的强弱。例如:手电筒灯泡有多亮。
1.3 词源:
- “Lux” 在拉丁语中直接意为“光”。
1.4 Lux(光照度)常见场景参考:
- 0.0001 lux:无月光的夜晚
- 2.50 lux:家庭浴室或走廊的照明
- 00 - 500 lux:办公室或教室的标准照明
- 10,000 - 25,000 lux:晴朗白天的室外(非直射阳光)
- 100,000 lux:正午直射阳光
2. BH1750 数据手册结构化摘要
2.1 典型应用与目标设备
- 智能手机、平板电脑:自动调节屏幕亮度
- LCD 电视、显示屏:背光控制
- 笔记本电脑:键盘背光控制
- 数码相机:曝光控制
- 智能家居:灯光自动调节
- 便携设备:GPS、PDA
2.2 核心参数
| 参数 | 规格 |
|---|---|
| 型号 | BH1750FVI |
| 制造商 | ROHM Semiconductor |
| 功能 | 数字环境光传感器(16位串行输出) |
| 测量范围 | 1 ~ 65535 lx(高分辨率模式) |
| 供电电压 (VCC) | 2.4V ~ 3.6V(建议 3.0V) |
| I2C 接口 | 标准/快速模式 (f/s Mode) |
| 功耗 | 测量时 120µA(典型值),断电模式 0.01µA |
| 封装 | WSOF6I (2.0mm × 2.5mm × 0.75mm) |
2.3 BH1750原理图怎么看?
- ADDR 连接了一个下拉电阻(R5),电阻阻值为 4.7kΩ。
- 另外,DVI 上接了一个上拉电阻(R1),阻值为 1kΩ(1000 欧姆)。
BH1750 原理图
如果无法预览,请点击 此处下载 BH1750FVI 数据手册 PDF 文件。
2.4 引脚定义 (6引脚封装)
| 引脚号 | 名称 | 功能 |
|---|---|---|
| 1 | VCC | 电源输入 (2.4V ~ 3.6V) |
| 2 | ADDR | I2C 地址选择。 接 GND → 地址 0x23 接 VCC → 地址 0x5C |
| 3 | GND | 接地 |
| 4 | SDA | I2C 数据线 |
| 5 | DVI | 复位 & I2C 参考电压。 上电后需至少 1µs 的低电平复位。 |
| 6 | SCL | I2C 时钟线 |
BH1750模块的引脚对应:
- 5脚模块,DVI未引出。
- 硬件上,ADDR已通过 R5 (4.7kΩ) 下拉到 GND → 地址固定为 0x23。
BH1750背视图
BH1750光照度传感器模块引脚丝印
BH1750接线图
2.5 I2C 地址
| ADDR 引脚状态 | 7位地址 | 写地址 | 读地址 |
|---|---|---|---|
| 接 GND (你模块的默认状态) | 0x23 (0100011) | 0x46 | 0x47 |
| 接 VCC | 0x5C (1011100) | 0xB8 | 0xB9 |
2.6 命令表 (Opcode)
| 命令 | 代码 (Hex) | 说明 |
|---|---|---|
| Power Down | 0x00 | 进入低功耗模式 |
| Power On | 0x01 | 从低功耗唤醒,等待测量 |
| Reset | 0x07 | 重置数据寄存器(清空之前的结果) |
| Continuously H-Resolution | 0x10 | 连续测量,1 lx 精度,120ms |
| Continuously H-Resolution 2 | 0x11 | 连续测量,0.5 lx 精度,120ms |
| Continuously L-Resolution | 0x13 | 连续测量,4 lx 精度,16ms |
| One Time H-Resolution | 0x20 | 单次测量,1 lx 精度,120ms,测量后自动进入 Power Down |
| One Time H-Resolution 2 | 0x21 | 单次测量,0.5 lx 精度,120ms,测量后自动进入 Power Down |
| One Time L-Resolution | 0x23 | 单次测量,4 lx 精度,16ms,测量后自动进入 Power Down |
2.7 电气特性 (VCC = 3.0V, Ta = 25°C)
| 参数 | 最小值 | 典型值 | 最大值 | 单位 |
|---|---|---|---|---|
| 工作电压 (VCC) | 2.4 | 3.0 | 3.6 | V |
| 测量电流 (Icc) | - | 120 | 190 | µA |
| 掉电电流 (Icc2) | - | 0.01 | 1.0 | µA |
| 测量精度 (S/A) | 0.96 | 1.2 | 1.44 | times |
| 测量时间 (H-Res) | - | 120 | 180 | ms |
| 分辨率 (H-Res) | - | 1 | - | lx |
| I2C 时钟频率 | - | - | 400 | kHz |
2.8 计算公式
C
uint16_t raw_data = (high_byte << 8) | low_byte;
float lux = raw_data / 1.2f;注意:高分辨率模式2 (0.5 lx) 时,计算公式为
lux = raw_data / 1.2f / 2。
2.9 关于 DVI 引脚的特别说明
虽然你的模块未引出 DVI 引脚,但根据数据手册:
- 引脚 5 (DVI) 是异步复位端:上电后,需让 DVI 保持至少 1µs 的低电平,才能完成内部寄存器复位。
- 手头上的模块设计:通过 R1 (1kΩ) 将 DVI 上拉到 VCC。这意味着硬件复位时序无法满足。
- 解决方案(软件复位):在初始化时发送 Reset 命令 (
0x07) 来模拟硬件复位。这已包含在上述提供的驱动代码中。
3. ESP32-S3的BH1750驱动代码(基于ESP-IDF)
3.1 ESP-IDF 编写 ESP32-S3 驱动 BH1750 获取光照度数据流程图

3.2 ESP-IDF 的 BH1750 驱动代码
C
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/i2c_master.h"
#include "esp_log.h"
static const char *TAG = "BH1750";
// =============================================
// 引脚与参数定义
// =============================================
#define I2C_MASTER_SCL_IO GPIO_NUM_16
#define I2C_MASTER_SDA_IO GPIO_NUM_17
#define I2C_MASTER_FREQ_HZ 100000
#define I2C_PORT I2C_NUM_0
// BH1750 地址(ADDR 接地)
#define BH1750_ADDR 0x23 // 7位地址
#define BH1750_WRITE_ADDR 0x46 // 写地址 (0x23 << 1)
#define BH1750_READ_ADDR 0x47 // 读地址 (0x23 << 1) | 1
// =============================================
// BH1750 命令定义
// =============================================
#define BH1750_CMD_POWER_ON 0x01 // 上电
#define BH1750_CMD_RESET 0x07 // 软复位
#define BH1750_CMD_ONE_TIME_H_RES 0x20 // 单次高分辨率模式 (1 lx, 120ms)
// =============================================
// 全局句柄
// =============================================
static i2c_master_bus_handle_t bus_handle;
static i2c_master_dev_handle_t dev_handle;
// =============================================
// I2C 初始化 & 设备探测
// =============================================
esp_err_t bh1750_init(void) {
// 1. 创建 I2C 总线
i2c_master_bus_config_t bus_cfg = {
.clk_source = I2C_CLK_SRC_DEFAULT,
.i2c_port = I2C_PORT,
.scl_io_num = I2C_MASTER_SCL_IO,
.sda_io_num = I2C_MASTER_SDA_IO,
.glitch_ignore_cnt = 7,
.flags.enable_internal_pullup = true,
};
ESP_ERROR_CHECK(i2c_new_master_bus(&bus_cfg, &bus_handle));
// 2. 探测设备是否在线
esp_err_t ret = i2c_master_probe(bus_handle, BH1750_ADDR, 1000 / portTICK_PERIOD_MS);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "BH1750 未找到 (地址 0x%02X)", BH1750_ADDR);
return ret;
}
ESP_LOGI(TAG, "BH1750 已找到 (地址 0x%02X)", BH1750_ADDR);
// 3. 添加设备到总线
i2c_device_config_t dev_cfg = {
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
.device_address = BH1750_ADDR,
.scl_speed_hz = I2C_MASTER_FREQ_HZ,
};
ESP_ERROR_CHECK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &dev_handle));
// 4. 软件复位(解决 DVI 上拉带来的复位问题)
uint8_t cmd = BH1750_CMD_RESET;
ret = i2c_master_transmit(dev_handle, &cmd, 1, 1000 / portTICK_PERIOD_MS);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "复位命令失败");
return ret;
}
vTaskDelay(pdMS_TO_TICKS(5));
// 5. 上电唤醒
cmd = BH1750_CMD_POWER_ON;
ret = i2c_master_transmit(dev_handle, &cmd, 1, 1000 / portTICK_PERIOD_MS);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Power On 命令失败");
return ret;
}
return ESP_OK;
}
// =============================================
// 单次测量(高分辨率模式)
// =============================================
esp_err_t bh1750_measure_once(float *lux) {
// 1. 发送测量命令
uint8_t cmd = BH1750_CMD_ONE_TIME_H_RES;
esp_err_t ret = i2c_master_transmit(dev_handle, &cmd, 1, 1000 / portTICK_PERIOD_MS);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "测量命令发送失败");
return ret;
}
// 2. 等待测量完成 (高分辨率模式需要 120-180ms)
vTaskDelay(pdMS_TO_TICKS(180));
// 3. 读取 2 字节数据
uint8_t data[2];
ret = i2c_master_receive(dev_handle, data, 2, 1000 / portTICK_PERIOD_MS);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "数据读取失败");
return ret;
}
// 4. 计算光照强度
uint16_t raw_data = (data[0] << 8) | data[1];
*lux = (float)raw_data / 1.2f;
return ESP_OK;
}
// =============================================
// 主程序
// =============================================
void app_main(void) {
ESP_LOGI(TAG, "BH1750 测试程序启动");
// 初始化 BH1750
if (bh1750_init() != ESP_OK) {
ESP_LOGE(TAG, "初始化失败,程序退出");
return;
}
// 主循环测量
while (1) {
float lux;
if (bh1750_measure_once(&lux) == ESP_OK) {
ESP_LOGI(TAG, "光照强度: %.2f lx", lux);
} else {
ESP_LOGE(TAG, "测量失败");
}
vTaskDelay(pdMS_TO_TICKS(2000)); // 每2秒测量一次
}
}