STM32外设系列—BH1750

2023-11-14

一、BH1750简介

BH1750是一款数字型光照强度传感器,能够获取周围环境的光照强度。其测量范围在0~65535 lx。lx勒克斯,是光照强度的单位。BH1750可用于调节手机屏幕和键盘的背光功率,或者用于智能灯光控制,比如,随着外界光照强度的变化调节灯光亮度。

BH1750

BH1750有以下特点

  • I2C总线接口
  • 接近视觉灵敏度的光谱灵敏度特性
  • 输出对应亮度的数字值
  • 高分辨率(0~65535 lx)
  • 通过降低功率功能,实现低电流化
  • 50Hz / 60Hz光噪声抑制功能
  • 可以选择两种类型的I2C从属地址
  • 最小误差变动在±20%
  • 受红外线影响很小

二、BH1750原理图

BH1750原理图

  • PD —— 接近人眼反应的光敏二极管
  • AMP —— 集成运算放大器(将 PD 电流转换为 PD 电压)
  • ADC —— 模数转换获取 16 位数字数据
  • Logic + IC Interface(逻辑+ IC 界面)
  • OSC —— 内部振荡器(该时钟为内部逻辑时钟,时钟频率典型值:320kHz)

PD二极管通过光伏效应将输入光信号转换成电信号,经运放电路放大后,电压经ADC采集,再经逻辑电路转换成16位二进制数,存储在内部的寄存器中(进入光窗的光越强,光电流越大,电压就越大,所以光强可以通过电压的大小判断,但是应该注意的是,虽然电压和光强一一对应,但它们不是成正比关系,所以该芯片内部是对数据进行了线性处理,这就是为什么直接使用集成IC而不是光电二极管的原因)。BH1750引出了时钟线和数据线,单片机可以通过I2C协议与BH1750进行通讯,可选择BH1750的工作模式,提取BH1750寄存器中的照度数据。

三、BH1750数据手册

3.1 指令集

BH1750的数据手册中给出了一些指令

BH1750指令集

其中的H分辨率模式和L分辨率模式等,是BH1750的测量模式,数据手册中也给出了说明

BH1750测量模式

我们通常使用H分辨率模式,H 分辨率模式下足够长的测量时间(积分时间)能够抑制一些噪声(包括 50Hz/60Hz)。同时,H 分辨率模式的分辨率在 1lx 下,适用于黑暗场合下(少于 10 lx)。

3.2 IIC通信读/写

上面介绍,BH1750有两种从属地址,由 ADDR 端口的电平决定。

  • ADDR=“H”( ADDR ≧ 0.7VCC ) →“1011100”
  • ADDR=“L”( ADDR ≦ 0.3VCC ) →“0100011”

关于IIC通信的详细内容,这里就不再介绍了,可以去本系列的OLED篇查看。BH1750数据手册中给出了一种配置连续高分辨率模式的方法

配置连续高分辨率模式方法步骤

BH1750数据读取格式如下

BH1750数据读取格式

光照强度(单位lx)=(High Byte + Low Byte)/ 1.2 * 测量精度

四、BH1750程序设计

4.1 IIC程序

相比于之前的OLED的IIC程序,增加了主设备发送应答信号(Ack),非应答信号(NAck),读取一个字节数据程序。修改了等待应答信号程序,增加了返回值。

/*
 *==============================================================================
 *函数名称:IIC_Delay
 *函数功能:IIC延时
 *输入参数:无
 *返回值:无
 *备  注:数据手册提供
 *==============================================================================
 */
void IIC_Delay (void)
{
	u8 t = 10;
	while (t--);
}
/*
 *==============================================================================
 *函数名称:I2C_Start
 *函数功能:IIC起始信号
 *输入参数:无
 *返回值:无
 *备  注:数据手册提供
 *==============================================================================
 */
void I2C_Start (void)
{
	BH1750_SDA_Set();
	BH1750_SCL_Set();
	IIC_Delay();
	BH1750_SDA_Clr();
	IIC_Delay();
	BH1750_SCL_Clr();
	IIC_Delay();
}
/*
 *==============================================================================
 *函数名称:I2C_Stop
 *函数功能:IIC终止信号
 *输入参数:无
 *返回值:无
 *备  注:数据手册提供
 *==============================================================================
 */
void I2C_Stop (void)
{
	BH1750_SDA_Clr();
	BH1750_SCL_Set();
	IIC_Delay();
	BH1750_SDA_Set();
}
/*
 *==============================================================================
 *函数名称:IIC_Ack
 *函数功能:CPU产生一个ACK信号
 *输入参数:无
 *返回值:无
 *备  注:无
 *==============================================================================
 */
void IIC_Ack (void)
{
	BH1750_SDA_Clr();
	IIC_Delay();
	BH1750_SCL_Set();
	IIC_Delay();
	BH1750_SCL_Clr();
	IIC_Delay();
	BH1750_SDA_Set();
}
/*
 *==============================================================================
 *函数名称:IIC_NAck
 *函数功能:CPU产生一个NACK信号
 *输入参数:无
 *返回值:无
 *备  注:无
 *==============================================================================
 */
void IIC_NAck (void)
{
	BH1750_SDA_Set();
	IIC_Delay();
	BH1750_SCL_Set();
	IIC_Delay();
	BH1750_SCL_Clr();
	IIC_Delay();	
}
/*
 *==============================================================================
 *函数名称:I2C_WaitAck
 *函数功能:IIC等待应答
 *输入参数:无
 *返回值:0:未收到应答信号;1:收到应答信号
 *备  注:无
 *==============================================================================
 */
u8 I2C_WaitAck (void)
{
	u8 re;

	BH1750_SDA_Set();
	IIC_Delay();
	BH1750_SCL_Set();
	IIC_Delay();
	if (BH1750_SDA_DATA())
	{
		re = 1;
	}
	else
	{
		re = 0;
	}
	
	BH1750_SCL_Clr();
	IIC_Delay();
	
	return re;
}
/*
 *==============================================================================
 *函数名称:Send_Byte
 *函数功能:写入一个字节
 *输入参数:dat:需要写入的数据
 *返回值:无
 *备  注:数据手册提供
 *==============================================================================
 */
void Send_Byte (u8 dat)
{
	u8 i;

	for (i = 0;i < 8;i ++)
	{
		// 发送数据时,从高位依次写入
		if (dat & 0x80)
		{
			BH1750_SDA_Set();
		}
		else
		{
			BH1750_SDA_Clr();
		}
		IIC_Delay();
		BH1750_SCL_Set();
		IIC_Delay();
		BH1750_SCL_Clr();
		
		// dat左移1位
		dat <<= 1;
	}
}
/*
 *==============================================================================
 *函数名称:IIC_Read_Byte
 *函数功能:IIC读取一个字节数据
 *输入参数:无
 *返回值:无
 *备  注:读取到的一个字节数据
 *==============================================================================
 */
u8 IIC_Read_Byte (void)
{
	u8 i;
	u8 value;
	
	// 高位在前
	value = 0;
	
	// 循环读取8bit数据
	for (i = 0; i < 8; i ++)
	{
		value <<= 1;   // 循环左移一位
		
		BH1750_SCL_Set();
		IIC_Delay();
		
		// 如果是“1”
		if (BH1750_SDA_DATA())
		{
			value ++;
		}
		
		BH1750_SCL_Clr();
		IIC_Delay();
	}
	
	return value;
}
//BH1750写一个字节
//返回值	成功:0		失败:非0 
/*
 *==============================================================================
 *函数名称:BH1750_Byte_Write
 *函数功能:BH1750写一个字节
 *输入参数:data:要写入的数据
 *返回值:0:写入成功;1/2:写入失败
 *备  注:无
 *==============================================================================
 */
u8 BH1750_Byte_Write (u8 data)
{
	I2C_Start();
	
	// 发送从设备地址,0:写
	Send_Byte (BH1750_Addr | 0);
	
	// 收到应答信号
	if(I2C_WaitAck() == 1)
	{
		return 1;
	}
	//发送控制命令
	Send_Byte(data);
	
	// 收到应答信号
	if(I2C_WaitAck() == 1)
	{
		return 2;
	}
	
	I2C_Stop();
	
	return 0;
}

4.2 BH1750初始化程序

初始化包括两部分,一部分是初始化IIC引脚,另一部分是初始化BH1750。也就是给BH1750上电,并复位。

/*
 *==============================================================================
 *函数名称:Drv_Bh1750_Init
 *函数功能:初始化BH1750
 *输入参数:无
 *返回值:无
 *备  注:无
 *==============================================================================
 */
void Drv_Bh1750_Init (void)
{
	// 结构体定义
 	GPIO_InitTypeDef  GPIO_InitStructure;
	
	// 开启时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	// 初始化GPIO结构体
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;	 
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   // 推挽式输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 	GPIO_Init(GPIOB, &GPIO_InitStructure);
	// 全部拉高,IIC处于空闲状态
 	GPIO_SetBits(GPIOB,GPIO_Pin_6 | GPIO_Pin_7);
	
	// BH1750上电
	BH1750_Byte_Write(POWER_ON);
	
	// 复位BH1750
	BH1750_Byte_Write(MODULE_RESET);
}

4.3 读取BH1750测量结果

BH1750返回两字节的测量结果数据

/*
 *==============================================================================
 *函数名称:Drv_Bh1750_Read_Measure
 *函数功能:读取BH1750测量数据
 *输入参数:无
 *返回值:0:读取失败;其他:光照强度
 *备  注:无
 *==============================================================================
 */
u16 Drv_Bh1750_Read_Measure (void)
{
	u16 receData = 0;
	
	I2C_Start();
	
	// 发送从设备地址,1:读
	Send_Byte(BH1750_Addr | 1);
	
	if(I2C_WaitAck() == 1)
	{
		return 0;
	}
	
	// 读取高八位
	receData = IIC_Read_Byte();
	IIC_Ack();
	
	// 读取低八位
	receData = (receData << 8) + IIC_Read_Byte();
	IIC_NAck();
	I2C_Stop();
	
	return receData;   // 返回读取到的数据
}

4.4 获取光照强度

/*
 *==============================================================================
 *函数名称:Med_Bh1750_GetLightIntensity
 *函数功能:获取光照强度
 *输入参数:无
 *返回值:光照强度
 *备  注:分辨率	光照强度(单位lx)=(High Byte  + Low Byte)/ 1.2 * 测量精度
 *==============================================================================
 */
float Med_Bh1750_GetLightIntensity (void)
{
	return (float)(Drv_Bh1750_Read_Measure() / 1.1f * Resolurtion);   //返回测量光照强度
}

4.5 相关宏定义

// BH1750的地址(ADDR=“H”)
#define BH1750_Addr   0x46

// BH1750指令
#define POWER_OFF					0x00
#define POWER_ON					0x01
#define MODULE_RESET			0x07
#define	CONTINUE_H_MODE		0x10
#define CONTINUE_H_MODE2	0x11
#define CONTINUE_L_MODE		0x13
#define ONE_TIME_H_MODE		0x20
#define ONE_TIME_H_MODE2	0x21
#define ONE_TIME_L_MODE		0x23

//测量模式
#define Measure_Mode   CONTINUE_H_MODE

//分辨率	光照强度(单位lx)=(High Byte  + Low Byte)/ 1.2 * 测量精度
#if ((Measure_Mode == CONTINUE_H_MODE2)|(Measure_Mode == ONE_TIME_H_MODE2))
	#define Resolurtion		0.5
#elif ((Measure_Mode == CONTINUE_H_MODE)|(Measure_Mode == ONE_TIME_H_MODE))
	#define Resolurtion		1
#elif ((Measure_Mode == CONTINUE_L_MODE)|(Measure_Mode == ONE_TIME_L_MODE))
	#define Resolurtion		4
#endif

// SCL
#define BH1750_SCL_Clr()   GPIO_ResetBits(GPIOB,GPIO_Pin_6)
#define BH1750_SCL_Set()   GPIO_SetBits(GPIOB,GPIO_Pin_6)
// SDA
#define BH1750_SDA_Clr()   GPIO_ResetBits(GPIOB,GPIO_Pin_7)
#define BH1750_SDA_Set()   GPIO_SetBits(GPIOB,GPIO_Pin_7)

// 读取SDA电平
#define BH1750_SDA_DATA()   GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_7)

五、应用实例

使用串口打印光照强度,main函数如下

float gLingtIntensity = 0;

int main(void)
{
	Med_Mcu_Iint();   // 系统初始化
	
	while(1)
  {
		gLingtIntensity = Med_Bh1750_GetLightIntensity();   // 获取光照强度
		printf ("Light:%.1f lx",gLingtIntensity);   // 串口打印光照强度
		
		delay_ms(500);   //延时500ms = 0.5s
	}
}

六、拓展应用

利用BH1750获取到的周围环境光强可用于许多方面,这里举几个例子,比如设计一个教室灯光控制系统,根据实际环境光强来调节灯光亮度,使室内环境光强保持在一个稳定的值。另外,比如做颜色识别时,周围环境的光照强度不同,识别的效果也不同。可以利用BH1750实时监测周围环境光照强度变化,不同的光照强度下,切换不同的颜色阈值,可以改善颜色识别的效果。这里简单介绍一下实现思路。

6.1 实时调节LED亮度

可以用PWM来控制LED的亮度。根据周围环境的光照强度的变化,实时调节PWM的占空比,达到LED亮度根据周围环境光照强度变化而变化的效果。但是需要注意光照强度与占空比的换算关系。

6.2 实时调整颜色阈值

比如使用Open MV做颜色是别时,在不同光照强度下,同一种颜色的颜色阈值不同,可以根据不同的光照强度,匹配不同的颜色阈值。

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

STM32外设系列—BH1750 的相关文章

  • Robot Framework 自动化测试详解

    一 Robot Framework 简介 1 界面自动化测试工具 界面自动化测试 即UI自动化测试 比较常见的工具有 QTP AutoIt Selenium等 像QTP经历了很多版本 最新的版本好像叫UFT了 对初学者来说 录制回放是相当容
  • 搭建免费IP代理池

    声明 本文章中所有内容仅供学习交流 不可用于任何商业用途和非法用途 否则后果自负 如有侵权 请联系作者立即删除 由于本人水平有限 如有理解或者描述不准确的地方 还望各位大佬指教 搭建代理池思路 思路来源 崔庆才大佬的爬虫书 代理从何而来 用

随机推荐

  • 网络安全面试必问

    项目经历 因为大家写的都是渗透相关 所以编故事也要编的圆润些 题材可以去freebuf看 https search freebuf com search search E6 8C 96 E6 B4 9E article 这里主要记录如何挖洞
  • 三类保留地址(私有地址)【个人笔记,仅供参考】

    A类 10 X X X是私有地址 私有地址就是在互联网上不使用 而被用在局域网络中的地址 127 X X X是保留地址 用做循环测试用的 B类 172 16 0 0 172 31 255 255是私有地址 169 254 X X是保留地址
  • 在Anaconda下安装并使用Pytorch,pillow,numpy等库及Python版本的匹配

    我在Anaconda下创建的新环境为 python 3 7 0 pytorch 1 8 0 pillow 9 5 0 numpy 1 21 5 能够正常运行 如果我这个版本够用的话可以按照这个版本进行安装 具体步骤如下 1 在Anacond
  • PROFINET从站设备描述文件

    目录 一 GSDML文件名格式 二 设备标识信息 三 设备支持的通讯周期时间 四 设备支持的槽位和数据模块 相信熟悉工业现场的工程师们 对于PROFIBUS和PROFINET这两个工业协议都不陌生 过去在使用PROFIBUS现场总线时 从站
  • matlab 专家pid,专家PID

    3 专家控制器 专家控制器的模型是整个仿真模型中的重点 其实质就是把专家规则用Matlab现有计算元件实现出来 当前一般的做法就是利用 IF THEN 语句来表述一条一条的专家规则 28 把单回路控制中的部分规则做成的专家控制器如下所示 图
  • 什么是Elastic Stack

    什么是Elastic Stack Elastic Stack是由ELK演化而来 ELK是三种软件的简称 分别是Elasticsearch logstash kibana组成 在发展的过程中 又有新成员Beats的加入 形成了Elastic
  • Hadoop运行模式 之 本地运行模式

    Hadoop的运行模式包括 本地模式 伪分布式模式以及完全分布式模式 Hadoop官网地址 https hadoop apache org 本次使用的Hadoop的版本是2 7 2 官网文档 https hadoop apache org
  • ssh-keygen 常用命令与参数

    ssh keygen 常用命令与参数 生成密钥 默认生成 2048 位 RSA 密钥 ssh keygen 生成 4096 位 RSA 密钥 ssh keygen t rsa b 4096 生成 521 位 ECDSA 密钥 ssh key
  • sql注入基础原理(超详细)

    一 Sql注入简介 Sql 注入攻击是通过将恶意的 Sql 查询或添加语句插入到应用的输入参数中 再在后台 Sql 服务器上解析执行进行的攻击 它目前黑客对数据库进行攻击的最常用手段之一 二 Web 程序三层架构 三层架构 3 tier a
  • qt信号槽之创建和连接自定义的槽

    在第一版的Qt设计器中 你可以创建你自定义的槽的信号并使他们连接起来 但是你不能直接实现你的槽 你不得不子集于该窗体 并在这个子集中对你自定义的槽编码 子集的方法依然有用 在某些情况下仍起作用 Make sense 但是现在你可以在Qt设计
  • R语言入门

    安装 R语言开源 安装很简单 此处带过 界面 R语言的使用简介 赋值命令 赋值符号为 lt 或 但是建议使用 lt x lt 10 赋值10给变量x R语言的数据类型 R是一种基于对象 object 的语言 在R中看到的一切事物都是对象 对
  • JAVA遇见HTML—JSP篇(六.JSP指令与动作元素)

    include指令 语法 代码示例 新建date jsp文件
  • TensorFlow2.0.0开发环境安装

    TensorFlow 框架支持多种常见的操作系统 如 Windows 10 Ubuntu 18 04 Mac OS 等等 同时也支持运行在 NVIDIA 显卡上的 GPU 版本和仅适用 CPU完成计算的 CPU 版本 我们以最为常见的 Wi
  • c语言练习49:有多少⼩于当前数字的数字

    有多少 于当前数字的数字 给你 个数组 nums 对于其中每个元素 nums i 请你统计数组中 它 的所有数字的数 换 之 对于每个 nums i 你必须计算出有效的 j 的数量 其中 j 满 j i 且nums j lt nums i
  • 【网络层】网络基础 -- IP协议

    引入 IP 协议头格式 网段划分 特殊的IP地址 IP地址的数量限制 私有IP地址和公网IP地址 分片与组装 如何分片与组装 引入 我们前面学习了传输层的相关知识 难道真的就是直接传送吗 当然不是 那TCP究竟做了什么 IP又扮演什么角色
  • Unity3d 制作一个简单的NPC对话系统

    制作一个简单的NPC对话系统 文章目录 制作一个简单的NPC对话系统 前言 效果展示 进入对话区域 开始对话 Inspector面板可调选项 准备工作 NPC UI 代码 完整代码 详细逻辑 开启对话 显示对话 头顶标识 头顶标识 后话 前
  • 算法 - 堆排序(C#)

    csharp view plain copy print
  • 33.121. 买卖股票的最时机

    思路 第一个确定是buyVal 第二个三种情况 大于等于buyVal 就把这个设置为saleVal 小于buyVal buyVal 改变为这个 继续遍历 错误思路 我的想法是 先把买的时机确定了 再确定卖的时机 分类讨论 实际操作过程中 有
  • LayUi做登录注册

    LayUi登录注册页面附代码 登录页面 注册页面 附加CSS JS代码 JS代码 CSS代码 登录页面 下面展示登录页面 代码如下
  • STM32外设系列—BH1750

    文章目录 一 BH1750简介 二 BH1750原理图 三 BH1750数据手册 3 1 指令集 3 2 IIC通信读 写 四 BH1750程序设计 4 1 IIC程序 4 2 BH1750初始化程序 4 3 读取BH1750测量结果 4