
目录
[1. 物理检测原理](#1. 物理检测原理)
[2. 通信方式](#2. 通信方式)
[4. 数据计算规则](#4. 数据计算规则)
前言
最近用到了STM32驱动BH1750光敏传感器模块,我这里用的STM32是STM32F407IGT6,这个模块的精度能达到±5%,所以记录一下
一、工作原理
BH1750 是一款低成本、高精度的数字型光照强度传感器,核心特点是无需外部 AD 转换,直接通过 I2C 输出数字量,以下是核心原理拆解:
1. 物理检测原理
BH1750 内部集成了对可见光敏感的光电二极管(光谱响应接近人眼),光电二极管将接收到的光信号转换为微弱的电流信号;内部运放对电流信号放大后,经 ADC 转换为数字信号,再通过内置的数字处理电路将信号转换为 16 位的光照数值,最终通过 I2C 接口输出。
2. 通信方式
- 采用I2C 串行通信 ,7 位从机地址有两种(由 ADDR 引脚决定):
- ADDR 接 GND:0x23(发送时需左移 1 位,实际写地址为 0x46,读地址为 0x47);
- ADDR 接 VCC:0x5C(发送时左移 1 位,写地址 0xB8,读地址 0xB9);
- 无需复杂的寄存器配置,仅需发送 "工作模式指令" 即可启动测量。
核心工作模式(常用)
| 模式 | 分辨率 | 测量时间 | 特点 |
|---|---|---|---|
| 连续高分辨率模式 | 1 lux | 120ms | 默认模式,持续测量 |
| 连续低分辨率模式 | 4 lux | 16ms | 速度快,精度低 |
| 单次高分辨率模式 | 1 lux | 120ms | 测量一次后进入低功耗 |
4. 数据计算规则
传感器输出的 16 位原始数据,除以 1.2 即为实际光照强度(单位:lux),公式:

二、接线方式
|-----|-----|
| VIN | 5V |
| GND | GND |
| SCL | PB6 |
| SDA | PB7 |
三、软件程序
头文件(bh1750.h)
#ifndef __BH1750_H
#define __BH1750_H
#include "stm32f1xx_hal.h"
// 配置BH1750的I2C句柄(根据自己的工程修改)
#define BH1750_I2C_HANDLE &hi2c1
// BH1750 I2C地址(ADDR接GND时用0x23,接VCC时用0x5C)
#define BH1750_ADDR 0x23
// BH1750 指令集
#define BH1750_POWER_DOWN 0x00 // 断电模式
#define BH1750_POWER_ON 0x01 // 上电模式
#define BH1750_RESET 0x07 // 重置数据寄存器
// 连续高分辨率模式(推荐)
#define BH1750_CONT_H_RES 0x10
// 连续低分辨率模式
#define BH1750_CONT_L_RES 0x13
// 单次高分辨率模式
#define BH1750_ONE_H_RES 0x20
// 函数声明
uint8_t BH1750_WriteCmd(uint8_t cmd); // 写指令到BH1750
uint8_t BH1750_ReadData(uint16_t *data); // 读取16位原始数据
void BH1750_Init(void); // BH1750初始化
float BH1750_GetLux(void); // 获取实际光照强度(lux)
#endif
源文件(bh1750.c)
#include "bh1750.h"
#include "delay.h"
/**
* @brief 向BH1750写入单个指令
* @param cmd:要写入的指令
* @retval HAL_OK(0)成功,其他值失败
*/
uint8_t BH1750_WriteCmd(uint8_t cmd)
{
HAL_StatusTypeDef status;
// I2C写操作:地址+指令(BH1750_ADDR左移1位是因为I2C写位为0)
status = HAL_I2C_Master_Transmit(BH1750_I2C_HANDLE, (BH1750_ADDR<<1), &cmd, 1, 100);
return status;
}
/**
* @brief 读取BH1750的16位原始数据
* @param data:存储读取到的原始数据
* @retval HAL_OK(0)成功,其他值失败
*/
uint8_t BH1750_ReadData(uint16_t *data)
{
HAL_StatusTypeDef status;
uint8_t buf[2] = {0};
// I2C读操作:地址+读位(1)
status = HAL_I2C_Master_Receive(BH1750_I2C_HANDLE, (BH1750_ADDR<<1)|0x01, buf, 2, 100);
if(status == HAL_OK)
{
// 拼接16位数据:高8位+低8位
*data = (buf[0] << 8) | buf[1];
}
return status;
}
/**
* @brief BH1750初始化(上电+重置+设置工作模式)
*/
void BH1750_Init(void)
{
// 1. 上电
BH1750_WriteCmd(BH1750_POWER_ON);
HAL_Delay(10); // 等待上电稳定
// 2. 重置数据寄存器
BH1750_WriteCmd(BH1750_RESET);
HAL_Delay(10);
// 3. 设置为连续高分辨率模式(默认推荐)
BH1750_WriteCmd(BH1750_CONT_H_RES);
HAL_Delay(120); // 等待首次测量完成(高分辨率需120ms)
}
/**
* @brief 获取实际光照强度(单位:lux)
* @retval 光照强度值(失败返回-1.0)
*/
float BH1750_GetLux(void)
{
uint16_t raw_data = 0;
float lux = 0.0;
// 读取原始数据
if(BH1750_ReadData(&raw_data) == HAL_OK)
{
// 计算实际照度:原始数据 / 1.2
lux = (float)raw_data / 1.2;
return lux;
}
else
{
return -1.0; // 读取失败
}
}
main.c
#include "bh1750.h"
#include "stdio.h"
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_I2C1_Init(); // 初始化I2C1
MX_USART1_UART_Init(); // 初始化串口(用于打印)
// 初始化BH1750
BH1750_Init();
while (1)
{
float lux = BH1750_GetLux();
// 串口打印光照强度
printf("当前光照强度:%.2f lux\r\n", lux);
HAL_Delay(500); // 每500ms读取一次
}
}
// 重定向printf到串口1(需开启微库)
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
关键注意事项!!!
- SCL/SDA 引脚需接4.7KΩ 上拉电阻(STM32 内部上拉可能不稳定);
- ADDR 引脚接 GND(用 0x23 地址)或 VCC(用 0x5C 地址),推荐接 GND;
- 供电电压:3.3V(推荐)或 5V(需确认传感器兼容)。
总结
- BH1750 核心原理:光电二极管将光信号转为电信号,经内部处理后通过 I2C 输出 16 位数字量,除以 1.2 得到实际光照强度(lux)。
- STM32 驱动核心:通过 I2C 向 BH1750 发送工作模式指令,读取 16 位原始数据后完成计算,需注意测量延时和 I2C 地址的正确处理。
- 关键要点:硬件需接上下拉电阻,初始化流程必须包含上电 - 重置 - 设模式三步,数据读取后需验证通信状态。