STM32外设芯片驱动学习记录 —— (一) BH1750光照传感器驱动开发

目录

 

一、芯片介绍

        BH1750是16位数字输出型,环境光强度传感器集成电路,使用I2C接口通信,工作电压:VCC(2.4~3.6V),I2C电平(1.65~VCC),用于各类消费类LCD屏背光检测或环境光检测。

二、Datasheet解读

1.硬件说明

1)框图

7f9820c2807e41cebe4e226f5dbd1b65.png

  • PD:光电二极管,接受光信号
  • AMP:放大器,将电流信号转化为电压信号
  • ADC:16位AD转换
  • Logic + I2 C Interface:环境光计算与I2C接口
  • OSC:内部时钟
2)引脚说明
引脚号名称说明
1VCC供电正极
2ADDR

器件地址设置,

高电平时地址为:“1011100“

低电平时地址为:“0100011“

3GND供电负极
4SDAI2C数据线
5DVISDA,SCL参考电压引脚,内部寄存器异步重置端口
6SCLI2C时钟线

3)上电时序

 推荐的VCC和DVI的上电时序图:

341dea8732474e1a959b9234e766974b.png

VCC上电至少1us内DVI要保持低电平。

2.寄存器说明

fa035e168cca498cb6d3993fc77ae74a.png

        推荐使用高分辨率模式,高分辨率模式(1lx)适用于暗箱(<10lx)测试,高分辨率模式2(0.5lx)也适用于暗箱测试。

        查看电气参数可看出,高分辨率模式测量时间一般为120ms,最大不超过180ms。测量精度:测量值/实际值一般等于1.2倍。

b29ed91ef70346b7bc0532b68ba40ba3.png

3.通信过程

        以器件地址设置为ADDR='L',分辨率设置为高分辨率模式为例,如下图:

bf1c788da51046bcabe7e9a4428c4d82.png

 注意:地址字节最后一位为读写标志位,‘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)。

        在高分辨率模式下,设置流程如下:

0070202c5d574e81af30e980e49e6823.png

        设置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文库

 

  • 7
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值