STM32应用开发

您所在的位置:网站首页 传感器220 STM32应用开发

STM32应用开发

2024-06-16 05:44| 来源: 网络整理| 查看: 265

STM32应用开发——BH1750光照传感器详解

目录 STM32应用开发——BH1750光照传感器详解前言1 硬件介绍1.1 BH1750简介1.2 硬件接线 2 软件编程2.1 软件原理2.1.1 IIC设备地址2.1.2 IIC读写2.1.3 BH1750指令集2.1.4 BH1750工作流程2.1.5 BH1750测量模式 2.2 测试代码2.3 运行测试2.4 常见问题 结束语

前言

几年前我发布了一篇关于STM32+BH1750光照传感器的博客,因为大学时期经验欠缺,无论是代码还是博客,都有很多不足之处,也收到了非常多同学的反馈。于是我重新整理了代码和文章,这是一个全新版本。

1 硬件介绍 1.1 BH1750简介

BH1750FVI 是一种用于两线式串行总线接口的数字型光强度传感器集成电路。这种集成电路可以根据收集的光线强度数据来调整液晶或者键盘背景灯的亮度。利用它的高分辨率可以探测较大范围的光强度变化。

注:这个模块只适用于室内环境或者学习使用,户外场景下会超量程。

BH1750的引脚如下:

引脚号名称功能1VCC电源正2ADDR地址端口3GND电源负4SDAIIC数据线5DVIIIC端口参考电压6SCLIIC时钟线

注:上述引脚指的是芯片的引脚,如果用的是某宝买的那种传感器模式,引出来的排针引脚排列是不同的。

参考外围电路如下: 在这里插入图片描述

1.2 硬件接线

本文使用STM32F103作为主控MCU,STM32和BH1750的引脚连接如下表:

STM32BH1750功能VCCVCC电源正,3.3V供电GNDGND电源负PB6SCLIIC时钟线,必须外接上拉电阻PB7SDAIIC数据线,必须外接上拉电阻GNDADDR地址端口

注:BH1750用的是模块,模块上已经有接上拉电阻了,因此STM32这边就不需要再接了。另外,ADDR引脚默认有一个下拉电阻,因此不接地其实也是没关系的。

BH1750模块的电路图如下: 在这里插入图片描述

2 软件编程 2.1 软件原理

BH1750是一个IIC设备,通讯协议遵循标准IIC协议。只需要着重关注设备地址,发送命令,读取寄存器即可。

2.1.1 IIC设备地址

所有IIC设备都有一个专属的设备地址,BH1750也不例外,BH1750一共有2个设备地址,可以通过芯片的ADDR引脚切换。 数据手册原文如下: 在这里插入图片描述 翻译过来的话,设备地址的配置如下:

ADDR引脚电平7bit地址8bit地址高电平0x5C0xB8低电平0x230x46

注:这里解释一下7bit地址和8bit地址。 IIC设备的地址一般来说都只有7位,也就是7bit地址,BH1750数据手册上面写的也是7bit地址。 但是设备地址并不是单独使用的,在地址后面需要补1个读写位(不懂的先看下IIC通信协议),也就相当于把7bit的地址左移了1位,那么得到的值就是8bit地址。 所以,在IIC进行读写的时候,要用7bit地址还是8bit地址取决于你这个读写函数里面有没有对这个地址进行移位操作。

2.1.2 IIC读写

1、IIC写入流程。 在这里插入图片描述 时序解释:先发送设备地址+读写位,再发送指令数据。

题外话: 大多数IIC设备,在发送的这串数据中,往往会把第1个字节的数据作为1个寄存器地址(有些也叫偏移),随后才是真正的数据。这样一来,就可以通过1个字节或多个字节的寄存器地址,来实现数据和命令的扩展。 不过BH1750可能是因为功能比较简单,它没有采用这种方式,读写似乎都在同一个寄存器里面操作。

2、IIC读取流程。 在这里插入图片描述 时序解释:先发送设备地址+读写位,随后读取两个数据(其中高位数据在前,低位数据在后)。

题外话: 这个读取的流程跟绝大多数IIC设备的读取流程是一样的。

2.1.3 BH1750指令集

在初始化BH1750时,通过发送1个字节的指令即可配置BH1750的模式。

详细指令集如下表: 在这里插入图片描述

2.1.4 BH1750工作流程

根据数据手册的描述,配置流程如下图:

在这里插入图片描述 总结一下这个流程: 第1步:给BH1750供电。 第2步:BH1750上电后默认为断电模式(此断电模式不是说芯片没有电,而是芯片没有进入工作模式)。 第3步:通过发送指令,把BH1750配置为通电模式(此时芯片进入工作模式)。 第4步:发送测量指令(测量方式有多种,详细信息看上面2.1.3的指令集)。 第5步:读取测量结果并转换成光照值。

按照上面这个流程走,就可以使BH1750正常工作。

2.1.5 BH1750测量模式

BH1750有6种测量模式,每种模式有各自的特点,详见下表:

测量模式精度测量时间备注一次H分辨率模式1 lx120ms该模式配置完成后会自动进行一次测量,测量完成后会切换到断电模式一次H分辨率模式20.5 lx120ms该模式配置完成后会自动进行一次测量,测量完成后会切换到断电模式一次L分辨率模式4 lx16ms该模式配置完成后会自动进行一次测量,测量完成后会切换到断电模式连续H分辨率模式1 lx120ms该模式配置完成后会自动进行连续测量,无需重复配置连续H分辨率模式20.5 lx120ms该模式配置完成后会自动进行连续测量,无需重复配置连续L分辨率模式4 lx16ms该模式配置完成后会自动进行连续测量,无需重复配置

总结: L分辨率模式采集时间短,但精度差,适用于采集光照变化大且变化非常快的场景。 H分辨率模式采集时间长,但精度高,适用于光照变化速度不快的场景。 一次采集模式适用于采集间隔时间长或者需要省电的场景。 连续采集模式适用于对设备节能没有要求的大多数场景。

2.2 测试代码

根据上述原理,编写测试代码,主要的代码清单如下:

文件名代码内容iic_software.h定义了软件IIC所需的引脚定义和电平设置,方便修改IO或者移植iic_software.c软件IIC代码主体iic_hardware.h定义了硬件IIC所需的引脚定义和电平设置,方便修改IO或者移植iic_hardware.c硬件IIC代码主体bh1750.h定义了BH1750的相关信息,如设备地址,命令等bh1750.cBH1750驱动主体,底层调用软件IIC接口uart.c串口主体,用来打印测量过程和结果main.c主函数

注: 1、除了串口的代码,其他代码全部都在下面贴出来了。串口的教程很多,这里就不细说了。 2、我这里采用软件IIC和硬件IIC两种方式测试,但实际上两种方式只能同时使用其中一种。 3、本文主要介绍如何驱动BH1750,尝试了几种测量模式,结果都由串口打印出来,不需要使用串口的话注释掉即可,如果需要现在在LCD屏或者OLED屏,请自行增加这部分的代码。

测试示例代码如下:

iic_software.h : 注:打开宏USE_SOFTWARE_IIC,表示使用软件IIC。此时要注释掉iic_hardware.h的宏USE_HARDWARE_IIC。

#ifndef __IIC_SOFTWARE_H__ #define __IIC_SOFTWARE_H__ #define USE_SOFTWARE_IIC // 使用软件IIC(注:软件IIC和硬件IIC只能同时使用一种) #ifdef USE_SOFTWARE_IIC #include "stm32f10x.h" #include "stm32f10x_gpio.h" // IIC SCL引脚配置 #define IIC_SCL_CLOCK RCC_APB2Periph_GPIOB // 时钟 #define IIC_SCL_PORT GPIOB // 端口 #define IIC_SCL_PIN GPIO_Pin_6 // 引脚号 // IIC SCL电平设置 #define SET_IIC_SCL(s) s > 0 ? GPIO_SetBits(IIC_SCL_PORT, IIC_SCL_PIN) : GPIO_ResetBits(IIC_SCL_PORT, IIC_SCL_PIN) // IIC SDA引脚配置 #define IIC_SDA_CLOCK RCC_APB2Periph_GPIOB // 时钟 #define IIC_SDA_PORT GPIOB // 端口 #define IIC_SDA_PIN GPIO_Pin_7 // 引脚号 // IIC SDA电平设置 #define SET_IIC_SDA(s) s > 0 ? GPIO_SetBits(IIC_SDA_PORT, IIC_SDA_PIN) : GPIO_ResetBits(IIC_SDA_PORT, IIC_SDA_PIN) #define READ_IIC_SDA GPIO_ReadInputDataBit(IIC_SDA_PORT, IIC_SDA_PIN) void iic_init(void); uint8_t iic_write_bytes(uint8_t addr, uint8_t *buf, uint8_t buf_size); uint8_t iic_receive_bytes(uint8_t addr, uint8_t *buf, uint8_t buf_size); #endif #endif

iic_software.c :

/************************************************************************** * 文件名 :iic_software.c * 描述 :软件模拟IIC程序 ****************************************************************************/ #include "iic_software.h" #include "delay.h" #include "stdio.h" #ifdef USE_SOFTWARE_IIC // 使用软件IIC(注:软件IIC和硬件IIC只能同时使用一种) /* IIC软件模拟时序延时函数 */ void iic_delay(uint16_t us) { delay_us(us); } /* IIC起始信号 */ void set_iic_sda_mode(uint8_t mode) { GPIO_InitTypeDef GPIO_InitStruct; if(mode > 0) {// 设置为输出模式 GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD; // 开漏或推挽,外部需要接上拉电阻 } else {// 设置为输入模式 GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; // 浮空或上拉,外部需要接上拉电阻 } GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStruct.GPIO_Pin = IIC_SDA_PIN; GPIO_Init(IIC_SDA_PORT, &GPIO_InitStruct); } /* IIC起始信号 */ void iic_start(void) { SET_IIC_SDA(1); SET_IIC_SCL(1); iic_delay(5); SET_IIC_SDA(0); SET_IIC_SCL(0); iic_delay(5); } /* IIC停止信号 */ void iic_stop(void) { SET_IIC_SCL(0); SET_IIC_SDA(0); iic_delay(5); SET_IIC_SCL(1); SET_IIC_SDA(1); iic_delay(5); } /* IIC发送应答信号 */ uint8_t iic_send_ack(int ack) { set_iic_sda_mode(1); if(ack == 1) {// 发送NACK SET_IIC_SDA(1); } else if(ack == 0) {// 发送ACK SET_IIC_SDA(0); } else { return 0; // 入参有误,发送失败 } SET_IIC_SCL(1); iic_delay(5); SET_IIC_SCL(0); iic_delay(5); return 1; // 发送成功 } /* IIC接收应答信号 */ uint8_t iic_wait_ack(void) { uint8_t ack = 0; uint8_t timeout = 5; SET_IIC_SDA(1); set_iic_sda_mode(0); // SDA输入模式 SET_IIC_SCL(1); iic_delay(5); while(timeout--) {// 等待从设备发送ACK if(READ_IIC_SDA == 0) {// 读到应答信号 ack = 1; } else {// 没有读到应答信号,继续等待 iic_delay(1); if(timeout == 0) {// 等待超时 ack = 0; } } } SET_IIC_SCL(0); iic_delay(5); set_iic_sda_mode(1); // SDA输出模式 return ack; } /* IIC总线发送1个字节数据 */ uint8_t iic_send_byte(uint8_t dat) { uint8_t i; for (i = 0; i


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3