本帖最后由 jinglixixi 于 2025-6-2 12:22 编辑
#申请原创#
BH1750是一款基于 I2C 接口的数字式环境光传感器,它适于获得环境光照强度的检测,受光学窗口的影响其检测最小为 0.11 lx,最大为 100000 lx。
该传感器的引脚定义如图1所示,它与开发板的连接关系为:
SCL ---PB8
SDA---PB9
为便于直观观察检测结果,由OLED进行显示,它与开发板的连接关系为:
SCL ---PA5
SDA---PA6
图1 引脚定义
图2 所用接口
为便于引脚的分配和使用,这里采用模拟I2C的方式来实现光照强度的检测。
配置所用引脚的函数为:
void BH1750_Init(void)
{
gpio_init_type gpio_init_struct;
crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);
gpio_default_para_init(&gpio_init_struct);
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
gpio_init_struct.gpio_pins = GPIO_PINS_8|GPIO_PINS_9;
gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
gpio_init(GPIOB, &gpio_init_struct);
}
有别于OLED屏的显示驱动,在进行光照检测时,数据引脚既要工作在输出模式,也要工作在输入模式。
为此,需要配置相应的工作模式函数,以便进行工作模式切换。
设置为输入模式的函数为:
void IIC_INPUT_MODE_SET()
{
gpio_init_type gpio_init_struct;
gpio_init_struct.gpio_mode = GPIO_MODE_INPUT;
gpio_init_struct.gpio_pins = GPIO_PINS_9;
gpio_init(GPIOB, &gpio_init_struct);
}
设置为输出模式的函数为:void IIC_OUTPUT_MODE_SET()
{
gpio_init_type gpio_init_struct;
gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
gpio_init_struct.gpio_pins = GPIO_PINS_9;
gpio_init(GPIOB, &gpio_init_struct);
}
设置引脚输出高低电平和检测引脚状态的语句定义为:
#define SCL_Set() GPIOB->scr = GPIO_PINS_8
#define SCL_Clr() GPIOB->clr = GPIO_PINS_8
#define SDA_Set() GPIOB->scr = GPIO_PINS_9
#define SDA_Clr() GPIOB->clr = GPIO_PINS_9
#define IIC_SDA_IN gpio_input_data_bit_read(GPIOB, GPIO_PINS_9)
模拟I2C处理的辅助辅助函数如下:
void BH1750_Start()
{
IIC_OUTPUT_MODE_SET();
SDA_Set();
SCL_Set();
delay_us(5);
SDA_Clr();
delay_us(5);
SCL_Clr();
}
void BH1750_Stop()
{
IIC_OUTPUT_MODE_SET();
SDA_Clr();
SCL_Set();
delay_us(5);
SDA_Set();
delay_us(5);
}
void BH1750_SendACK(char ack)
{
IIC_OUTPUT_MODE_SET();
SCL_Clr();
if(ack)
{
SDA_Set();
}
else
{
SDA_Clr();
}
delay_us(2);
SCL_Set();
delay_us(5);
SCL_Clr();
}
char BH1750_RecvACK()
{
int cnt=0;
IIC_OUTPUT_MODE_SET();
SDA_Set();
delay_us(1);
SCL_Set();
IIC_INPUT_MODE_SET();
delay_us(1);
while(IIC_SDA_IN)
{
cnt++;
delay_us(1);
if(cnt>=250)
{
BH1750_Stop();
return 1;
}
}
SCL_Clr();
return 0;
}
模拟I2C发送字节数据的函数为:
void BH1750_SendByte(char data)
{
char i;
IIC_OUTPUT_MODE_SET();
SCL_Clr();
delay_us(2);
for (i=0;i<8;i++)
{
if(data&0x80)
{
SDA_Set();
}
else
{
SDA_Clr();
}
data <<= 1;
SCL_Set();
delay_us(2);
SCL_Clr();
delay_us(2);
}
}
模拟I2C读取字节数据的函数为:
char BH1750_RecvByte()
{
char i;
char data = 0;
IIC_INPUT_MODE_SET();
for (i=0;i<8;i++)
{
SCL_Clr();
delay_us(2);
SCL_Set();
data <<= 1;
SCL_Set();
if(IIC_SDA_IN) data|=0x01;
delay_us(2);
}
SCL_Clr();
return data;
}
写入寄存器地址的函数为:
void Single_Write_BH1750(char REG_Address)
{
BH1750_Start();
BH1750_SendByte(SlaveAddress);
BH1750_RecvACK();
BH1750_SendByte(REG_Address);
BH1750_RecvACK();
BH1750_Stop();
}
读取BH1750多字节数据的函数为:
void Multiple_Read_BH1750()
{
BH1750_Start();
BH1750_SendByte(SlaveAddress+1);
BH1750_RecvACK();
BUF[0] = BH1750_RecvByte();
BH1750_SendACK(0);
BUF[1] = BH1750_RecvByte();
BH1750_SendACK(1);
BH1750_Stop();
delay_ms(5);
}
实现光强检测与显示的函数为:
void Get_Sunlight_Value()
{
int dis_data=0;
float temp;
char i=0;
unsigned int sd;
Single_Write_BH1750(0x01);
Single_Write_BH1750(0x10);
delay_ms(180);
Multiple_Read_BH1750();
for(i=0;i<3;i++)dis_data=BUF[0];
dis_data=(dis_data<<8)+BUF[1];
temp=(float)dis_data/1.2;
sd=temp;
OLED_ShowNum(20,2,sd,5,16);
}
实现光强检测与显示的主程序为:
int main(void)
{
system_clock_config();
at32_board_init();
oled_config();
OLED_Init();
OLED_Clear();
OLED_ShowString(0,0,"AT32M412",16);
OLED_ShowString(0,2,"L=",16);
BH1750_Init();
while(1)
{
at32_led_toggle(LED2);
delay_ms(200);
at32_led_toggle(LED3);
delay_ms(200);
at32_led_toggle(LED4);
delay_ms(200);
Get_Sunlight_Value();
}
}
经程序的编译和下载,其检测结果如图4所示。
图3 连接形式
图4 检测结果
|