这里我先简单的介绍一下bh1750光照传感器模块的基本信息(不多废话),我将着重讲解它的使用部分,相信对于屏幕前的你也是更关心它是怎么使用的,ok,gogogo!!!
一、产品简介
芯片: bh1750fvi 是一种用于两线式串行总线接口的数字型光强度传感器集成电路。这种集成电路可以根据收集的光线强度数据来调整液晶或者键盘背景灯的亮度。利用它的高分辨率可以探测较大范围的光强度变化。
工作原理: bh1750的内部由光敏二极管、运算放大器、adc采集、晶振等组成。pd二极管通过光生伏特效应将输入光信号转换成电信号,经运算放大电路放大后,由adc采集电压,然后通过逻辑电路转换成16位二进制数存储在内部的寄存器中(光照越强,光电流越大,电压就越大)。
物理电路图:
pcb原理图:
实物图:
可见,该模块有5个引脚,接下来再看看引脚介绍是啥模样
引脚定义:
模块指令:
使用步骤:
产品特点:
- 支持i2cbus接口
- 接近视觉灵敏度的光谱灵敏度特性
- 输出对应亮度的数字值
- 对应广泛的输入光范围。(相当于1-65535lx)
- 通过降低功率功能,实现低电流化。
- 通过50hz/60hz除光噪音功能实现稳定的测定。
- 支持1.8v逻辑输入接口。
- 无需其他外部件。
- 光源依赖性弱。
- 有两种可选的i2cslave地址。
- 可调的测量结果影响较大的因素为光入口大小。
- 使用这种功能计算1.1lx到100000lx马克斯/分钟的范围。
- 最小误差变动在±20%。
- 受红外线影响很小。
二、iic通信
iic是一种串行通信总线,iic串行总线一般有两根信号线,一根是双向的数据线sda,另一根是时钟线scl。所有接到i2c总线设备上的串行数据sda都接到总线的sda上,各设备的时钟线scl接到总线的scl上。可以理解为 其通过sda和clk俩根线完成通信传输,
由于该模块是通过iic协议进行通信的,所以接下来我再来介绍介绍iic的相关驱动。
iic驱动部分都是通用的,其各个模块是根据自身的设备地址及其配置、命令等寄存器操作不同来完成各自的通信。
iic 驱动部分我划分为了6个部分,分为:
- 开始信号
- 停止信号
- 发送应答信号
- 接收应答信号
- 发送一个字节
- 接收一个字节
首先先来看时序图:
时序没看明白,别着急,听我一 一道来。
首先,请记住 : sda和clk只有“0和1”俩种状态;其次,主机在发送信号时clk引脚要定义输出模式,在接收信号时clk引脚要定义输入模式。
1. 开始信号:
对于开始信号,你可以这样理解,sda是在clk置高电平的情况下 由高电平->低电平,这就是开始信号,只不过为了通信稳定,一般在跳变中途延时5us。
接下来看看程序是怎么设计的:
void iic_start(void)
{
sda_out(); //sda线输出模式
iic_sda=1;
iic_scl=1;
delay_us(5);
iic_sda=0; //产生下降沿
delay_us(5);
iic_scl=0;//钳住i2c总线,准备发送或接收数据
}
2. 停止信号:
同开始信号,sda在clk为高电平时 由低电平->高电平,完成停止信号。
void iic_stop(void)
{
sda_out(); //sda线输出
iic_sda=0; //产生上升沿
delay_us(5);
iic_scl=1;
iic_sda=1; //发送i2c总线结束信号
delay_us(5);
}
3. 发送应答信号:
在sda为低电平时 clk由高电平->低电平 ,完成应答;
在sda为高电平时 clk由高电平->低电平 ,拒绝应答;
所以在程序中 需设置一个变量进行判断是否接受应答:
void sendack(int ack)
{
gpio_inittypedef gpio_initstruct;
gpio_initstruct.gpio_mode = gpio_mode_out_pp; //定义输出模式
gpio_initstruct.gpio_speed = gpio_speed_50mhz;
gpio_initstruct.gpio_pin = sda;
gpio_init(bh1750_port, &gpio_initstruct);
if(ack == 1) //写应答信号
sda=1;
else if(ack == 0)
sda=0;
else
return;
scl=1; //拉高时钟线
delay_us(5); //延时
scl=0; //拉低时钟线
delay_us(5); //延时
}
4. 接收应答信号:
在clk由低电平->高电平->低电平 期间sda保持低电平
u8 iic_waitack()
{
u8 ack =0;
iic_setsdamode_in();
iic_scl_out(0); //准备时序
delay_us(5);
iic_scl_out(1);
delay_us(5);
if(iic_sda_in)
{
ack =1;
}
else
{
ack =0;
}
iic_scl_out(0); //拉低,表示应答完成
delay_us(5);
return ack;
}
5. 发送一个字节:
clk每完成一次 高电平->低电平 跳变,主机发送1bit,1字节发送完成后且需要接收从机发回来的应答信号。
void sendbyte(uchar dat)
{
uchar i;
for (i=0; i<8; i++) //8位计数器
{
if( 0x80 & dat )
gpio_setbits(bh1750_port,sda);
else
gpio_resetbits(bh1750_port,sda);
dat <<= 1;
scl=1; //拉高时钟线
delay_us(5); //延时
scl=0; //拉低时钟线
delay_us(5); //延时
}
recvack();
}
6. 接收一个字节:
类似于发送一字节,只是引脚定义不同,具体如下:
u8 iic_readbyte()
{
u8 data = 0;
iic_setsdamode_in();
iic_scl_out(0); //先拉低,为读取数据做准备
delay_us(5);
for(int i=0;i<8;i++)
{
iic_scl_out(1); // scl为高期间才可以读取数据
delay_us(5);
if(iic_sda_in)
{
data|=(0x01<<(7-i));
}else{
data &= ~(0x1<<(7-i));
}
iic_scl_out(0);
delay_us(5);
}
return data;
}
三、bh1750的使用
1. 写信号
首先需要对模块进行写操作,然后再初始化, 写操作的过程为:起始信号 -->发送设备地址+写信号 -->发送内部寄存器地址 --> 发送停止信号。
void single_write_bh1750(uchar reg_address)
{
bh1750_start(); //起始信号
bh1750_sendbyte(slaveaddress); //发送设备地址+写信号
bh1750_sendbyte(reg_address); //内部寄存器地址
bh1750_stop(); //发送停止信号
}
2. 初始化
对模块进行初始化,初始化sda和clk引脚 初步设置为推挽输出,然后对模块进行上电,根据指令表可知 上电指定为0x01,上电后需要延迟180ms左右让模块进行缓冲。
void init_bh1750()
{
gpio_inittypedef gpio_initstruct;
/*开启gpiob的外设时钟*/
rcc_apb2periphclockcmd( rcc_apb2periph_gpioa, enable);
gpio_initstruct.gpio_mode = gpio_mode_out_pp;
gpio_initstruct.gpio_speed = gpio_speed_50mhz;
gpio_initstruct.gpio_pin = sda | scl ;
gpio_init(bh1750_port,&gpio_initstruct);
single_write_bh1750(0x01);
delay_ms(180); //延时180ms
}
3. 读寄存器内部数据
读数据操作的过程为:起始信号 -->发送设备地址+读信号 -->定义数组存储数据(最后一个数据需要拒绝应答) --> 发送停止信号。
void mread(void)
{
uchar i;
bh1750_start(); //起始信号
bh1750_sendbyte(slaveaddress+1); //发送设备地址+读信号
for (i=0; i<3; i++) //连续读取3个地址数据,存储中buf
{
buf[i] = bh1750_recvbyte(); //buf[0]存储0x32地址中的数据
if (i == 3)
{
bh1750_sendack(1); //最后一个数据需要回noack
}
else
{
bh1750_sendack(0); //回应ack
}
}
bh1750_stop(); //停止信号
delay_ms(5);
}
4. 对数据进行操作、转存
float read_bh1750(void)
{
int dis_data; //变量
float temp1;
float temp2;
single_write_bh1750(0x01); // power on
single_write_bh1750(0x10); // h- resolution mode
delay_ms(180); //延时180ms
mread(); //连续读出数据,存储在buf中
dis_data=buf[0];
dis_data=(dis_data<<8)+buf[1]; //合成数据
temp1=dis_data/1.2;
temp2=10*dis_data/1.2;
temp2=(int)temp2%10;
oled_showstring(87,2,".",12);
oled_shownum(94,2,temp2,1,12);
return temp1;
}
5. 主函数里调用bh17502并显示在oled上
int main(void)
{
float light;
nvic_prioritygroupconfig(nvic_prioritygroup_2);// 设置中断优先级分组2
delay_init(); //延时函数初始化
uart_init(9600); //串口初始化为9600
led_init(); //初始化与led连接的硬件接口
init_bh1750(); //初始化bh1750
oled_init(); //初始化oled
oled_clear(); //清屏
while(1)
{
light=read_bh1750(); //读取bh1750的光强数据
oled_showstring(0,2,"light:",12); //显示光照强度
oled_shownum(48,2,light,6,12);
oled_showstring(110,2,"lx",12);
if(light<100)
{
led1=0;
oled_showstring(38,5,"led-on ",12);
}
else
{
led1=1;
oled_showstring(38,5,"led-off",12);
}
}
}
四、程序源码
疑难解答或技术交流加下方wx联系即可👇👇👇
发表评论