目录
一、芯片介绍
二、Datasheet解读
1.硬件说明
2.寄存器说明
3.通信过程
三、驱动代码编写
1.软件I2C驱动
2. BH1750芯片驱动函数
总结
文章来源地址https://www.toymoban.com/news/detail-432624.html
一、芯片介绍
BH1750是16位数字输出型,环境光强度传感器集成电路,使用I2C接口通信,工作电压:VCC(2.4~3.6V),I2C电平(1.65~VCC),用于各类消费类LCD屏背光检测或环境光检测。
二、Datasheet解读
1.硬件说明
1)框图
- PD:光电二极管,接受光信号
- AMP:放大器,将电流信号转化为电压信号
- ADC:16位AD转换
-
Logic + I2 C Interface:环境光计算与I2C接口
-
OSC:内部时钟
引脚号 | 名称 | 说明 |
1 | VCC | 供电正极 |
2 | ADDR | 器件地址设置, 高电平时地址为:“1011100“ 低电平时地址为:“0100011“ |
3 | GND | 供电负极 |
4 | SDA | I2C数据线 |
5 | DVI | SDA,SCL参考电压引脚,内部寄存器异步重置端口 |
6 | SCL | I2C时钟线 |
3)上电时序
推荐的VCC和DVI的上电时序图:
VCC上电至少1us内DVI要保持低电平。
2.寄存器说明
推荐使用高分辨率模式,高分辨率模式(1lx)适用于暗箱(<10lx)测试,高分辨率模式2(0.5lx)也适用于暗箱测试。
查看电气参数可看出,高分辨率模式测量时间一般为120ms,最大不超过180ms。测量精度:测量值/实际值一般等于1.2倍。
3.通信过程
以器件地址设置为ADDR='L',分辨率设置为高分辨率模式为例,如下图:
注意:地址字节最后一位为读写标志位,‘0’为写,‘1’为读;读出数据高8位在前,低8位在后。
1)发送上电指令,0000_0001,
起始位->器件地址(7位)+读写位‘0’(1位)->等待应答->上电指令->结束位,
使设备上电等待测量;
2)发送测量指令,0001_0000(以连续高分辨率模式为例),
起始位->器件地址(7位)+读写位‘0’(1位)->等待应答->测量指令->结束位。
3)等待测量结束,一般高分辨率模式测量时间为120ms,最长为180ms,可等待180ms后读取测量结果。若为低分辨率模式,最长测量时间为24ms。
4)读取测量结果,
起始位->器件地址(7位)+读写位‘1’(1位)->等待应答->高8位读数->->低8位读数->不应答->结束位。
5)计算结果,
光照强度 =(寄存器值[15:0] * 分辨率) / 1.2 (单位:勒克斯lx)
寄存器值[15:0]:读到的寄存器值,先接收高8位,再接收低8位;
分辨率:设置的分辨率,本例位连续高分辨率模式,为1lx;
1.2 :测量精度,一般设置为1.2 。
6)灵敏度调整,通过调整光学窗口影响测量结果。
通过改变测量时间寄存器(MTreg)来改变灵敏度,MTreg寄存器默认值为“0100_0101” (69),最小设置值为“0001_1111”(31),最大设置值为“1111_1110”(254)。
在高分辨率模式下,设置流程如下:
设置MTreg高3位->设置MTreg低5位->设置为高分辨率模式测量->等待测量结束。
光照强度 =(寄存器值[15:0] * 分辨率) / 1.2 /(69/MTreg[7:0])(单位:勒克斯lx)
三、驱动代码编写
1.软件I2C驱动
1)参照正点原子I2C驱动程序,包括GPIO初始化,起始信号,结束信号,等待应答信号,产生Ack应答信号,不产生Ack应答信号:
//IO方向设置
#define SDA_IN() {GPIOB->CRH&=0XFF0FFFFF;GPIOB->CRH|=(uint32_t)8<<20;} //PB13输入模式
#define SDA_OUT() {GPIOB->CRH&=0XFF0FFFFF;GPIOB->CRH|=(uint32_t)3<<20;} //PB13输出模式
//IO操作
#define IIC_SCL(n) (n) ? (GPIOB->BSRR = GPIO_PIN_12) : (GPIOB->BSRR = GPIO_PIN_12<<16u)
#define IIC_SDA(n) (n) ? (GPIOB->BSRR = GPIO_PIN_13) : (GPIOB->BSRR = GPIO_PIN_13<<16u)
#define READ_SDA (GPIOB->IDR)&GPIO_PIN_13
//IIC初始化
void IIC_Init(void)
{
GPIO_InitTypeDef GPIO_Initure;
__HAL_RCC_GPIOB_CLK_ENABLE(); //使能GPIOB时钟
//PH4,5初始化设置
GPIO_Initure.Pin=GPIO_PIN_12|GPIO_PIN_13;
GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP; //推挽输出
GPIO_Initure.Pull=GPIO_PULLUP; //上拉
GPIO_Initure.Speed=GPIO_SPEED_FREQ_HIGH;//高速
HAL_GPIO_Init(GPIOB,&GPIO_Initure);
IIC_SDA(1);
IIC_SCL(1);
}
//产生IIC起始信号
void IIC_Start(void)
{
SDA_OUT(); //sda线输出
IIC_SDA(1);
IIC_SCL(1);
delay_us(4);
IIC_SDA(0); //START:when CLK is high,DATA change form high to low
delay_us(4);
IIC_SCL(0); //钳住I2C总线,准备发送或接收数据
}
//产生IIC停止信号
void IIC_Stop(void)
{
SDA_OUT(); //sda线输出
IIC_SCL(0);
IIC_SDA(0); //STOP:when CLK is high DATA change form low to high
delay_us(4);
IIC_SCL(1);
IIC_SDA(1); //发送I2C总线结束信号
delay_us(4);
}
//等待应答信号到来
//返回值:1,接收应答失败
// 0,接收应答成功
uint8_t IIC_Wait_Ack(void)
{
uint8_t ucErrTime=0;
SDA_IN(); //SDA设置为输入
IIC_SDA(1);delay_us(1);
IIC_SCL(1);delay_us(1);
while(READ_SDA)
{
ucErrTime++;
if(ucErrTime>250)
{
IIC_Stop();
return 1;
}
}
IIC_SCL(0); //时钟输出0
return 0;
}
//产生ACK应答
void IIC_Ack(void)
{
IIC_SCL(0);
SDA_OUT();
IIC_SDA(0);
delay_us(2);
IIC_SCL(1);
delay_us(2);
IIC_SCL(0);
}
//不产生ACK应答
void IIC_NAck(void)
{
IIC_SCL(0);
SDA_OUT();
IIC_SDA(1);
delay_us(2);
IIC_SCL(1);
delay_us(2);
IIC_SCL(0);
}
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答
void IIC_Send_Byte(uint8_t txd)
{
uint8_t t;
SDA_OUT();
IIC_SCL(0); //拉低时钟开始数据传输
for(t=0;t<8;t++)
{
IIC_SDA((txd&0x80)>>7);
txd<<=1;
delay_us(2); //对TEA5767这三个延时都是必须的
IIC_SCL(1);
delay_us(2);
IIC_SCL(0);
delay_us(2);
}
}
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK
uint8_t IIC_Read_Byte(unsigned char ack)
{
unsigned char i,receive=0;
SDA_IN(); //SDA设置为输入
for(i=0;i<8;i++ )
{
IIC_SCL(0);
delay_us(2);
IIC_SCL(1);
receive<<=1;
if(READ_SDA)
receive++;
delay_us(1);
}
if (!ack)
IIC_NAck();//发送nACK
else
IIC_Ack(); //发送ACK
return receive;
}
2)I2C读写函数
void Soft_I2C_Write(uint8_t slaveAddress,uint8_t* dataBuffer,uint8_t bytesNumber,uint8_t stopBit)
{
unsigned char i = 0;
IIC_Start();
IIC_Send_Byte((slaveAddress << 1) | 0x00); //发送从机地址写命令
IIC_Wait_Ack();
for(i = 0; i < bytesNumber; i++)
{
IIC_Send_Byte(*(dataBuffer + i));
IIC_Wait_Ack();
}
if(stopBit == 1) IIC_Stop();
}
void Soft_I2C_Read(uint8_t slaveAddress,uint8_t* dataBuffer,uint8_t bytesNumber,uint8_t stopBit)
{
unsigned char i = 0;
IIC_Start();
IIC_Send_Byte((slaveAddress << 1) | 0x01); //发送从机地址读命令
IIC_Wait_Ack();
for(i = 0; i < bytesNumber; i++)
{
if(i == bytesNumber - 1)
{
*(dataBuffer + i) = IIC_Read_Byte(0);//读取的最后一个字节发送NACK
}
else
{
*(dataBuffer + i) = IIC_Read_Byte(1);
}
}
if(stopBit == 1) IIC_Stop();
}
2. BH1750芯片驱动函数
#define BHAdd 0x23 //从机地址 ADDR = L
//#define BHAdd 0x5C //从机地址 ADDR = H
#define BHPowDown 0x00 //关闭模块
#define BHPowOn 0x01 //打开模块等待测量指令
#define BHReset 0x07 //重置数据寄存器值在PowerOn模式下有效
#define BHModeH 0x10 //连续高分辨率模式 单位 1lx 测量时间120ms
#define BHModeH2 0x11 //连续高分辨率模式2 单位0.5lx 测量时间120ms
#define BHModeL 0x13 //连续低分辨率模式 单位 4lx 测量时间16ms
#define BHSigModeH 0x20 //一次高分辨率模式 单位 1lx 测量时间120ms,测量后转到 PowerDown模式
#define BHSigModeH2 0x21 //一次高分辨率模式2 单位0.5lx 测量时间120ms,测量后转到 PowerDown模式
#define BHSigModeL 0x23 //一次低分辨率模式 单位 4lx 测量时间16ms,测量后转到 PowerDown模式
#define Resolution BHModeH2 // 连续高分辨率模式,0.5lx
#if Resolution == BHModeH || Resolution == BHSigModeH
#define SCALE_INTERVAL 1
#elif Resolution == BHModeH2 || Resolution == BHSigModeH2
#define SCALE_INTERVAL 0.5f
#elif Resolution == BHModeL || Resolution == BHSigModeL
#define SCALE_INTERVAL 4
#endif
void BH1750_Init(void);
float BH1750_Read(void);
// 写传感器函数
void BH1750_Write(uint8_t REG_Address)
{
uint8_t buf[2]={0};
buf[0]=REG_Address;
Soft_I2C_Write(BHAdd,buf,1,1);
}
// 读传感器函数
float BH1750_Read(void)
{
uint8_t buf[2];
float temp;
Soft_I2C_Read(BHAdd, buf, 2, 1);
temp= (float)(((uint16_t)buf[0]<<8) + buf[1]) * SCALE_INTERVAL / 1.2f ;
return temp;
}
// 对传感器进行初始化
void BH1750_Init(void)
{
BH1750_Write(BHPowOn); // 通电
BH1750_Write(Resolution); // 设置分辨率
}
总结
参考源代码如下链接:基于STM32F103的BH1750光照传感器驱动程序-单片机文档类资源-CSDN文库文章来源:https://www.toymoban.com/news/detail-432624.html
到了这里,关于STM32外设芯片驱动学习记录 —— (一) BH1750光照传感器驱动开发的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!