環境傳感器是一類我們很常用的傳感器,它可以方便我們獲取壓力、溫度、濕度以及空氣質量等資料,在這一篇中,我們將分析BME680環境傳感器的功能,并設計和實作BME680環境傳感器的驅動,
1、功能概述
BME680是一款專為移動應用和可穿戴設備開發的集成環境傳感器,其尺寸和低功耗是關鍵要求,
1.1、硬體介面
BME680由一個8針金屬蓋3.0 x 3.0 x0.93mm3LGA封裝組成,旨在根據特定的作業模式,長期穩定性和高EMC穩健性進行優化消耗,可以選擇采用I2C介面或者SPI介面,其管腳排布如下圖:

BME680環境傳感器可以選擇使用I2C介面或者SPI介面,在不同的介面模式及下各個引腳的定義及功能有一些差別,其具體分配及定義如下所示:

從上表中我們可以知道當CSB引腳接高電平VDDIO時,采用的是I2C介面,此時I2C的設備地址的最后一位由SDO引腳的電平決定,所以設備地址計7位為0x76或0x77,計8位則是0xEC或0xEE,
當CSB引腳用作片選信號時,則使用SPI介面,SPI介面支持模式0(CPOL=0,CPHA=0)和模式3(CPOL=1,CPHA=1),同時支持3線SPI和4線SPI,控制位元組的最高位為0時表示寫,為1時表示讀,
1.2、內置傳感器
BME680擴展了博世現有的環境傳感器系列,首次集成了高線性度和高精度的氣體,壓力,濕度和溫度傳感器,
1.2.1、氣體傳感器
BME680內的氣體傳感器可以檢測各種氣體,以測量個人健康的空氣質量,BME680可檢測到的氣體包括油漆(如甲醛),油漆,脫漆劑,清潔用品,家具等的揮發性有機化合物(VOC),大氣質量傳感器的特性引數如下:

BME680采用了博世軟體環境群組解決方案,該解決方案使用智能算術方法將空氣質量索引(IAQ)作為輸出,該指標將IAQ劃分為0到500的索引數值用以指示IAQ,具體劃分如下所示:

1.2.2、濕度傳感器
BME680集成了濕度傳感器用于外部環境中濕度資料的采集,濕度傳感器的性能引數如下:

1.2.3、壓力傳感器
BME680集成有大氣壓力傳感器用于檢測外部環境的絕對壓力,壓力傳感器的性能引數如下:

1.2.4、溫度傳感器
BME680也集成了溫度傳感器用以檢測溫度資料,溫度資料除了指示環境溫度外,同時用于壓力和濕度的補償計算,溫度傳感器的性能引數如下:

1.3、資料存盤結構
BME680采用特定的存盤器區域來存盤控制及資料資訊,存盤的資料包括測量資料、控制資訊以及校準資料,
對于溫度傳感器,包括3個校準引數和一個ADC測量資料,其測量資料和校準資料的存盤結構及地址如下:

對于壓力傳感器,包括10個計算校準資料和一個ADC轉換資料,其測量資料的校準資料存盤結構及地址如下:

對于濕度傳感器,包括7個計算校準資料和一個ADC轉換資料,其測量資料的校準資料存盤結構及地址如下:

大氣質量傳感器,包括3個計算校準資料、一個加熱器范圍存盤資料、一個加熱器電阻校準因子存盤資料、氣體ADC測量資料、氣體范圍資料以及范圍轉換錯誤,其測量資料的校準資料存盤結構及地址如下:

BME680環境傳感器暫存器都是8位的,所有的操作均通過對暫存器的讀寫來實作,全部控制暫存器及資料暫存器的結構和地址如下:

這里我們需要說明一下,BME680的存盤器地址范圍是0x00~0xFF,在I2C介面通訊時,通訊采用的是8位暫存器地址正好符合對應的尋址范圍,但是采用SPI介面通訊時,暫存器地址的最高為被用于區分讀寫操作,所以地址只有7位,存盤空間被分為2頁,具體如下:

所以在使用SPI介面時需要分辨是哪一頁,當前操作的是哪一頁由Status暫存器來決定,
2、驅動設計與實作
我們對BME680環境傳感器的基本情況已經有了整體了解,接下來我們將為BME680環境傳感器設計并實作驅動程式,
2.1、物件定義
我們依然是采用基于物件的操作,所以我們需要定義物件,所以我們需要抽象出物件型別,并對我們想要操作的物件進行初始化,
2.1.1、物件抽象
對于一個物件來說,一般包括有屬性和操作兩方面的內容,接下來我們就從這兩個方面分析BME680環境傳感器的物件,
我們需要從BME680物件抽象出其屬性,這些屬性能夠定義一個物件的特點并將其與其它物件區別開來,BME680支持SPI通訊和I2C通訊,所以我們將通訊埠作為屬性以規定物件的通訊方式,在使用I2C時,設備有地址以區別不同的設備,所以我們將I2C設備地址也定義為屬性,每臺BME680都有一個ID用以區別于其它設備,所以我們將它定義為物件的屬性,還有配置暫存器、測量控制暫存器、濕度控制暫存器、氣體控制暫存器都記錄了設備的配置狀態,所以我們也將它們作為屬性,每臺設備都有特定的校準資料,這些校準資料每次資料檢測都是需要的,所以我們用屬性將它們記錄下來,還有測量資料,它們標識了設備當前的作業狀態,所以我們將它們也作為屬性,
接下來我們分析BME680的操作,首先來講,我們肯定要與BME680互動,但我們對BME680的讀寫依賴于具體的硬體平臺,所以我們將它們作為物件的操作,在進行相關操作時,我們需要控制時序,則需要使用延時操作,但延時處理總是依賴于具體的軟硬體平臺,所以我們將延時處理作為物件的操作,而使用SPI時,沒有設備地址但有片選信號,如何操作片選信號依賴于硬體平臺,我們將對片選的操作定義為物件的操作函式,
根據上述的分析,我們可以得到BME680環境傳感器的物件型別如下:
/*定義BME680操作物件*/
typedef struct BME680Object{
uint8_t chipID; //芯片ID
uint8_t bmeAddress; //I2C通訊時的設備地址
uint8_t memeryPage; //用于在SPI介面時記錄當前所處的記憶體頁
uint8_t config; //配置暫存器
uint8_t ctrlMeas; //測量控制暫存器
uint8_t ctrlHumi; //濕度測量控制暫存器
uint8_t ctrlGas0; //氣體控制暫存器0
uint8_t ctrlGas1; //氣體控制暫存器1
uint8_t resHeat;
uint8_t gasWait;
BME680PortType port; //介面選擇
BME680CalibParamType caliPara; //校準引數
#if BME680_COMPENSATION_SELECTED > (0)
int32_t temperature; //溫度值
int32_t pressure; //壓力值
int32_t humidity; //濕度值
int32_t gasResistence; //大氣質量電阻值
int32_t iaq; //空氣質量水平
#else
float temperature; //溫度值
float pressure; //壓力值
float humidity; //濕度值
float gasResistence; //大氣質量電阻值
float iaq; //空氣質量水平
#endif
void (*Read)(struct BME680Object *bme,uint8_t regAddress,uint8_t *rData,uint16_t rSize); //讀資料操作指標
void (*Write)(struct BME680Object *bme,uint8_t regAddress,uint8_t command); //謝資料操作指標
void (*Delayms)(volatile uint32_t nTime); //延時操作指標
void (*ChipSelect)(BME680CSType cs); //使用SPI介面時,片選操作
}BME680ObjectType;
片選操作有一點需要注意,如果片選信號在硬體電路上固定有效時,可以將NULL給它,同樣在SPI介面時也需要將NULL給它,
2.1.2、物件初始化函式
一個物件必須對其進行初始化才可使用,初始化物件主要有四個方面的內容:檢查物件賦值的合法性;屬性賦初值;為物件操作指定函式指標;物件所指向設備的初始配置,據此我們可以撰寫BME680環境傳感器的初始化函式如下:
/*實作BME680初始化配置*/
void BME680Initialization(BME680ObjectType *bme, //BMP280物件
uint8_t bmeAddress, //I2C介面是設備地址
BME680PortType port, //介面選擇
BME680IIRFilterType filter, //過濾器
BME680SPI3wUseType spi3W_en, //3線SPI控制
BME680TempSampleType osrs_t, //溫度精度
BME680PresSampleType osrs_p, //壓力精度
BME680SPI3wIntType spi3wint_en,//3線SPI中斷控制
BME680HumiSampleType osrs_h, //濕度精度
BME680GasRunType run_gas, //氣體運行設定
BME680HeaterSPType nb_conv, //加熱器設定點選擇
BME680HeaterOffType heat_off, //加熱器關閉
uint16_t duration, //TPHG測量回圈周期,ms單位
uint8_t tempTarget, //加熱器的目標溫度
BME680Read Read, //讀資料操作指標
BME680Write Write, //寫資料操作指標
BME680Delayms Delayms, //延時操作指標
BME680ChipSelect ChipSelect //片選操作指標
)
{
uint8_t try_count = 5;
uint8_t regValue=0;
if((bme==NULL)||(Read==NULL)||(Write==NULL)||(Delayms==NULL))
{
return;
}
bme->Read=Read;
bme->Write=Write;
bme->Delayms=Delayms;
bme->port=port;
if(bme->port==BME680_I2C)
{
if((bmeAddress==0xEC)||(bmeAddress==0xEE))
{
bme->bmeAddress=bmeAddress;
}
else if((bmeAddress==0x76)||(bmeAddress==0x77))
{
bme->bmeAddress=(bmeAddress<<1);
}
else
{
return;
}
bme->ChipSelect=NULL;
}
else
{
if(ChipSelect!=NULL)
{
bme->ChipSelect=ChipSelect;
}
else
{
bme->ChipSelect=BME680ChipSelectDefault;
}
}
bme->chipID=0x00;
bme->pressure=0.0;
bme->temperature=25.0;
bme->humidity=0.0;
bme->bmeAddress=0x00;
bme->caliPara.t_fine=0;
if(!ObjectIsValid(bme))
{
return;
}
while(try_count--)
{
ReadBME680Register(bme,REG_BME680_ID,®Value,1);
bme->chipID=regValue;
if(0x61==bme->chipID)
{
BME680SoftReset(bme);
break;
}
}
if(try_count)
{
uint8_t waitTime;
waitTime=CalcProfileDuration(bme,duration,osrs_t,osrs_p,osrs_h);
//控制暫存器配置
ConfigControlRegister(bme,filter,spi3W_en,osrs_t,osrs_p,spi3wint_en,osrs_h,run_gas,nb_conv,heat_off,waitTime,tempTarget);
//讀取校準值
GetBME680CalibrationData(bme);
}
}
2.2、物件操作
每一個物件都有操作,我們使用物件的目的當然是通過操作物件來獲取我們需要的資料,所以開發驅動時,物件的操作才是我們主要的作業內容,在這里對BME680的操作就是對其暫存器的操作,
2.2.1、寫暫存器操作
我們已經說過了,對BME680的操作都是通過讀寫暫存器實作的,這里我們先來看寫暫存器,在I2C介面方式下,寫暫存器操作是在從站地址的最后一位來識別的,再加上要寫的暫存器地址和資料來實作的,這也是I2C協議的標準做法,其時序圖如下所示:

而在SPI介面方式下,由于SPI并未有設備地址,也不存在用從還在那地址最后為來標記讀寫的模式,通常一些設備需要定義操作碼來實作讀寫區分,但BME680采取了將暫存器地址的最高位置零表示為寫,之所以可以這樣定義,是因為BME680暫存器地址分配的特殊性決定的,改變暫存器地址的最高位也能區分不同的暫存器,絕不會重復,在SPI介面方式下,寫暫存器的時序圖如下所示:

根據上述描述和時序圖,我們可以實作寫BME680環境傳感器暫存器的程式,
/* 向BME680暫存器寫一個位元組 */
static void WriteBME680Register(BME680ObjectType *bme,uint8_t regAddress,uint8_t command)
{
if(ObjectIsValid(bme))
{
if(bme->port==BME680_SPI)
{
bme->ChipSelect(BME680CS_Enable);
bme->Delayms(1);
SetMemeryPageNumber(bme,regAddress);
regAddress&=0x7F;
bme->Delayms(1);
bme->Write(bme,regAddress,command);
bme->Delayms(1);
bme->ChipSelect(BME680CS_Disable);
}
else
{
bme->Write(bme,regAddress,command);
}
}
}
2.2.2、讀暫存器操作
讀暫存器的處理方式與寫暫存器是類似,在I2C介面方式下,將從站地址的最低位置1來表示讀,在I2C介面方式下,讀暫存器的時序圖如下所示:

而在SPI介面方式下,通過將暫存器地址的最改為置1來標識為讀操作,事實上,所有暫存器地址的最高為都是1,所以在讀操作時實際不需要做處理,在SPI介面方式下,讀暫存器的時序圖如下所示:

根據上述描述和時序圖,我們可以實作讀BME680環境傳感器暫存器的程式,
/*從BME680暫存器讀取資料*/
static uint8_t ReadBME680Register(BME680ObjectType *bme,uint8_t regAddress,uint8_t *rDatas,uint16_t rSize)
{
uint8_t bmeError=0xFF;
if(ObjectIsValid(bme))
{
if(bme->port==BME680_SPI)
{
bme->ChipSelect(BME680CS_Enable);
bme->Delayms(1);
SetMemeryPageNumber(bme,regAddress);
regAddress |= 0x80;
bme->Delayms(1);
bme->Read(bme,regAddress,rDatas,rSize);
bme->Delayms(1);
bme->ChipSelect(BME680CS_Disable);
}
else
{
bme->Read(bme,regAddress,rDatas,rSize);
}
bmeError=0x00;
}
return bmeError;
}
3、驅動的使用
上一節我們設計并實作了BME680環境傳感器的驅動程式,但這個驅動設計的是否合理還不確定,所以我們來設計一個簡單的應用驗證BME680環境傳感器的驅動,
3.1、宣告并初始化物件
使用基于物件的操作我們需要先得到這個物件,所以我們先要使用前面定義的BME680環境傳感器物件型別宣告一個BME680環境傳感器物件變數,具體操作格式如下:
BME680ObjectType bme680;
宣告了這個物件變數并不能立即使用,我們還需要使用驅動中定義的初始化函式對這個變數進行初始化,這個初始化函式所需要的輸入引數如下:
BME680ObjectType *bme,BMP680物件
uint8_t bmeAddress,I2C介面是設備地址
BME680PortType port,介面選擇
BME680IIRFilterType filter,過濾器
BME680SPI3wUseType spi3W_en,3線SPI控制
BME680TempSampleType osrs_t,溫度精度
BME680PresSampleType osrs_p,壓力精度
BME680SPI3wIntType spi3wint_en,3線SPI中斷控制
BME680HumiSampleType osrs_h,濕度精度
BME680GasRunType run_gas,氣體運行設定
BME680HeaterSPType nb_conv,加熱器設定點選擇
BME680HeaterOffType heat_off,加熱器關閉
uint16_t duration,TPHG測量回圈周期,ms單位
uint8_t tempTarget,加熱器的目標溫度
BME680Read Read,讀資料操作指標
BME680Write Write,寫資料操作指標
BME680Delayms Delayms,延時操作指標
BME680ChipSelect ChipSelect,片選操作指標
對于這些引數,物件變數我們已經定義了,其他的引數基本都是配置引數,我們根據實際使用需求選擇輸入就好了,主要的是我們需要定義幾個函式,并將函式指標作為引數,這幾個函式的型別如下:
/* 定義讀資料操作函式指標型別 */
typedef void (*BME680Read)(struct BME680Object *bme,uint8_t regAddress,uint8_t *rData,uint16_t rSize);
/* 定義寫資料操作函式指標型別 */
typedef void (*BME680Write)(struct BME680Object *bme,uint8_t regAddress,uint8_t command);
/* 定義延時操作函式指標型別 */
typedef void (*BME680Delayms)(volatile uint32_t nTime);
/* 定義使用SPI介面時,片選操作函式指標型別 */
typedef void (*BME680ChipSelect)(BME680CSType cs);
對于這幾個函式我們根據樣式定義就可以了,具體的操作可能與使用的硬體平臺有關系,若采用的SPI介面則需注意片選操作,片選操作函式用于多設備需要軟體操作時,如采用硬體片選可以傳入NULL即可,同樣如果采用的是I2C介面,則片選可以傳入NULL即可,具體函式定義如下:
/*讀BME680暫存器值*/
static void ReadDataFromBME680(BME680ObjectType *bme680,uint8_t regAddress,uint8_t *rData,uint16_t rSize)
{
HAL_I2C_Master_Transmit(&bme680hi2c, bme680->bmeAddress,®Address,1,1000);
HAL_I2C_Master_Receive(&bme680hi2c, bme680->bmeAddress+1,rData, rSize, 1000);
}
/*寫BME680暫存器值*/
static void WriteDataToBME680(BME680ObjectType *bme680,uint8_t regAddress,uint8_t command)
{
uint8_t pData[2];
pData[0]=regAddress;
pData[1]=command;
HAL_I2C_Master_Transmit(&bme680hi2c,bme680->bmeAddress, pData, 2,1000);
}
對于延時函式我們可以采用各種方法實作,我們采用的STM32平臺和HAL庫則可以直接使用HAL_Delay()函式,于是我們可以呼叫初始化函式如下:
BME680Initialization(&bme680, //BME280物件
0xEC, //I2C介面是設備地址
BME680_I2C, //介面選擇
BME680_IIR_FILTER_COEFF_X127, //過濾器
BME680_SPI3W_DISABLE, //3線SPI控制
BME680_TEMP_SAMPLE_X16, //溫度精度
BME680_PRES_SAMPLE_X16, //壓力精度
BME680_SPI3W_INT_DISABLE, ///3線SPI中斷使能
BME680_HUMI_SAMPLE_X16, //濕度精度
BME680_GAS_RUN_ENABLE,//氣體運行設定
BME680_HEATER_SP0,//加熱器設定點選擇
BME680_HEATER_DISABLE,//加熱器關閉
20,//TPHG測量回圈周期,ms單位
200,//加熱器的目標溫度
ReadDataFromBME680, //讀資料操作指標
WriteDataToBME680, //寫資料操作指標
HAL_Delay, //延時操作指標
NULL //片選操作指標
);
3.2、基于物件進行操作
我們定義了物件變數并使用初始化函式給其作了初始化,接著我們就來考慮操作這一物件獲取我們想要的資料,我們在驅動中已經將獲取資料并轉換為轉換值的比例值,接下來我們使用這一驅動開發我們的應用實體,
/*獲取環境資料*/
void BME680GetEnvironmentalData(void)
{
float pressure; //壓力值
float temperature; //溫度值
float humidity; //濕度值
float gasResistance; //氣體電阻
GetBME680Measure(&bme680);
pressure=bme680.pressure;
temperature=bme680.temperature;
humidity=bme680.humidity;
gasResistance=bme680.gasResistence;
}
4、應用總結
我們設計并實作了BME680環境傳感器的驅動程式,并基于這一驅動程式設計了簡單的應用,我們獲得了BME680檢測的全部環境資料,結果也是令我們滿意的,這說明我們的驅動設計是正確的,
在使用驅動時需注意,采用SPI介面的器件需要考慮片選操作的問題,如果片選信號是通過硬體電路來實作的,我們在初始化時給其傳遞NULL值,如果是軟體操作片選則傳遞我們撰寫的片選操作函式,而如果采用I2C介面,那么在初始化時也應傳遞NULL值,
BME680環境傳感器支持SPI和I2C兩種介面,而且SPI也支持3線和4線模式,但我們在測驗應用中只使用了I2C介面,SPI介面還有待測驗,BME680環境傳感器在使用SPI介面時,支持SPI模式0(CPOL=CPHA=0)和模式3(CPOL=CPHA=1),而在使用I2C介面時,支持標準模式、快速模式以及高速模式,而且在使用I2C介面時,SDO引腳必須接高電平或低電平,以確定設備地址,
BME680環境傳感器有2種作業模式:休眠模式和強制模式,在設備上電后就進入休眠模式,在這種模式下設備不執行測量作業,一旦啟動強制模式則執行一遍TPHG回圈檢測,模式設定的具體定義如下:

對于BME680環境傳感器有一個測量范圍暫存器,這個暫存器的值對應兩組計算常數,這下常數用于測量值的計算,具體如下:

總的來說對BME680環境傳感器的讀寫操作本身并不復雜,但其計算與修正關系卻相對復雜,特別是氣體質量資料更應注意,
原始碼下載:https://github.com/foxclever/ExPeriphDriver
歡迎關注:

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/241413.html
標籤:其他
下一篇:YS13-3熒光管時鐘設計
