關於I2C協議不再詳述,見之前的總結stm32h7「I2C協議驅動DS3231晶片」,下面直入主題,總結我在開發晶片BH1730FVC的驅動心得體會。
1、BH1730FVC介紹2、BH1730FVC典型應用電路圖1 BH1730FVC典型應用電路圖2 BH1730FVC管腳說明3、BH1730FVC工作流程及寄存器圖BH1730FV的工作流程是,上電後BH1730FVC初始狀態是掉電狀態,通過I2C總線對該晶片的寄存器CONTROL的第0位POWER設置1 : ADC power on,第1位ADC_EN設置1 : ADC measurement starts,然後進入到自動測量狀態。接著判斷該晶片的寄存器CONTROL的第3位ONE_TIME是否為1(0 : ADC measurement is continuous. 1 : ADC measurement is one time.ADC transits to power down automatically),如果是0即ADC連續測量模式。接著再判斷寄存器INTERRUPT的第6位INT_STOP是否為1(0 : ADC measurement does not stop. 1 : ADC measurement stops and transits to
power down mode when interrupt becomes active), 如果是0,返回到測量狀態,如圖3。關於寄存器CONTROL和INTERRUPT的位圖,如圖4
BH1730FV的寄存圖,如圖5。
圖5 BH1730FVC寄存器圖重點關注COMMAND,它很特殊,它是沒有地址的,它既可以與第7位CMD設置為1合成為一個地址,又可作為一個命令,如圖6
圖6 BH1730FVC寄存器圖BH1730FVC的I2C協議讀寫數據流程,如圖7。首先看看如何給BH1730FVC發送指令,這裡以發送連續測量模式為例。注意:①是寄存器CONTROL地址0x00加上0x80(結合圖6,第7位CMD一直為1,第5至6位設為00為地址模式,第0至4位為寄存器地址)② 是給剛剛的寄存器(CONTROL)寫數據,即第0位POWER置1,第1位ADC_EN置1。再看如何讀取測量結果。注意:③是寄存器DATA0LOW地址0x14加上0x80(結合圖6,第7位CMD一直為1,第5至6位設為00為地址模式,第0至4位為寄存器地址)④實測此處STOP可以省略(相當於stm32h7「I2C協議驅動DS3231晶片」中圖7的Repeated START)
圖7 BH1730FVC的I2C協議讀寫數據流程至此,BH1730FVC的數據手冊中的工作流程、寄存器圖、I2C讀寫協議已分析完畢,下面進行驅動開發。
4、BH1730FVC驅動開發根據BH1730FVC的寄存器分布圖編寫bsp_i2c_bh1730fvc.h,如代碼1。註:模擬I2C總線協議的底層代碼未貼出。
/*
*********************************************************************************************************
*
* 模塊名稱 : 光照強度晶片BH1730FVC驅動模塊
* 文件名稱 : bsp_i2c_bh1730fvc.h
* 版 本 : V1.0
* 說 明 :
*
* 修改記錄 :
* 版本號 日期 作者 說明
* V1.0 2021-05-12 芯跳不止 正式發布
*
* Copyright (C), 2020-2030, 芯跳不止 www.mazirong.com
*
*********************************************************************************************************
*/
#ifndef __BSP_BH1730FVC_H
#define __BSP_BH1730FVC_H
// BH1730FVC正確響應
#define BH1730FVC_OK 0
// BH1730FVC設備ID
#define BH1730FVC_ID 0x70
// BH1730FVC器件地址
#define BH1730FVC_SLAVE_ADDRESS 0x29
// BH1730FVC器件讀地址
#define BH1730FVC_SLAVE_ADDRESS_W (BH1730FVC_SLAVE_ADDRESS << 1)
// BH1730FVC器件寫地址
#define BH1730FVC_SLAVE_ADDRESS_R ((BH1730FVC_SLAVE_ADDRESS << 1) + 1)
// 定義BH1730FVC內部寄存器地址
#define BH1730FVC_REG_CONTROL 0x00 // Operation mode control
#define BH1730FVC_REG_TIMING 0x01 // Light integration time control
#define BH1730FVC_REG_INTERRUPT 0x02 // Interrupt function control
#define BH1730FVC_REG_THLLOW 0x03 // Low byte of low interrupt threshold setting
#define BH1730FVC_REG_THLHIGH 0x04 // High byte of low interrupt threshold setting
#define BH1730FVC_REG_THHLOW 0x05 // Low byte of high interrupt threshold setting
#define BH1730FVC_REG_THHHIGH 0x06 // High byte of high interrupt threshold setting
#define BH1730FVC_REG_GAIN 0x07 // Gain control
#define BH1730FVC_REG_ID 0x12 // Part number and Revision ID
#define BH1730FVC_REG_DATA0LOW 0x14 // ADC Type0 low byte data register
#define BH1730FVC_REG_DATA0HIGH 0x15 // ADC Type0 high byte data register
#define BH1730FVC_REG_DATA1LOW 0x16 // ADC Type1 low byte data register
#define BH1730FVC_REG_DATA1HIGH 0x17 // ADC Type1 high byte data register
// 將兩個uint8數據轉換為一個uint16_t類型
#define BH1730FVC_UINT8_TO_UINT16(data) ((uint16_t)(data[1] << 8 | data[0]))
// 定義BH1730FVC增益枚舉
enum BH1730FVC_GAIN
{
BH1730FVC_GAIN_x1 = 0,
BH1730FVC_GAIN_x2,
BH1730FVC_GAIN_x64,
BH1730FVC_GAIN_x128,
};
// 定義BH1730FVC光強結構體類型
typedef struct
{
volatile uint8_t ucGain;
volatile float ulLux;
}BH1730FVC_T;
// 外部結構體聲明
extern BH1730FVC_T g_tBH1730FVC;
// 外部函數聲明
void BH1730FVC_GetLux(void);
void BH1730FVC_Stop(void);
void BH1730FVC_Start(void);
int8_t bsp_InitBH1730FVC(void);
// 內部函數聲明
static float BH1730FVC_CountLightValue(uint16_t *p_data);
static void BH1730FVC_WriteByte(uint8_t _ucRegAddr, uint8_t _ucRegData);
static void BH1730FVC_WriteData(uint8_t _ucRegAddr, uint8_t *_ucWriteBuf, uint8_t _ucLength);
static uint8_t BH1730FVC_ReadByte(uint8_t _ucRegAddr);
static void BH1730FVC_ReadData(uint8_t _ucRegAddr, uint8_t *_ucReadBuf, uint8_t _ucLength);
#endif
代碼1
根據BH1730FVC的datasheet,編寫整個完整的bsp_i2c_bh1730fvc.c,如代碼2
/*
*********************************************************************************************************
*
* 模塊名稱 : 光照強度晶片BH1730FVC驅動模塊
* 文件名稱 : bsp_i2c_bh1730fvc.h
* 版 本 : V1.0
* 說 明 :
*
* 修改記錄 :
* 版本號 日期 作者 說明
* V1.0 2021-05-12 芯跳不止 正式發布
*
* Copyright (C), 2020-2030, 芯跳不止 www.mazirong.com
*
*********************************************************************************************************
*/
#include "bsp.h"
// 定義BH1730FVC光強結構體
BH1730FVC_T g_tBH1730FVC;
/*
*********************************************************************************************************
* 函 數 名: BH1730FVC_GetLux
* 功能說明: 獲取BH1730FVC光照強度值(單位:勒克斯)
* 形 參: 無
* 返 回 值: 無
*********************************************************************************************************
*/
void BH1730FVC_GetLux(void)
{
uint8_t reg_data[2];
uint16_t tem_data[2];
// 獲取光照強度可見光數值
BH1730FVC_ReadData(BH1730FVC_REG_DATA0LOW, reg_data, 2);
tem_data[0] = BH1730FVC_UINT8_TO_UINT16(reg_data);
// 獲取光照強度紅外光數值
BH1730FVC_ReadData(BH1730FVC_REG_DATA1LOW, reg_data, 2);
tem_data[1] = BH1730FVC_UINT8_TO_UINT16(reg_data);
// 計算光照強度(單位:勒克斯)
g_tBH1730FVC.ulLux = BH1730FVC_CountLightValue(tem_data);
}
/*
*********************************************************************************************************
* 函 數 名: BH1730FVC_Stop
* 功能說明: 停止BH1730FVC
* 形 參: 無
* 返 回 值: 無
*********************************************************************************************************
*/
void BH1730FVC_Stop(void)
{
// BH1730FVC配置為電源關閉、ADC測量停止、可見光與紅外光測量、ADC測量連續模式
// RES[7,6]-00: 固定寫此值
// ADC_INTR[5]-只讀
// ADC_VALID[4]-只讀
// ONE_TIME[3]-0: ADC measurement is continuous/1: ADC measurement is one time
// DATA_SEL[2]-0: ADC measurement Type0 and Type1/1: ADC measurement Type0 only
// ADC_EN[1]-0: ADC measurement stops/1: ADC measurement starts
// POWER[0]-0: ADC power down/1: ADC power on
BH1730FVC_WriteByte(BH1730FVC_REG_CONTROL, 0x00);
}
/*
*********************************************************************************************************
* 函 數 名: BH1730FVC_Start
* 功能說明: 啟動BH1730FVC
* 形 參: 無
* 返 回 值: 無
*********************************************************************************************************
*/
void BH1730FVC_Start(void)
{
// BH1730FVC配置為電源開啟、ADC測量啟動、可見光與紅外光測量、ADC測量連續模式
// RES[7,6]-00: 固定寫此值
// ADC_INTR[5]-只讀
// ADC_VALID[4]-只讀
// ONE_TIME[3]-0: ADC measurement is continuous/1: ADC measurement is one time
// DATA_SEL[2]-0: ADC measurement Type0 and Type1/1: ADC measurement Type0 only
// ADC_EN[1]-0: ADC measurement stops/1: ADC measurement starts
// POWER[0]-0: ADC power down/1: ADC power on
BH1730FVC_WriteByte(BH1730FVC_REG_CONTROL, 0x03);
}
/*
*********************************************************************************************************
* 函 數 名: bsp_InitBH1730FVC
* 功能說明: 初始化BH1730FVC
* 形 參: 無
* 返 回 值: error status (BH1730FVC_OK, !BH1730FVC_OK)
*********************************************************************************************************
*/
int8_t bsp_InitBH1730FVC(void)
{
int8_t res = 0;
// 讀取BH1730FVC的設備ID(固定為0x7X)
res = BH1730FVC_ReadByte(BH1730FVC_REG_ID);
if((res & 0xF0) != BH1730FVC_ID)
return -1;
// 設置BH1730FVC初始光強值為0勒克斯
g_tBH1730FVC.ulLux = 0;
// 設置BH1730FVC內部增益為1(註:不要使用BH1730FVC_GAIN_x128,誤差太大)
g_tBH1730FVC.ucGain = 1;
BH1730FVC_WriteByte(BH1730FVC_REG_GAIN, BH1730FVC_GAIN_x1);
return BH1730FVC_OK;
}
/*
*********************************************************************************************************
* 函 數 名: BH1730FVC_CountLightValue
* 功能說明: 根據兩個光照強度值計算實際值
* 形 參: p_data : 光照數據指針地址
* 返 回 值: 光照強度值(單位:勒克斯)
*********************************************************************************************************
*/
static float BH1730FVC_CountLightValue(uint16_t *p_data)
{
uint8_t temp = 0;
float lux = 0;
// 注釋來源於BH1730FVC數據手冊
// 積分時間:ITIME_ms = Tint * 964 * (256 - ITIME),內部時鐘周期:Tint典型值為2.6us,最大值為4.0us
// ITIME寄存器默認值為0xDA,則默認情況下ITIME_ms = 2.6*964*(256-218)/1000 = 95.2432
//
// if (DATA1/DATA0<0.26) Lx = ( 1.290 x DATA0 - 2.733 x DATA1 ) / Gain x 102.6 / ITIME_ms
// else if (DATA1/DATA0<0.55) Lx = ( 0.795 x DATA0 - 0.859 x DATA1 ) / Gain x 102.6 / ITIME_ms
// else if (DATA1/DATA0<1.09) Lx = ( 0.510 x DATA0 - 0.345 x DATA1 ) / Gain x 102.6 / ITIME_ms
// else if (DATA1/DATA0<2.13) Lx = ( 0.276 x DATA0 - 0.130 x DATA1 ) / Gain x 102.6 / ITIME_ms
// else Lx=0
//
// 102.6 / ITIME_ms = 1.07724,在精度損耗不大情況下可將公式精簡為如下形式
if (p_data[0] != 0)
{
temp = (p_data[1] * 100 / p_data[0]);
} else
{
temp = 0xff;
}
if (temp < 26)
{
lux = ( 1.290 * p_data[0] - 2.733 * p_data[1] ) * 1.07724 / g_tBH1730FVC.ucGain ;
}
else if (temp < 55)
{
lux = ( 0.795 * p_data[0] - 0.859 * p_data[1] ) * 1.07724 / g_tBH1730FVC.ucGain ;
}
else if (temp < 109)
{
lux = ( 0.510 * p_data[0] - 0.345 * p_data[1] ) * 1.07724 / g_tBH1730FVC.ucGain ;
} else if (temp < 213)
{
lux = ( 0.276 * p_data[0] - 0.130 * p_data[1] ) * 1.07724 / g_tBH1730FVC.ucGain ;
} else
{
lux = 0;
}
return lux;
}
/*
*********************************************************************************************************
* 函 數 名: BH1730FVC_WriteByte
* 功能說明: 向BH1730FVC指定寄存器寫入1位元組數據
* 形 參: _ucRegAddr : 寄存器地址
* _ucRegData : 寄存器數據
* 返 回 值: 無
*********************************************************************************************************
*/
static void BH1730FVC_WriteByte(uint8_t _ucRegAddr, uint8_t _ucRegData)
{
// I2C總線開始信號
i2c_Start();
// 發送設備地址+寫信號
i2c_SendByte(BH1730FVC_SLAVE_ADDRESS_W);
// 等待應答信號
i2c_WaitAck();
// 發送內部寄存器地址
i2c_SendByte(_ucRegAddr | 0x80); // 根據BH1730FVC數據手冊,寫命令寄存器時最高位固定為1
// 等待應答信號
i2c_WaitAck();
// 發送內部寄存器數據
i2c_SendByte(_ucRegData);
// 等待應答信號
i2c_WaitAck();
// I2C總線停止信號
i2c_Stop();
}
///*
//*********************************************************************************************************
//* 函 數 名: BH1730FVC_WriteData
//* 功能說明: 向BH1730FVC的連續_ucLength個寄存器每個寫入1位元組數據
//* 形 參: _ucRegAddr : 寄存器地址
//* _ucWriteBuf: 待寫入數據存放地址
//* _ucLength : 待寫入字節個數
//* 返 回 值: 無
//*********************************************************************************************************
//*/
//static void BH1730FVC_WriteData(uint8_t _ucRegAddr, uint8_t *_ucWriteBuf, uint8_t _ucLength)
//{
// uint8_t i;
// //uint8_t ack;
//// 連續寫數據
//#if 0
// // I2C總線開始信號
// i2c_Start();
// // 發送設備地址+寫信號
// i2c_SendByte(BH1730FVC_SLAVE_ADDRESS_W);
// // 等待應答信號
// ack = i2c_WaitAck();
// if(ack != 0)
// {
// i2c_Stop();
// return;
// }
//
// // 發送寄存器地址
// i2c_SendByte(_ucRegAddr | 0x80); // 根據BH1730FVC數據手冊,寫命令寄存器時最高位固定為1
// // 等待應答信號
// ack = i2c_WaitAck();
// if(ack != 0)
// {
// i2c_Stop();
// return;
// }
// // 循環寫入寄存器數據
// for (i = 0; i < _ucLength; i++)
// {
// i2c_SendByte(_ucWriteBuf[i]);
// // 等待應答信號
// ack = i2c_WaitAck();
// if(ack != 0)
// {
// i2c_Stop();
// return;
// }
// }
//
// // I2C總線停止信號
// i2c_Stop();
//#else
// for (i = 0 ; i < _ucLength; i++)
// {
// BH1730FVC_WriteByte(_ucRegAddr + i, _ucWriteBuf[i]);
// }
//#endif
//}
/*
*********************************************************************************************************
* 函 數 名: BH1730FVC_ReadByte
* 功能說明: 向BH1730FVC指定寄存器讀取1位元組數據
* 形 參: _ucRegAddr : 寄存器地址
* 返 回 值: 讀取的1位元組數據
*********************************************************************************************************
*/
static uint8_t BH1730FVC_ReadByte(uint8_t _ucRegAddr)
{
uint8_t ucData;
// I2C總線開始信號
i2c_Start();
// 發送設備地址+寫信號
i2c_SendByte(BH1730FVC_SLAVE_ADDRESS_W);
// 等待應答信號
i2c_WaitAck();
// 發送寄存器地址
i2c_SendByte(_ucRegAddr | 0x80); // 根據BH1730FVC數據手冊,寫命令寄存器時最高位固定為1
// 等待應答信號
i2c_WaitAck();
// I2C總線開始信號
i2c_Start();
// 發送設備地址+讀信號
i2c_SendByte(BH1730FVC_SLAVE_ADDRESS_R);
// 等待應答信號
i2c_WaitAck();
// 讀取寄存器數據
ucData = i2c_ReadByte();
// 發送NACK信號
i2c_NAck();
// I2C總線停止信號
i2c_Stop();
return ucData;
}
/*
*********************************************************************************************************
* 函 數 名: BH1730FVC_ReadData
* 功能說明: 向BH1730FVC的連續_ucLength個寄存器每個讀取1位元組數據
* 形 參: _ucRegAddr : 寄存器地址
* _ucWriteBuf: 待讀取數據存放地址
* _ucLength : 待讀取字節個數
* 返 回 值: 無
*********************************************************************************************************
*/
static void BH1730FVC_ReadData(uint8_t _ucRegAddr, uint8_t *_ucReadBuf, uint8_t _ucLength)
{
uint8_t i;
//uint8_t ack;
// 連續讀數據
#if 0
// I2C總線開始信號
i2c_Start();
// 發送設備地址+寫信號
i2c_SendByte(BH1730FVC_SLAVE_ADDRESS_W);
// 等待應答信號
ack = i2c_WaitAck();
if (ack != 0)
{
i2c_Stop();
return;
}
// 發送寄存器地址
i2c_SendByte(_ucRegAddr | 0x80); // 根據BH1730FVC數據手冊,寫命令寄存器時最高位固定為1
// 等待應答信號
ack = i2c_WaitAck();
if (ack != 0)
{
i2c_Stop();
return;
}
// I2C總線開始信號
i2c_Start();
// 發送設備地址+讀信號
i2c_SendByte(BH1730FVC_SLAVE_ADDRESS_R);
// 等待應答信號
ack = i2c_WaitAck();
if (ack != 0)
{
i2c_Stop();
return;
}
// 循環讀出寄存器數據
for (i = 0; i < _ucLength-1; i++)
{
_ucReadBuf[i] = i2c_ReadByte();
// 發送ACK信號
i2c_Ack();
}
// 讀最後一個字節,發送NAck
_ucReadBuf[_ucLength-1] = i2c_ReadByte();
// 發送NACK信號
i2c_NAck();
// I2C總線停止信號
i2c_Stop();
// 單字節讀
#else
for (i = 0 ; i < _ucLength; i++)
{
_ucReadBuf[i] = BH1730FVC_ReadByte(_ucRegAddr + i);
}
#endif
}
代碼2
注意1:代碼2的187、231、284、337行,為什麼加0x80?參考圖6與圖7。注意2:代碼2的126至136行,關於BH1730FVC光照強度計算公式解析。
5、BH1730FVC調試驗證在現有的程序構架中加入驅動文件bsp_i2c_bh1730fvc.h和bsp_i2c_bh1730fvc.c,在初始化函數bsp_Init中調用函數bsp_InitBH1730FVC和函數BH1730FVC_Start,並定時調用函數BH1730FVC_GetLux,如代碼3的20至21行
/*
*********************************************************************************************************
* 函 數 名: bsp_RunPer10ms
* 功能說明: 該函數每隔10ms被Systick中斷調用1次。詳見 bsp_timer.c的定時中斷服務程序。一些處理時間要求不嚴格的
* 任務可以放在此函數。比如:按鍵掃描、蜂鳴器鳴叫控制等。
* 形 參: 無
* 返 回 值: 無
*********************************************************************************************************
*/
void bsp_RunPer10ms(void)
{
bsp_KeyScan10ms();
BEEP_Pro();
// 定時獲取當前時間
DS3231_GetTime(&g_tDS3231Time);
// 定時獲取當前溫度(註:64秒計算一次溫度)
DS3231_GetTemp(&g_tDS3231Temp);
// 定時獲取電池電量數據
STC3100_ReadBatteryData();
// 獲取當前光照強度
BH1730FVC_GetLux();
}
代碼3
獲取g_tBH1730FVC.ulLux,顯示在主界面中,可以看到已經在系統主界面顯示當前的光照強度為125.04勒克斯,如圖8
圖8 BH1730FVC光照強度顯示至此,stm32h7「I2C協議驅動BH1730FVC光照強度晶片」完成!