GY-30 数字环境光传感器模块

BH1750

STM32F103C8T6 · HAL库 · 软件I2C通信

16位数字光照强度传感器 · 1-65535 lx 测量范围

工作电压
3V - 5V
通信方式
I2C
测量范围
1 - 65535 lx
分辨率
1 lx
▼
01

传感器原理与功能

1.1 工作原理

BH1750FVI 是一款用于 I2C总线接口 的数字环境光传感器 IC。芯片内部集成了光敏二极管(Photodiode),当可见光照射到光敏二极管表面时,产生与光强度成正比的光电流。该光电流经过内部16位ADC(模数转换器)转换为数字值,再通过数字电路进行光谱响应补偿计算,最终输出以勒克斯(lx)为单位的数字光照强度值。

BH1750 的光谱响应曲线经过专门设计,接近人眼视觉灵敏度曲线(峰值约540nm),能够准确感知人眼所感受的环境亮度,广泛用于手机、显示器背光调节、智能家居照明等场景。传感器支持连续测量和单次测量两种工作模式,高分辨率模式下测量时间约120ms,分辨率可达1 lx。

1.2 核心功能

☀

光照强度测量

测量范围 1-65535 lx,覆盖从夜间微光到晴天直射阳光的全部场景,16位高精度ADC确保数据准确。

👁

人眼响应曲线

光谱灵敏度经过校准,接近人眼视觉特性(V(λ)曲线),感知结果与人眼感受高度一致。

🔌

I2C数字输出

标准I2C总线接口,地址可选(0x23/0x5C),直接输出数字光照值,无需复杂模拟信号处理。

⚡

低功耗设计

支持断电模式(Power Down),待机电流极低,适合电池供电的便携式设备长时间运行。

1.3 引脚定义

引脚 名称 功能 STM32连接
VCC电源正极模块供电 (3V-5V)3.3V
GND电源地公共接地GND
SCLI2C时钟线串行时钟信号PB1
SDAI2C数据线串行数据信号PB0
ADDR地址选择I2C地址选择 (低=0x23, 高=0x5C)GND (低电平)
02

模块外观展示

模块正面
模块正面 - BH1750FVI芯片及光敏元件
模块背面
模块背面 - 焊接引脚及电路布线
模块尺寸
模块尺寸示意图
03

原理图与PCB封装

原理图
PCB封装
04

程序分析

4.1 系统初始化 main.c

系统启动后,依次完成 HAL库初始化、系统时钟配置(HSE 8MHz × PLL9 = 72MHz)、GPIO时钟使能,然后初始化 OLED显示屏(PB14/PB15 软件I2C)和 BH1750传感器(PB0/PB1 软件I2C)。BH1750初始化时会发送上电命令并等待180ms确保芯片稳定。
Core/Src/main.c
int main(void)
{
    HAL_Init();                              // 初始化HAL库
    SystemClock_Config();                    // 配置系统时钟 72MHz
    MX_GPIO_Init();                        // 使能GPIO时钟

    OLED_Init();                           // 初始化OLED显示屏 (PB14/PB15)
    BH1750_GPIO_Init();                    // 初始化BH1750引脚 (PB0/PB1)

    while (1)
    {
        // 主循环逻辑见 4.7节
    }
}

4.2 系统时钟配置 main.c

使用外部高速晶振(HSE)8MHz 作为PLL源,通过 PLLMUL × 9 倍频得到 72MHz 系统时钟。APB1总线分频为36MHz,APB2总线保持72MHz。这是STM32F103C8T6的标准时钟配置。
Core/Src/main.c
void SystemClock_Config(void)
{
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;       // 8MHz × 9 = 72MHz

    HAL_RCC_OscConfig(&RCC_OscInitStruct);

    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;     // HCLK = 72MHz
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;      // APB1 = 36MHz
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;      // APB2 = 72MHz

    HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2);
}

4.3 BH1750 GPIO初始化 bh1750.c

将 PB1(SCL) 和 PB0(SDA) 配置为推挽输出模式,启用内部上拉电阻,速度设为高速。由于采用软件模拟I2C,SDA引脚需要在输出和输入之间动态切换。初始化完成后发送上电命令(0x01)并等待180ms。
HAL/BH1750/bh1750.c
void BH1750_GPIO_Init(void)
{
    BH1750_SCL_GPIO_CLK_ENABLE();          // 使能GPIOB时钟
    BH1750_SDA_GPIO_CLK_ENABLE();

    GPIO_InitTypeDef GPIO_InitStruct = {0};

    // SCL - PB1 推挽输出
    GPIO_InitStruct.Pin = BH1750_SCL_Pin;            // GPIO_PIN_1
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(BH1750_SCL_GPIO_Port, &GPIO_InitStruct);

    // SDA - PB0 推挽输出
    GPIO_InitStruct.Pin = BH1750_SDA_Pin;            // GPIO_PIN_0
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(BH1750_SDA_GPIO_Port, &GPIO_InitStruct);

    Single_Write_BH1750(0x01);               // 上电命令
    HAL_Delay(180);                         // 等待芯片稳定
    bh_data_send(BHPowOn);                    // 发送Power On
}

4.4 I2C起始信号 bh1750.c

I2C起始信号:当 SCL为高电平 时,SDA从高电平变为低电平,表示通信开始。随后拉低SCL钳住总线,准备发送或接收数据。软件I2C通过直接操控GPIO引脚电平实现时序。
HAL/BH1750/bh1750.c
void BH1750_IIC_Start(void)
{
    BH1750_SDA_OUT();                        // SDA设为输出模式
    BH1750_SDA_DATA(1);                   // SDA拉高
    BH1750_SCL_OUT(1);                   // SCL拉高
    delay_us(4);

    BH1750_SDA_DATA(0);                   // SCL高时SDA下降沿 = START
    delay_us(4);
    BH1750_SCL_OUT(0);                   // 钳住I2C总线
}

4.5 I2C字节发送 bh1750.c

每次发送一个字节(8位),先发最高位(MSB)。通过位操作 (txd & 0x80) >> 7 提取最高位,设置SDA电平后,SCL产生上升沿发送数据位,然后拉低SCL。循环8次完成一个字节的传输。
HAL/BH1750/bh1750.c
void BH1750_IIC_Send_Byte(uint8_t txd)
{
    uint8_t t;
    BH1750_SDA_OUT();
    BH1750_SCL_OUT(0);                       // 拉低时钟开始传输

    for(t = 0; t < 8; t++)
    {
        if((txd & 0x80) >> 7)
            BH1750_SDA_DATA(1);             // 发送1
        else
            BH1750_SDA_DATA(0);             // 发送0
        txd <<= 1;                      // 左移一位
        delay_us(2);
        BH1750_SCL_OUT(1);                 // SCL上升沿 - 从机读取数据
        delay_us(2);
        BH1750_SCL_OUT(0);                 // SCL下降沿
        delay_us(2);
    }
}

4.6 BH1750光照读取算法 bh1750.c

读取流程:① 发送复位命令(0x07)清除状态寄存器;② 发送连续高分辨率模式命令(0x10,分辨率1lx);③ 等待180ms完成ADC转换;④ 通过I2C读取2字节数据(高字节 + 低字节);⑤ 计算勒克斯值:lux = (高字节×256 + 低字节) / 1.2。
HAL/BH1750/bh1750.c
uint16_t bh1750_read(void)
{
    uint16_t light;

    bh_data_send(BHReset);        // 0x07 - 复位命令
    bh_data_send(BHModeH1);      // 0x10 - 连续高分辨率模式 (1lx)
    HAL_Delay(180);            // 等待ADC转换完成 (约120ms + 余量)

    light = bh_data_read();    // 读取2字节数据
    light = light / 1.2;      // 转换为勒克斯(lx)单位

    return light;
}

4.7 主循环逻辑 main.c

主循环采用非阻塞定时方式,通过 HAL_GetTick() 获取系统毫秒时间戳,每 500ms 执行一次光照读取和显示更新。流程为:读取BH1750光照值 → 清屏 → 居中显示"光照:XXX lx" → 更新OLED显示 → 更新时间戳。
Core/Src/main.c
while (1)
{
    if(HAL_GetTick() - Time_Now >= 500)        // 500ms更新一次
    {
        light = bh1750_read();                        // 读取光照值 (lx)

        OLED_Clear();                                // 清屏
        OLED_CenterPrintf(24, "光照:%d lx", light); // 居中显示
        OLED_Update();                              // 更新OLED显示

        Time_Now = HAL_GetTick();                    // 更新时间戳
    }
}

BH1750 命令代码表

命令名称代码说明
BHPowDown0x00断电模式,停止测量
BHPowOn0x01上电,准备接收指令
BHReset0x07复位,清除状态寄存器
BHModeH10x10连续高分辨率模式 (1lx, 120ms)
BHModeH20x11连续高分辨率模式2 (0.5lx, 120ms)
BHModeL0x13连续低分辨率模式 (4lx, 16ms)
BHSigModeH0x20单次高分辨率模式 (测量后自动断电)
BHSigModeH20x21单次高分辨率模式2 (测量后自动断电)
BHSigModeL0x23单次低分辨率模式 (测量后自动断电)

光照等级对照表

光照范围 (lx)等级典型场景
< 10很暗夜间环境、无光源
10 - 100较暗昏暗走廊、月光下
100 - 500正常普通室内照明、办公室
500 - 1000明亮明亮室内、超市照明
1000 - 10000很亮阴天户外、窗边
> 10000极亮晴天阳光直射
05

程序流程图

开始 HAL_Init() 初始化HAL库 SystemClock_Config() 72MHz MX_GPIO_Init() 使能GPIO OLED_Init() 初始化显示屏 BH1750_GPIO_Init() 初始化传感器 while(1) HAL_GetTick() - Time_Now >= 500? 否 是 light = bh1750_read() light = light / 1.2 (转换为lx) OLED_Clear() 清屏 OLED_CenterPrintf("光照:%d lx") OLED_Update() 更新显示 Time_Now = HAL_GetTick()
06

交互式动画演示

光照模拟

光照: 5000 lx
自动模式 (模拟昼夜变化)
组件说明:上方太阳模拟光源,调节滑块可改变光照强度。下方的GY-30模块板载BH1750芯片接收光线,光线越强芯片感应区越亮。

OLED显示 & 数据仪表

光照:0 lx
0
lx
等待数据...
数据显示:OLED屏幕实时显示光照值,右侧仪表盘以环形进度条指示当前光照强度占满量程的比例,下方文字根据光照范围标注等级(很暗/较暗/正常/明亮/很亮/极亮)。