BH1750 光照传感器文档详解 及 驱动设计

2023-10-27

前言

最近接触到一个应用,需要在低功耗的产品上加上光照度采集,正好最近有接触到一款光照传感器 BH1750 ,性能价格都合适,那么今天就抽空来好好测试一下。

那么要写一篇测试文章,我会尽量以新手的角度从资料的获取,资料的阅读理解,以及根据资料进行驱动设计来做记录 。

我是 矜辰所致,全网同名,尽量用心写好每一系列文章,不浮夸,不将就,认真对待学知识的我们,矜辰所致,金石为开!
插一句,技术群在 CSDN 文章结尾后面的的推广,讨论学习。

一、确认基本参数

传感器资料网上可以找到,实在不行可以去电子商城下载,比如某商城:

在这里插入图片描述

1.1 根据产品特征整体认识产品

那么其实接触一个新的传感器,在传感器文档开头部分,都会有一个 Features ,说明了产品的特征,比如 BH1750 的 Features 如下图:

在这里插入图片描述

上面特征我虽然全部看了,但是我画出了两条,第一条可以得知传感器的通讯方式为 I2C,第二条 具备低功耗的能力可以判断传感器是否符合我们的应用。 当然,其他的特征也得过一遍,看看是否能满足自己的应用场合。

1.2 根据工作条件确定产品的供电方式

继续往下看,我们能看到 Absolute Maximum Ratings 这个电气绝对参数,这个是规定的传感器的耐压等数据,这里了解一下即可,我们更加需要关系的是下面这个图:

在这里插入图片描述

通过上图我们可以直接确定传感器的供电电压。

当然还有一个重要的点就是他的 I2C 参考电压可以达到 Vcc ,这说明在我们常用的 3.3V 供电的 MCU 系统上使用这个传感器不需要做电平转换,可以直接与 MCU 的 I2C 接口连接。

再往下的一些电气参数 Electrical Characteristics 其实过一遍了解一下即可,不仔细也没有太大关系。

1.3 根据推荐电路图确定 PCB 设计

上面我们已经知道了传感器供电电压,那么如果是自己设计 硬件电路的话,那么需要了解:

各个引脚的功能定义

参考产品手册上的推荐电路图

这个在资料往下翻一大段。

引脚的定义如下:

在这里插入图片描述

这里加一个判别传感器1引脚的方法:

上图中,传感器中间有一个品字形状,我们拿到传感器仔细看,也能看到品字形状,根据这个形状判断 引脚即可。

在文档后面有引脚的定义:

在这里插入图片描述

我这里自己写一个表格做简要说明:

名称 功能
VCC 电源
ADDR 传感器地址引脚,ADDR 高低电平传感器地址不一样 ,高电平:0x5C 低电平: 0x23
GND GND
SDA I2C 数据线
DVI SDA和 SCL 的参考电压,内部寄存器的异步重置端口,在供电以后需要保持低电平,在内部通过 150k 的电阻下拉到地
SCL I2C 时钟线

当 ADDR 为高电平的时候,传感器地址为 1011100 :0x5C;

当 ADDR 为低电平的时候,传感器地址为 0100011 :0x23;

接下来我们来看看推荐电路图 ,注意手册中的说明:

在这里插入图片描述
图中 SDA 和 SCL 以及省略了,还得注意一下 ADDR 的高低电平,因为决定了传感器的地址。

在手册中推荐了 4 种电路图,我这里推荐的是使用第四种(需要知道一下这种无法满足内部寄存器重置的操作):

在这里插入图片描述

如果使用这种方式,那么我们接下来操作传感器的地址就是:0x23。

对于硬件相关的东西我们确定好了以后,我们可以自己画 PCB ,要记住 I2C 通讯是需要上拉电阻的。当然如果是采购的现成的传感器模块可以省略。

采购的传感器模块一般都只需要连接 4个引脚,就是标准的 I2C 通讯的 :SCL、 SDA、VCC、GND 。

博主本次采用的传感器其实也是采购的成品小板子,但是正真的最后还是会自己画的,到时候有机会也来记录一下自己画的用作低功耗的小板子:

在这里插入图片描述

二、工作流程及指令

我们完成硬件的基本了解,可以了解一下传感器的工作流程级操作指令。

2.1 工作流程分析

在资料手册中,列出了 Measurement Procedure 部分,如下图:

在这里插入图片描述

对于低功耗的产品,我们都会使用单次测量模式,可以最大限度的控制功耗。

我们可以直接总结出来,我们如果使用单次测量命令的话,我们在初始化传感器的时候就可以使用指令让模块进入单次测量模式:

初始化:

模块上电 ——> 发送指令使模块进入单次测量模式

正常工作流程:

发送指令使模块进入上电模式 ——> 发送测量命令 ——> 模块测量完成会会自动进入掉电模式(单次测量模式)

2.2 操作命令

在手册中给出了操作命令,但是根据我们前面的分析,我们需要用到的指令并不多,在图中我圈出了我们可能需要用到的指令:

在这里插入图片描述

其中我们只需要记住单次测量的命令就可以了,使用什么分辨率根据自己的情况而定。

2.3 单次测量示例解析

为了更好的说明命令怎么用,在手册中也已经举了例子,我给他加上了中文注释说明测量流程:

在这里插入图片描述

传感器手册读到这里,基本上已经满足我们的开发需求,我们下面就开始根据上面所分析的资料进行程序设计。

三、程序设计

本次的测试基于 STM32L051 ,但是其实在驱动程序中体现不出来,因为用的软件 I2C ,驱动基本上可以移植到各种单片机平台。

在我们使用 i2c 传感器的时候,一般都是有一个通用驱动文件,然后还有一个传感器的驱动文件,如下图(d6t44l 是一个 I2C 传感器):

在这里插入图片描述

对于 I2C 的基础知识,本文不做过多讨论,大家应该比较熟悉,不熟悉的可以复习一下基础知识。

3.1 I2C 通用驱动

通用驱动就包括了 ,I2C 启动,结束,发送等待 ACK ,发送不等待 ACK ,读取,等待 ACK 等等这些函数,这个其实在很多开源的项目中找一个就可以了。

我们这里先确定一下 i2c.h 文件,针对自己的设备连接的 IO 口进行定义:

在这里插入图片描述

这里因为大家都很方便的可以找到开源的驱动,唯独需要注意上图中的定义,改成自己测试的 IO 口,所以这里就不过多解释,直接把通用驱动放上 :

i2c.h:

#ifndef _I2C_H_INCLUDED
#define _I2C_H_INCLUDED

#include "main.h"
#include "Datadef.h"
        
#define MYIIC_CLK_HIGH      HAL_GPIO_WritePin(SCL_GPIO_Port,SCL_Pin,GPIO_PIN_SET) 
#define MYIIC_CLK_LOW  	    HAL_GPIO_WritePin(SCL_GPIO_Port,SCL_Pin,GPIO_PIN_RESET) 

#define MYIIC_DATA_HIGH   HAL_GPIO_WritePin(SDA_GPIO_Port,SDA_Pin,GPIO_PIN_SET) 
#define MYIIC_DATA_LOW    HAL_GPIO_WritePin(SDA_GPIO_Port,SDA_Pin,GPIO_PIN_RESET)
#define MYIIC_DATA_STATE  HAL_GPIO_ReadPin(SDA_GPIO_Port,SDA_Pin)
                         
                         
// ------------------------
#define DONOTHING()          {;}

// ------------------------
// command's
#define I2C_WRITE             0 
#define I2C_READ              1
#define I2C_ACK               0
#define I2C_NACK              1


void MYIIC_Start(void);
void MYIIC_Stop(void);
u8 MYIIC_Wait_Ack(void);
void IIC_NAck(void);
void IIC_Ack(void);
void IIC_Send_Byte(u8 txd);
u8 IIC_Read_Byte(unsigned char ack);

#endif

i2c.c:

#include "i2c.h"

void MYIIC_Start(void)
{
   MYIIC_DATA_HIGH;
   delay_us(5);
   MYIIC_CLK_HIGH;
   delay_us(10);
   MYIIC_DATA_LOW;
   delay_us(10);
   MYIIC_CLK_LOW; //使SCL置低,准备发送或者接受数据
   delay_us(10);
}

void MYIIC_Stop(void)
{ 
   MYIIC_DATA_LOW;
   delay_us(5);
   MYIIC_CLK_LOW;
   delay_us(10);
   MYIIC_CLK_HIGH;
   delay_us(5);
   MYIIC_DATA_HIGH;
   delay_us(10); 
}

//读1个字节,ack=1时,发送ACK,ack=0,发送nACK   
u8 IIC_Read_Byte(unsigned char ack)
{
	unsigned char i,receive=0;
	// MYSDA_IN;//SDA设置为输入
   for(i=0;i<8;i++ )
	{
        MYIIC_CLK_LOW;    //SCL为由低变高,在SCL高的时候去读 SDA的数据
        delay_us(10);
		  MYIIC_CLK_HIGH;
        receive<<=1;  //第一次这里还是0,第二次开始每次接收的数据做移动一位,从高位开始接收
        if(MYIIC_DATA_STATE)receive++;   //如果数据为1,++以后就是1,数据为0,不执行就是0; 
		  delay_us(10); 
   }					 
   if (!ack)
        IIC_NAck();//发送nACK
   else
        IIC_Ack(); //发送ACK   
   return receive;
}


u8 MYIIC_Wait_Ack(void)
{
    u8 ucErrTime=0;
	delay_us(5);
    MYIIC_DATA_HIGH;delay_us(5);       //MCU DATA 置高,外面高就是高,外面低就是低
    MYIIC_CLK_HIGH; delay_us(5);       //CLK 高电平期间数据有效
    while(MYIIC_DATA_STATE)             //低电平为有应答,高电平无应答    
    {
      ucErrTime++;
		if(ucErrTime>250)
		{
			MYIIC_Stop();
			return 1;
		}  
    }
		delay_us(10);
    MYIIC_CLK_LOW;
    return 0;
}

void IIC_Ack(void)
{
	MYIIC_CLK_LOW;    //SCL为低,SDA为低,SCL为高,SDA为低,应答低电平有效,SCL为低,产生应答信号
	// MYSDA_OUT;
	MYIIC_DATA_LOW;
	delay_us(10);
	MYIIC_CLK_HIGH;
	delay_us(10);
	MYIIC_CLK_LOW;
	delay_us(10);
	MYIIC_DATA_HIGH;
}

void IIC_NAck(void)
{
	MYIIC_CLK_LOW;     //SCL为低,SDA为高,SCL为高,SCL为低
	// MYSDA_OUT;
	MYIIC_DATA_HIGH;
	delay_us(10);
	MYIIC_CLK_HIGH;
	delay_us(10);
	MYIIC_CLK_LOW;
}

//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答			  
void IIC_Send_Byte(u8 txd)
{                        
   u8 t;   
	// MYSDA_OUT; 	    
   MYIIC_CLK_LOW;  //拉低时钟开始数据传输   ,SCL为低,SDA变高或者变低(数据位),SCL变高,SCL变低,期间SDA为1既1,为0既0
   for(t=0;t<8;t++)  //一个字节8位,一位一位发送
    {              
     MYIIC_CLK_LOW;
		if((txd&0x80)>>7)   //从最高位开始发送,如果是1,发送高电平
			MYIIC_DATA_HIGH;
		else
			MYIIC_DATA_LOW;
		txd<<=1; 	      //SDA处理完毕,此时可以将SCL拉高接受数据,拉高以后延时拉低
		delay_us(10);   //
		MYIIC_CLK_HIGH;
		delay_us(10); 
		MYIIC_CLK_LOW;	
		delay_us(5);
    }	 
}

3.2 BH1750 驱动

完成了通用驱动,我们现在就可以完全根据前面的分析流传进行 BH1750 的驱动设计。

我们新建一个 bh1750.cbh1750.h 文件,在头文件中进行一些必要的宏定义:

在这里插入图片描述

把可能需要用到的都给他定义一遍,后面需要改正再说。

然后开始在 c 文件中写驱动,首先当然是传感器初始化,上电就得设置为单次测量模式,那么发送数据就得按照前面给出的分析。

首先传感器上电初始化给他写个函数:

在这里插入图片描述

然后读取函数,因为只需要读取2个字节,所以也比较简单:

在这里插入图片描述

最后在需要的地方调用函数即可:

在这里插入图片描述

这里还是把 传感器测试驱动源码放上。

bh1750.c

#include "bh1750.h"
#include <stdio.h>

/*
说明,测试程序,函数不判断是否成功
*/

void bh1750_init()
{
	MYIIC_Start();
	IIC_Send_Byte(BH1750_ADDRESS << 1); //地址,和读写指令
	MYIIC_Wait_Ack();
	delay_us(150); 
	// IIC_Send_Byte(BH1750_CMD_POWERON);  // 电不一定需要,这里测试看看
	// MYIIC_Wait_Ack();
	// delay_us(150); 
	IIC_Send_Byte(BH1750_MODE_ONE_H_RES);  //单次测量
	MYIIC_Wait_Ack();
	HAL_Delay(BH1750_MEASURE_DURATION_MS);
	MYIIC_Stop();
}

void bh1750_read(uint16_t *lux)
{
	uint8_t read_buffer[2];

	MYIIC_Start();
	IIC_Send_Byte(BH1750_ADDRESS << 1); //地址,和读写指令
	MYIIC_Wait_Ack();
	delay_us(150); 
	IIC_Send_Byte(BH1750_MODE_ONE_H_RES);  //单次测量
	MYIIC_Wait_Ack();
	MYIIC_Stop();
	HAL_Delay(BH1750_MEASURE_DURATION_MS);
	MYIIC_Start();
	IIC_Send_Byte((BH1750_ADDRESS << 1)|1); //地址,和读写指令
	MYIIC_Wait_Ack();

	read_buffer[0] = IIC_Read_Byte(1);
	delay_us(120);
	read_buffer[1] = IIC_Read_Byte(0);
	delay_us(120);
	
	MYIIC_Stop();

	uint32_t lv_lux = ((read_buffer[0] << 8) | read_buffer[1]) * 10 / 12;
	*lux = (uint16_t)lv_lux;

}

bh1750.h

#ifndef __BH1750_H
#define __BH1750_H

#include "i2c.h"
#include "main.h"

// BH1750 working mode
#define BH1750_MODE_CONT_H_RES 			0x10
#define BH1750_MODE_CONT_H_RES2			0x11
#define BH1750_MODE_CONT_L_RES 			0x13
#define BH1750_MODE_ONE_H_RES 			0x20
#define BH1750_MODE_ONE_H_RES2 			0x21
#define BH1750_MODE_ONE_L_RES 			0x23

#define BH1750_MEASURE_DURATION_MS		120			// Max. 180ms

#define BH1750_CMD_POWERDOWN            0x00
#define BH1750_CMD_POWERON              0x01
#define BH1750_CMD_RESET                0x07

#define BH1750_ADDRESS                  0x23			// 0x23 (ADDR='L') or 0x5C (ADDR='H')


void bh1750_init();
void bh1750_read(uint16_t *lux);


#endif

3.3 测试效果

测试是比较简单的,直接通过串口助手看结果就行了,本次根据手册设计的驱动算是成功的:

在这里插入图片描述

结语

本文我们从一个传感器的基本资料入手,完成了一个传感器的驱动设计。

算是给新手工程师们做了一个示例,如何去阅读传感器文档资料,如何获取我们有用的东西。

当然本次也只是一个基本测试,后面我还需要自己画个板子,主要是看看这个传感器的低功耗效果,而且方案需要应用在别的硬件上面,还需要做电平转换,这个后面如果有机会再来做实际应用的记录。

本文就到这里,谢谢大家! 另外,别忘了下面可以加我的技术群哦!

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

BH1750 光照传感器文档详解 及 驱动设计 的相关文章

随机推荐

  • PHP7.27: connect mysql 5.7 using new mysqli_connect

  • Jenkins:报错Build step ‘Execute Windows batch command‘ marked build as failure解决办法

    Windows 下本地的 Jenkins 部署完成后 创建任务进行构建时 遇到如下报错信息 构建虽然失败了 但是命令却是执行成功了 问题就在于 Build step Execute Windows batch command marked
  • 数字媒体资产管理教材

    http vr sdu edu cn lulin course DAM
  • 产量预测文献读后整理

    文献名称 1 Data Driven End To End Production Prediction of Oil Reservoirs by EnKF Enhanced Recurrent Neural Networks 2 Produ
  • TensorFlow实现简单神经网络

    本文首发于我的个人博客QIMING INFO 转载请带上链接及署名 在上文 TensorFlow快速上手 中 我们介绍了TensorFlow中的一些基本概念 并实现了一个线性回归的例子 本文我们趁热打铁 接着用TensorFlow实现一下神
  • 前端强缓存和协商缓存

    缓存是前端面试的一个常见知识点 下面对于实际项目中如何进行缓存的设置给出方案 强缓存和协商缓存 浏览器缓存是浏览器将用户请求过的静态资源存储到电脑本地磁盘中 当再次访问时 就可以直接从本地缓存中加载而不需要去向服务器请求了 但是缓存也有缺点
  • C++内存泄露检测器(库注入方法)

    C 内存泄露检测器 库注入方法 2012 06 18 15 55 04 分类 C C codeproject上的一篇文章 翻译过来共享 C Memory Leak Finder C 内存泄露检测器 leakfinder zip 作者 Fre
  • GPT专业应用:早晚安问候语生成

    正文共 725 字 阅读大约需要 3 分钟 社群运营必备技巧 您将在3分钟后获得以下超能力 自动生成早晚安问候语 Beezy评级 B级 经过简单的寻找 大部分人能立刻掌握 主要节省时间 推荐人 nanako 编辑者 Linda 此图片由Le
  • 【Java 微服务架构 Dubbo篇】-1-Zookeeper

    课程回顾 微服务架构需要解决的问题 分布式协调框架Zookeeper 什么是分布式协调技术 分布式协调技术主要用来解决分布式环境当中多个进程之间的同步控制 让他们有序的去访问某种临界资源 防止造成 脏数据 的后果 在这图中有三台机器 每台机
  • LSTM神经网络详解

    LSTM 长短时记忆网络 Long Short Term Memory Network LSTM 是一种改进之后的循环神经网络 可以解决RNN无法处理长距离的依赖的问题 目前比较流行 长短时记忆网络的思路 原始 RNN 的隐藏层只有一个状态
  • Java学习笔记(02_1Java语言基础)

    知识点总结于毕向东Java基础视频教程25天版本 侵权请联系删除 第二章 Java语言基础 Java语言基础组成 关键字 标识符 注释 常量与变量 常量 变量 类型转换 运算符 算术运算符 赋值运算符 比较运算符 逻辑运算符 位运算符 三元
  • ajax后台返回的数据为空前台显示出现undefined的解决方法

    之前自己做的一个图书管理系统 显示图书借阅排行榜 因为翻译在数据库中有为空的字段 故前台显示会显示undefined 以下贴上部门代码 document ready function rankTable tbody html var id
  • chromium源码的下载与编译

    这篇文章主要记录在chromium源码下载以及编译过程中遇到的问题 一直都对chromium的源码感兴趣 在没有封闭外网之前 下载了一个版本 很老了 重新进行更新又不得行 再加上公司的产品线路需要了解chromium的相关知识 又加上疫情封
  • Ctfshow web入门 PHP特性篇 web89-web151 全

    web入门 PHP特性篇的wp都一把梭哈在这里啦 有点多 师傅们可以收藏下来慢慢看 写的应该挺全面的叭 有错误敬请斧正 CTFshow PHP web89 看题目 有个flag php文件 题目要求get有个num 是数字但是不包含0 9
  • 吴恩达深度学习笔记-单层神经网络(第2课)

    深度学习笔记 1 神经网络概览 2 神经网络表示 3 计算神经网络的输出 4 多个样本的向量化 5 向量化实现的解释 6 激活函数 7 为什么需要非线性激活函数 8 激活函数的导数 9 神经网络的梯度下降法 10 直观理解反向传播 11 随
  • SQL-万能密码

    打开目标站点 随便输入用户名密码 查看返回结果 提示错误 后台管理http 10 225 91 25 知识点 这题需要用到万能密码 首先了解一下万能密码 一般的 库验证登录注册查询数据会用到以下的句型 如果用户名与密码匹配正确则返回真值通过
  • Webpack配置

    Webpack 文章目录 Webpack 一 Webpack的基本功能 二 Webpack的核心概念 三 Webpack常用的Loader 四 Webpack常见的Plugins 五 Loader和Plugin的区别 以及如何自定义Load
  • Ehcache是现在最流行的纯Java开源缓存框架

    Ehcache是现在最流行的纯Java开源缓存框架 配置简单 结构清晰 功能强大 最初知道它 是从Hibernate的缓存开始的 网上中文的EhCache材料以简单介绍和配置方法居多 如果你有这方面的问题 请自行google 对于API 官
  • java枚举和数值的相互转换

    枚举简介 enum 的全称为 enumeration 是 JDK 1 5 中引入的新特性 存放在 java lang 包中 在实际编程中 往往存在着这样的 数据集 它们的数值在程序中是稳定的 而且 数据集 中的元素是有限的 此时枚举可以很方
  • BH1750 光照传感器文档详解 及 驱动设计

    前言 最近接触到一个应用 需要在低功耗的产品上加上光照度采集 正好最近有接触到一款光照传感器 BH1750 性能价格都合适 那么今天就抽空来好好测试一下 那么要写一篇测试文章 我会尽量以新手的角度从资料的获取 资料的阅读理解 以及根据资料进