你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

基于STM32F1的CAN通信之BH1750

[复制链接]
攻城狮Melo 发布时间:2023-10-23 23:28
一、BH1750简介
BH1750是一款数字型光照强度传感器,能够获取周围环境的光照强度。其测量范围在0~65535 lx。lx勒克斯,是光照强度的单位。BH1750可用于调节手机屏幕和键盘的背光功率,或者用于智能灯光控制,比如,随着外界光照强度的变化调节灯光亮度。


微信图片_20231023232803.png

BH1750

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

二、BH1750原理图

微信图片_20231023232800.png


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的数据手册中给出了一些指令

微信图片_20231023232756.png

BH1750指令集



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

微信图片_20231023232752.png

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数据手册中给出了一种配置连续高分辨率模式的方法


微信图片_20231023232748.png


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


BH1750数据读取格式如下

微信图片_20231023232744.png

BH1750数据读取格式



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


四、BH1750程序设计
4.1 IIC程序

相比于之前的OLED的IIC程序,增加了主设备发送应答信号(Ack),非应答信号(NAck),读取一个字节数据程序。修改了等待应答信号程序,增加了返回值。
  1. /*
  2. *==============================================================================
  3. *函数名称:IIC_Delay
  4. *函数功能:IIC延时
  5. *输入参数:无
  6. *返回值:无
  7. *备  注:数据手册提供
  8. *==============================================================================
  9. */
  10. void IIC_Delay (void)
  11. {
  12.     u8 t = 10;
  13.     while (t--);
  14. }
  15. /*
  16. *==============================================================================
  17. *函数名称:I2C_Start
  18. *函数功能:IIC起始信号
  19. *输入参数:无
  20. *返回值:无
  21. *备  注:数据手册提供
  22. *==============================================================================
  23. */
  24. void I2C_Start (void)
  25. {
  26.     BH1750_SDA_Set();
  27.     BH1750_SCL_Set();
  28.     IIC_Delay();
  29.     BH1750_SDA_Clr();
  30.     IIC_Delay();
  31.     BH1750_SCL_Clr();
  32.     IIC_Delay();
  33. }
  34. /*
  35. *==============================================================================
  36. *函数名称:I2C_Stop
  37. *函数功能:IIC终止信号
  38. *输入参数:无
  39. *返回值:无
  40. *备  注:数据手册提供
  41. *==============================================================================
  42. */
  43. void I2C_Stop (void)
  44. {
  45.     BH1750_SDA_Clr();
  46.     BH1750_SCL_Set();
  47.     IIC_Delay();
  48.     BH1750_SDA_Set();
  49. }
  50. /*
  51. *==============================================================================
  52. *函数名称:IIC_Ack
  53. *函数功能:CPU产生一个ACK信号
  54. *输入参数:无
  55. *返回值:无
  56. *备  注:无
  57. *==============================================================================
  58. */
  59. void IIC_Ack (void)
  60. {
  61.     BH1750_SDA_Clr();
  62.     IIC_Delay();
  63.     BH1750_SCL_Set();
  64.     IIC_Delay();
  65.     BH1750_SCL_Clr();
  66.     IIC_Delay();
  67.     BH1750_SDA_Set();
  68. }
  69. /*
  70. *==============================================================================
  71. *函数名称:IIC_NAck
  72. *函数功能:CPU产生一个NACK信号
  73. *输入参数:无
  74. *返回值:无
  75. *备  注:无
  76. *==============================================================================
  77. */
  78. void IIC_NAck (void)
  79. {
  80.     BH1750_SDA_Set();
  81.     IIC_Delay();
  82.     BH1750_SCL_Set();
  83.     IIC_Delay();
  84.     BH1750_SCL_Clr();
  85.     IIC_Delay();
  86. }
  87. /*
  88. *==============================================================================
  89. *函数名称:I2C_WaitAck
  90. *函数功能:IIC等待应答
  91. *输入参数:无
  92. *返回值:0:未收到应答信号;1:收到应答信号
  93. *备  注:无
  94. *==============================================================================
  95. */
  96. u8 I2C_WaitAck (void)
  97. {
  98.     u8 re;

  99.     BH1750_SDA_Set();
  100.     IIC_Delay();
  101.     BH1750_SCL_Set();
  102.     IIC_Delay();
  103.     if (BH1750_SDA_DATA())
  104.     {
  105.         re = 1;
  106.     }
  107.     else
  108.     {
  109.         re = 0;
  110.     }
  111.    
  112.     BH1750_SCL_Clr();
  113.     IIC_Delay();
  114.    
  115.     return re;
  116. }
  117. /*
  118. *==============================================================================
  119. *函数名称:Send_Byte
  120. *函数功能:写入一个字节
  121. *输入参数:dat:需要写入的数据
  122. *返回值:无
  123. *备  注:数据手册提供
  124. *==============================================================================
  125. */
  126. void Send_Byte (u8 dat)
  127. {
  128.     u8 i;

  129.     for (i = 0;i < 8;i ++)
  130.     {
  131.         // 发送数据时,从高位依次写入
  132.         if (dat & 0x80)
  133.         {
  134.             BH1750_SDA_Set();
  135.         }
  136.         else
  137.         {
  138.             BH1750_SDA_Clr();
  139.         }
  140.         IIC_Delay();
  141.         BH1750_SCL_Set();
  142.         IIC_Delay();
  143.         BH1750_SCL_Clr();
  144.         
  145.         // dat左移1位
  146.         dat <<= 1;
  147.     }
  148. }
  149. /*
  150. *==============================================================================
  151. *函数名称:IIC_Read_Byte
  152. *函数功能:IIC读取一个字节数据
  153. *输入参数:无
  154. *返回值:无
  155. *备  注:读取到的一个字节数据
  156. *==============================================================================
  157. */
  158. u8 IIC_Read_Byte (void)
  159. {
  160.     u8 i;
  161.     u8 value;
  162.    
  163.     // 高位在前
  164.     value = 0;
  165.    
  166.     // 循环读取8bit数据
  167.     for (i = 0; i < 8; i ++)
  168.     {
  169.         value <<= 1;   // 循环左移一位
  170.         
  171.         BH1750_SCL_Set();
  172.         IIC_Delay();
  173.         
  174.         // 如果是“1”
  175.         if (BH1750_SDA_DATA())
  176.         {
  177.             value ++;
  178.         }
  179.         
  180.         BH1750_SCL_Clr();
  181.         IIC_Delay();
  182.     }
  183.    
  184.     return value;
  185. }
  186. //BH1750写一个字节
  187. //返回值 成功:0  失败:非0
  188. /*
  189. *==============================================================================
  190. *函数名称:BH1750_Byte_Write
  191. *函数功能:BH1750写一个字节
  192. *输入参数:data:要写入的数据
  193. *返回值:0:写入成功;1/2:写入失败
  194. *备  注:无
  195. *==============================================================================
  196. */
  197. u8 BH1750_Byte_Write (u8 data)
  198. {
  199.     I2C_Start();
  200.    
  201.     // 发送从设备地址,0:写
  202.     Send_Byte (BH1750_Addr | 0);
  203.    
  204.     // 收到应答信号
  205.     if(I2C_WaitAck() == 1)
  206.     {
  207.         return 1;
  208.     }
  209.     //发送控制命令
  210.     Send_Byte(data);
  211.    
  212.     // 收到应答信号
  213.     if(I2C_WaitAck() == 1)
  214.     {
  215.         return 2;
  216.     }
  217.    
  218.     I2C_Stop();
  219.    
  220.     return 0;
  221. }
复制代码

4.2 BH1750初始化程序
初始化包括两部分,一部分是初始化IIC引脚,另一部分是初始化BH1750。也就是给BH1750上电,并复位。
  1. /*
  2. *==============================================================================
  3. *函数名称:Drv_Bh1750_Init
  4. *函数功能:初始化BH1750
  5. *输入参数:无
  6. *返回值:无
  7. *备  注:无
  8. *==============================================================================
  9. */
  10. void Drv_Bh1750_Init (void)
  11. {
  12.     // 结构体定义
  13.      GPIO_InitTypeDef  GPIO_InitStructure;
  14.    
  15.     // 开启时钟
  16.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
  17.    
  18.     // 初始化GPIO结构体
  19.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;  
  20.      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   // 推挽式输出
  21.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  22.      GPIO_Init(GPIOB, &GPIO_InitStructure);
  23.     // 全部拉高,IIC处于空闲状态
  24.      GPIO_SetBits(GPIOB,GPIO_Pin_6 | GPIO_Pin_7);
  25.    
  26.     // BH1750上电
  27.     BH1750_Byte_Write(POWER_ON);
  28.    
  29.     // 复位BH1750
  30.     BH1750_Byte_Write(MODULE_RESET);
  31. }
复制代码

4.3 读取BH1750测量结果
BH1750返回两字节的测量结果数据
  1. /*
  2. *==============================================================================
  3. *函数名称:Drv_Bh1750_Read_Measure
  4. *函数功能:读取BH1750测量数据
  5. *输入参数:无
  6. *返回值:0:读取失败;其他:光照强度
  7. *备  注:无
  8. *==============================================================================
  9. */
  10. u16 Drv_Bh1750_Read_Measure (void)
  11. {
  12.     u16 receData = 0;
  13.    
  14.     I2C_Start();
  15.    
  16.     // 发送从设备地址,1:读
  17.     Send_Byte(BH1750_Addr | 1);
  18.    
  19.     if(I2C_WaitAck() == 1)
  20.     {
  21.         return 0;
  22.     }
  23.    
  24.     // 读取高八位
  25.     receData = IIC_Read_Byte();
  26.     IIC_Ack();
  27.    
  28.     // 读取低八位
  29.     receData = (receData << 8) + IIC_Read_Byte();
  30.     IIC_NAck();
  31.     I2C_Stop();
  32.    
  33.     return receData;   // 返回读取到的数据
  34. }
复制代码

4.4 获取光照强度
  1. /*
  2. *==============================================================================
  3. *函数名称:Med_Bh1750_GetLightIntensity
  4. *函数功能:获取光照强度
  5. *输入参数:无
  6. *返回值:光照强度
  7. *备  注:分辨率 光照强度(单位lx)=(High Byte  + Low Byte)/ 1.2 * 测量精度
  8. *==============================================================================
  9. */
  10. float Med_Bh1750_GetLightIntensity (void)
  11. {
  12.     return (float)(Drv_Bh1750_Read_Measure() / 1.1f * Resolurtion);   //返回测量光照强度
  13. }
复制代码

4.5 相关宏定义
  1. // BH1750的地址(ADDR=“H”)
  2. #define BH1750_Addr   0x46

  3. // BH1750指令
  4. #define POWER_OFF     0x00
  5. #define POWER_ON     0x01
  6. #define MODULE_RESET   0x07
  7. #define CONTINUE_H_MODE  0x10
  8. #define CONTINUE_H_MODE2 0x11
  9. #define CONTINUE_L_MODE  0x13
  10. #define ONE_TIME_H_MODE  0x20
  11. #define ONE_TIME_H_MODE2 0x21
  12. #define ONE_TIME_L_MODE  0x23

  13. //测量模式
  14. #define Measure_Mode   CONTINUE_H_MODE

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

  23. // SCL
  24. #define BH1750_SCL_Clr()   GPIO_ResetBits(GPIOB,GPIO_Pin_6)
  25. #define BH1750_SCL_Set()   GPIO_SetBits(GPIOB,GPIO_Pin_6)
  26. // SDA
  27. #define BH1750_SDA_Clr()   GPIO_ResetBits(GPIOB,GPIO_Pin_7)
  28. #define BH1750_SDA_Set()   GPIO_SetBits(GPIOB,GPIO_Pin_7)

  29. // 读取SDA电平
  30. #define BH1750_SDA_DATA()   GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_7)
复制代码


五、应用实例
使用串口打印光照强度,main函数如下
  1. float gLingtIntensity = 0;

  2. int main(void)
  3. {
  4.     Med_Mcu_Iint();   // 系统初始化
  5.    
  6.     while(1)
  7.   {
  8.         gLingtIntensity = Med_Bh1750_GetLightIntensity();   // 获取光照强度
  9.         printf ("Light:%.1f lx",gLingtIntensity);   // 串口打印光照强度
  10.         
  11.         delay_ms(500);   //延时500ms = 0.5s
  12.     }
  13. }
复制代码

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

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

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

转载自:二土电子
如有侵权请联系删除



收藏 评论0 发布时间:2023-10-23 23:28

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版