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

2023-11-06

目录

 

一、芯片介绍

        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)引脚说明
引脚号 名称 说明
1 VCC 供电正极
2 ADDR

器件地址设置,

高电平时地址为:“1011100“

低电平时地址为:“0100011“

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

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

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

随机推荐

  • SpringBoot主类解析(四)

    SpringBoot主类 import org springframework boot Banner import org springframework boot SpringApplication import org springf
  • 51 Job招聘数据分析与可视化

    招聘数据分析与可视化 背景 为了分析现有数据行业的招聘情况 抓取2017年3月14日到2017年5月13日发布在51Job上的数据相关招聘职位116273条信息 并从中筛选出职位是数据分析 数据挖掘 文本挖掘 视觉学习 计算广告 数据开发
  • Spring-AOP的基本介绍以及通过先动态代理方式实现

    前言 本篇的Spring AOP系类文章第一篇详细的讲解了Spring AOP的介绍以及通过先动态代理在使用AOP由浅入深更容易理解 个人主页 尘觉主页 https blog csdn net apple 67445472 type blo
  • 警告当当成错误 may be used uninitialized in this function [-Werror=maybe-uninitialized]

    如果是ubuntu20版本 或者gcc版本太高 可能有些警告会当成错误导致编译出错 error may be used uninitialized in this function Werror maybe uninitialized cc
  • 1600*C. Binary String Copying

    https codeforces com problemset problem 1849 C Binary String Copying 洛谷 解析 对于某个区间x y 他排序之后 最左侧的连续0和最右侧的连续1是不影响排序结果的 假设左侧
  • Java7大数据结构

    Java数据结构 简书
  • FISCO BCOS 联盟链Pro搭建

    FISCO BCOS Pro版本 版本说明 FISCO BCOS 3 0支持Pro版本微服务区块链架构 Pro版本FISCO BCOS包含RPC服务 Gateway服务和节点服务 每个服务均可独立部署和扩容 本章通过单机搭建Pro版本2节点
  • 目标检测模型设计准则

    转载 https mp weixin qq com s 5SjQvRqRct6ClpE2eEcdkw 设计高效 高质量的表达性网络架构一直是深度学习领域最重要的研究课题 当今的大多数网络设计策略都集中于如何集成从不同层提取的特征 以及如何设
  • windows系统下安装linux(centos7)虚拟机详细教程(virtualbox环境)

    目录 一 概念 1 1 什么是镜像 1 2 关于镜像的基本概念 二 centos镜像下载 2 1 centos官网下载镜像 2 2 通过其他官网下载镜像 三 下载virtualbox 3 1 为什么要使用virtualbox 3 2 下载v
  • 极简java实现理解单例模式核心

    问 单例模式意义 在项目中 有的对象只需要存在一个就足够了 多创建对象则会浪费资源 单例模式可以保证项目对象只存在一个 且不会被多次创建 java实现例子 最少代码 public class Singleton public static
  • ABP模块系统学习及使用

    ABP模块系统简介 参考 ABP中配置的注册和初始化 ABP模块系统 ABP 源码解析 一 ABP启动 ABP框架提供了创建和组装模块的基础 一个模块能够依赖于另一个模块 在通常情况下 一个程序集就可以看成是一个模块 在ABP框架中 一个模
  • verilog搭建16位加法器记录时钟信号、实现24小时时钟

    构建一个4位BCD计数器 每个十进制数字用4位编码 q 3 0 是个位 q 7 4 是十位 以此类推 对于数字 3 1 也输出一个enable信号 表示什么时候需要增加上面三位数字 参考输出 代码 module top module inp
  • 通过uvm_printer的print_generic进行扩展打印

    uvm的field automation机制实现的其中一项功能就是sprint功能 该函数通过调用do print函数实现 在某些情况的 uvm的打印功能不是我们所期望的 比如多维数组的field automation机制就不支持 stru
  • k8s集群部署(rke + rancher)

    部署环境说明 cat etc redhat release CentOS Linux release 7 9 2009 Core 一 使用rke命令安装 k8s集群 1 在所有节点上安装chronyd服务 yum y install chr
  • 【LeetCode3】无重复字符的最长子串(滑动窗口)

    窗口维护的是无重复字符的最长子串 c int lengthOfLongestSubstring string s vector
  • linux下挂载和卸载cdrom

    1 查询块设备及mount位置 root slave143 lsblk NAME MAJ MIN RM SIZE RO TYPE MOUNTPOINT sr0 11 0 1 3 6G 0 rom type rom表示sr0为 cdrom设备
  • Java生成某段时间内的随机时间

    上代码 1 import java text SimpleDateFormat 2 import java util Date 3 4 public class DateUtil 5 6 7 生成随机时间 8 9 param beginDa
  • Linux部署vue项目

    一 nginx conf配置文件位置 etc nginx nginx conf 二 nginx的常用命令 1 启动 Nginx start nginx 或 systemctl start nginx 2 关闭 Nginx nginx s s
  • 【2023最全最新教程】RobotFramework的介绍与环境搭建(超详细~)

    本文使用的环境 win10系统 python3 6 一 RobotFramework介绍 1 1 框架基本介绍 1 Robot Framework 简称RF 是基于python编写的 开源的 功能自动化框架 2 RF是一款关键字驱动的测试框
  • STM32外设芯片驱动学习记录 —— (一) BH1750光照传感器驱动开发

    目录 一 芯片介绍 二 Datasheet解读 1 硬件说明 2 寄存器说明 3 通信过程 三 驱动代码编写 1 软件I2C驱动 2 BH1750芯片驱动函数 总结 一 芯片介绍 BH1750是16位数字输出型 环境光强度传感器集成电路 使