?? 文章作者:二土電子
?? 關(guān)注文末公眾號獲取其他資料和工程文件!
?? 期待大家一起學習交流!
一、BH1750簡介
BH1750是一款數(shù)字型光照強度傳感器,能夠獲取周圍環(huán)境的光照強度。其測量范圍在0~65535 lx。lx勒克斯,是光照強度的單位。
BH1750可用于調(diào)節(jié)手機屏幕和鍵盤的背光功率,或者用于智能燈光控制,比如,隨著外界光照強度的變化調(diào)節(jié)燈光亮度。
BH1750有以下特點
- I2C總線接口
- 接近視覺靈敏度的光譜靈敏度特性
- 輸出對應亮度的數(shù)字值
- 高分辨率(0~65535 lx)
- 通過降低功率功能,實現(xiàn)低電流化
- 50Hz / 60Hz光噪聲抑制功能
- 可以選擇兩種類型的I2C從屬地址
- 最小誤差變動在±20%
- 受紅外線影響很小
二、BH1750原理圖
- PD —— 接近人眼反應的光敏二極管
- AMP —— 集成運算放大器(將 PD 電流轉(zhuǎn)換為 PD 電壓)
- ADC —— 模數(shù)轉(zhuǎn)換獲取 16 位數(shù)字數(shù)據(jù)
- Logic + IC Interface(邏輯+ IC 界面)
- OSC —— 內(nèi)部振蕩器(該時鐘為內(nèi)部邏輯時鐘,時鐘頻率典型值:320kHz)
PD二極管通過光伏效應將輸入光信號轉(zhuǎn)換成電信號,經(jīng)運放電路放大后,電壓經(jīng)ADC采集,再經(jīng)邏輯電路轉(zhuǎn)換成16位二進制數(shù),存儲在內(nèi)部的寄存器中(進入光窗的光越強,光電流越大,電壓就越大,所以光強可以通過電壓的大小判斷,但是應該注意的是,雖然電壓和光強一一對應,但它們不是成正比關(guān)系,所以該芯片內(nèi)部是對數(shù)據(jù)進行了線性處理,這就是為什么直接使用集成IC而不是光電二極管的原因)。BH1750引出了時鐘線和數(shù)據(jù)線,單片機可以通過I2C協(xié)議與BH1750進行通訊,可選擇BH1750的工作模式,提取BH1750寄存器中的照度數(shù)據(jù)。
三、BH1750數(shù)據(jù)手冊
3.1 指令集
BH1750的數(shù)據(jù)手冊中給出了一些指令
其中的H分辨率模式和L分辨率模式等,是BH1750的測量模式,數(shù)據(jù)手冊中也給出了說明
我們通常使用H分辨率模式,H 分辨率模式下足夠長的測量時間(積分時間)能夠抑制一些噪聲(包括 50Hz/60Hz)。同時,H 分辨率模式的分辨率在 1lx 下,適用于黑暗場合下(少于 10 lx)。
3.2 IIC通信讀/寫
上面介紹,BH1750有兩種從屬地址,由 ADDR 端口的電平?jīng)Q定。
- ADDR=“H”( ADDR ≧ 0.7VCC ) →“1011100”
- ADDR=“L”( ADDR ≦ 0.3VCC ) →“0100011”
關(guān)于IIC通信的詳細內(nèi)容,這里就不再介紹了,可以去本系列的OLED篇查看。BH1750數(shù)據(jù)手冊中給出了一種配置連續(xù)高分辨率模式的方法
BH1750數(shù)據(jù)讀取格式如下
光照強度(單位lx)=(High Byte + Low Byte)/ 1.2 * 測量精度
四、BH1750程序設(shè)計
4.1 IIC程序
相比于之前的OLED的IIC程序,增加了主設(shè)備發(fā)送應答信號(Ack),非應答信號(NAck),讀取一個字節(jié)數(shù)據(jù)程序。修改了等待應答信號程序,增加了返回值。
/*
*==============================================================================
*函數(shù)名稱:IIC_Delay
*函數(shù)功能:IIC延時
*輸入?yún)?shù):無
*返回值:無
*備 注:數(shù)據(jù)手冊提供
*==============================================================================
*/
void IIC_Delay (void)
{
u8 t = 10;
while (t--);
}
/*
*==============================================================================
*函數(shù)名稱:I2C_Start
*函數(shù)功能:IIC起始信號
*輸入?yún)?shù):無
*返回值:無
*備 注:數(shù)據(jù)手冊提供
*==============================================================================
*/
void I2C_Start (void)
{
BH1750_SDA_Set();
BH1750_SCL_Set();
IIC_Delay();
BH1750_SDA_Clr();
IIC_Delay();
BH1750_SCL_Clr();
IIC_Delay();
}
/*
*==============================================================================
*函數(shù)名稱:I2C_Stop
*函數(shù)功能:IIC終止信號
*輸入?yún)?shù):無
*返回值:無
*備 注:數(shù)據(jù)手冊提供
*==============================================================================
*/
void I2C_Stop (void)
{
BH1750_SDA_Clr();
BH1750_SCL_Set();
IIC_Delay();
BH1750_SDA_Set();
}
/*
*==============================================================================
*函數(shù)名稱:IIC_Ack
*函數(shù)功能:CPU產(chǎn)生一個ACK信號
*輸入?yún)?shù):無
*返回值:無
*備 注:無
*==============================================================================
*/
void IIC_Ack (void)
{
BH1750_SDA_Clr();
IIC_Delay();
BH1750_SCL_Set();
IIC_Delay();
BH1750_SCL_Clr();
IIC_Delay();
BH1750_SDA_Set();
}
/*
*==============================================================================
*函數(shù)名稱:IIC_NAck
*函數(shù)功能:CPU產(chǎn)生一個NACK信號
*輸入?yún)?shù):無
*返回值:無
*備 注:無
*==============================================================================
*/
void IIC_NAck (void)
{
BH1750_SDA_Set();
IIC_Delay();
BH1750_SCL_Set();
IIC_Delay();
BH1750_SCL_Clr();
IIC_Delay();
}
/*
*==============================================================================
*函數(shù)名稱:I2C_WaitAck
*函數(shù)功能:IIC等待應答
*輸入?yún)?shù):無
*返回值: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;
}
/*
*==============================================================================
*函數(shù)名稱:Send_Byte
*函數(shù)功能:寫入一個字節(jié)
*輸入?yún)?shù):dat:需要寫入的數(shù)據(jù)
*返回值:無
*備 注:數(shù)據(jù)手冊提供
*==============================================================================
*/
void Send_Byte (u8 dat)
{
u8 i;
for (i = 0;i < 8;i ++)
{
// 發(fā)送數(shù)據(jù)時,從高位依次寫入
if (dat & 0x80)
{
BH1750_SDA_Set();
}
else
{
BH1750_SDA_Clr();
}
IIC_Delay();
BH1750_SCL_Set();
IIC_Delay();
BH1750_SCL_Clr();
// dat左移1位
dat <<= 1;
}
}
/*
*==============================================================================
*函數(shù)名稱:IIC_Read_Byte
*函數(shù)功能:IIC讀取一個字節(jié)數(shù)據(jù)
*輸入?yún)?shù):無
*返回值:無
*備 注:讀取到的一個字節(jié)數(shù)據(jù)
*==============================================================================
*/
u8 IIC_Read_Byte (void)
{
u8 i;
u8 value;
// 高位在前
value = 0;
// 循環(huán)讀取8bit數(shù)據(jù)
for (i = 0; i < 8; i ++)
{
value <<= 1; // 循環(huán)左移一位
BH1750_SCL_Set();
IIC_Delay();
// 如果是“1”
if (BH1750_SDA_DATA())
{
value ++;
}
BH1750_SCL_Clr();
IIC_Delay();
}
return value;
}
//BH1750寫一個字節(jié)
//返回值 成功:0 失?。悍?
/*
*==============================================================================
*函數(shù)名稱:BH1750_Byte_Write
*函數(shù)功能:BH1750寫一個字節(jié)
*輸入?yún)?shù):data:要寫入的數(shù)據(jù)
*返回值:0:寫入成功;1/2:寫入失敗
*備 注:無
*==============================================================================
*/
u8 BH1750_Byte_Write (u8 data)
{
I2C_Start();
// 發(fā)送從設(shè)備地址,0:寫
Send_Byte (BH1750_Addr | 0);
// 收到應答信號
if(I2C_WaitAck() == 1)
{
return 1;
}
//發(fā)送控制命令
Send_Byte(data);
// 收到應答信號
if(I2C_WaitAck() == 1)
{
return 2;
}
I2C_Stop();
return 0;
}
4.2 BH1750初始化程序
初始化包括兩部分,一部分是初始化IIC引腳,另一部分是初始化BH1750。也就是給BH1750上電,并復位。
/*
*==============================================================================
*函數(shù)名稱:Drv_Bh1750_Init
*函數(shù)功能:初始化BH1750
*輸入?yún)?shù):無
*返回值:無
*備 注:無
*==============================================================================
*/
void Drv_Bh1750_Init (void)
{
// 結(jié)構(gòu)體定義
GPIO_InitTypeDef GPIO_InitStructure;
// 開啟時鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
// 初始化GPIO結(jié)構(gòu)體
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處于空閑狀態(tài)
GPIO_SetBits(GPIOB,GPIO_Pin_6 | GPIO_Pin_7);
// BH1750上電
BH1750_Byte_Write(POWER_ON);
// 復位BH1750
BH1750_Byte_Write(MODULE_RESET);
}
4.3 讀取BH1750測量結(jié)果
BH1750返回兩字節(jié)的測量結(jié)果數(shù)據(jù)
/*
*==============================================================================
*函數(shù)名稱:Drv_Bh1750_Read_Measure
*函數(shù)功能:讀取BH1750測量數(shù)據(jù)
*輸入?yún)?shù):無
*返回值:0:讀取失敗;其他:光照強度
*備 注:無
*==============================================================================
*/
u16 Drv_Bh1750_Read_Measure (void)
{
u16 receData = 0;
I2C_Start();
// 發(fā)送從設(shè)備地址,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; // 返回讀取到的數(shù)據(jù)
}
4.4 獲取光照強度
/*
*==============================================================================
*函數(shù)名稱:Med_Bh1750_GetLightIntensity
*函數(shù)功能:獲取光照強度
*輸入?yún)?shù):無
*返回值:光照強度
*備 注:分辨率 光照強度(單位lx)=(High Byte + Low Byte)/ 1.2 * 測量精度
*==============================================================================
*/
float Med_Bh1750_GetLightIntensity (void)
{
return (float)(Drv_Bh1750_Read_Measure() / 1.1f * Resolurtion); //返回測量光照強度
}
4.5 相關(guān)宏定義
// 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函數(shù)如下
float gLingtIntensity = 0;
int main(void)
{
Med_Mcu_Iint(); // 系統(tǒng)初始化
while(1)
{
gLingtIntensity = Med_Bh1750_GetLightIntensity(); // 獲取光照強度
printf ("Light:%.1f lx",gLingtIntensity); // 串口打印光照強度
delay_ms(500); //延時500ms = 0.5s
}
}
六、拓展應用
利用BH1750獲取到的周圍環(huán)境光強可用于許多方面,這里舉幾個例子,比如設(shè)計一個教室燈光控制系統(tǒng),根據(jù)實際環(huán)境光強來調(diào)節(jié)燈光亮度,使室內(nèi)環(huán)境光強保持在一個穩(wěn)定的值。另外,比如做顏色識別時,周圍環(huán)境的光照強度不同,識別的效果也不同??梢岳肂H1750實時監(jiān)測周圍環(huán)境光照強度變化,不同的光照強度下,切換不同的顏色閾值,可以改善顏色識別的效果。這里簡單介紹一下實現(xiàn)思路。
6.1 實時調(diào)節(jié)LED亮度
可以用PWM來控制LED的亮度。根據(jù)周圍環(huán)境的光照強度的變化,實時調(diào)節(jié)PWM的占空比,達到LED亮度根據(jù)周圍環(huán)境光照強度變化而變化的效果。但是需要注意光照強度與占空比的換算關(guān)系。文章來源:http://www.zghlxwxcb.cn/news/detail-528668.html
6.2 實時調(diào)整顏色閾值
比如使用Open MV做顏色是別時,在不同光照強度下,同一種顏色的顏色閾值不同,可以根據(jù)不同的光照強度,匹配不同的顏色閾值。文章來源地址http://www.zghlxwxcb.cn/news/detail-528668.html
到了這里,關(guān)于STM32外設(shè)系列—BH1750的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!