日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

外设驱动库开发笔记19:BMP280压力温度传感器驱动

發布時間:2024/7/23 编程问答 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 外设驱动库开发笔记19:BMP280压力温度传感器驱动 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

壓力和溫度監測在嵌入式系統開發中是非常常見的需求,特別是對環境大氣壓力和溫度的檢測需求就更常見了。我們一般都會選擇一些封裝較小操作比較方便的壓力傳感器。BMP280就是滿足這一要求的器件。在這一篇中我們將設計并實現BMP280的驅動。

1、功能概述

BMP280是一款絕對壓力傳感器產品。BMP280是一款絕對的氣壓傳感器,專為移動應用而設計。傳感器模塊采用極其緊湊的封裝。其小尺寸和低功耗允許在諸如移動電話,GPS模塊或手表的電池供電設備中實現。

1.1、硬件接口

BMP280基于博世經過驗證的壓阻式壓力傳感器技術,具有高精度和線性度以及長期穩定性和高EMC穩健性。眾多器件操作選項提供了最高的靈活性,可針對功耗,分辨率和濾波器性能優化器件。為開發人員提供了一組經過測試的默認設置(例如用例),以便盡可能簡化設計。

BMP280壓力溫度傳感器采用了小巧的8引腳LGA封裝形式。其引腳排布就功能如下圖所示:

BMP280壓力溫度傳感器支持3種通訊接口方式:四線SPI、三線SPI以及I2C。在不同的接口模式下,各引腳的定義也是有差異的,關于這三種接口模式各引腳的定義如下:

對應3種不同的接口方式,BMP280壓力溫度傳感器存在三種與總線連接的方式。首先我們來看四線SPI接口方式,包括CSB片選、SCK時鐘、SDI數字輸入、SDO數字輸出。其總線連接方式如下圖:

?

接下來我們來看三線SPI接口方式,包括CSB片選、SCK時鐘、SDI數字輸入/SDO數字輸出。其與4SPI的區別是數字輸入輸出使用同一引腳,第3腳就是輸入也是輸出,而第5腳浮空。其總線連接方式如下圖:

最后我們來看I2C接口方式,包括SCL時鐘、SDA數字輸入輸出。在I2C接口模式下,第2CSB連接到高電平,以設置BMP280壓力溫度傳感器使用I2C接口。而第5腳則可以通過連接高電平或低電平來設置設備地址的最后一位,不可以浮空。所以根據第5腳電頻不同,BMP280壓力溫度傳感器的I2C設備7位地址為:0x760x77。其總線連接方式如下圖:

BMP280壓力溫度傳感器在使用SPI接口時,支持SPI模式0CPOL=CPHA=0)和模式3CPOL=CPHA=1)。而在使用I2C接口時,支持標準模式、快速模式以及高速模式。接口的選擇實際上是通過CSB的電位實現的,低電平時就是SPI,高電平時就是I2C

1.2、數據存儲結構

BMP280壓力溫度傳感器的所有操作都是通過讀寫對應的寄存器來實現的。BMP280壓力溫度傳感器中所有的寄存器都是8位的。這些寄存器在存儲器中的地址分配如下圖所示。

在上圖并未包括系統保留的寄存器,這些寄存器不可以進行寫操作,讀出來的值也是無意義的。接下來我們來詳細描述上圖中的這些寄存器。

先來看看兩個比較特殊的寄存器。首先是ID寄存器,這個寄存器是只讀的,而且其存儲的值也固定為0x58,用來代表設備為BMP280壓力溫度傳感器。這個寄存器在系統上電后即可讀取。還有復位寄存器,這個寄存器是只寫的,固定向其寫0xB6來實現BMP280壓力溫度傳感器的復位。同樣只要系統上電后即可以寫復位寄存器。

狀態寄存器是只讀的,其實只使用了其中的兩位,這兩位分別表示數據測量是否完成和影響寄存器是否更新。下圖是狀態寄存器的詳細說明:

測量控制寄存器是可讀寫的,用以配置BMP280壓力溫度傳感器數據獲取的方式。分別配置溫度采樣、壓力采樣和工作模式。工作模式有三種:休眠模式、強制模式、正常模式。系統上電后即為休眠模式,通過這一寄存器的配置可以使BMP280壓力溫度傳感器進入強制模式或正常模式運行。測量控制寄存器的各位定義如下圖:

配置寄存器用于設置BMP280壓力溫度傳感器的速率、過濾器以及接口模式。在休眠模式下寫配置寄存器是允許的,但在正常模式下會被忽略,所以在系統復位后,進入正常模式前先寫配置寄存器。配置寄存器各位的定義如下圖所示:

壓力數據寄存器存儲有壓力測量數據輸出的原始值。使用了三個寄存器中的20位來下存儲壓力數據。壓力數據寄存器各位的定義如下圖所示:

溫度數據寄存器存儲有溫度測量數據輸出的原始值。使用了三個寄存器中的20位來下存儲溫度數據。溫度數據寄存器各位的定義如下圖所示:

此外還有校準數據寄存器,總共是26個寄存器,存儲了計算壓力溫度最終值的廠家校準數據。這些校準寄存器的定義及地址分配如下圖所示:

我們已經說過面向BMP280壓力溫度傳感器的所有操作都是基于寄存器進行的,我們已經了解了BMP280壓力溫度傳感器的各個寄存器,現在可以來實現它的操作了。

2、驅動設計與實現

我們已經比較詳細的說明了BMP280的引腳定義、通訊接口、數據存儲格式,在此基礎上我們將設計并實現BMP280壓力溫度傳感器的驅動程序。

2.1、對象定義

在使用一個對象之前我們需要獲得一個對象。同樣的我們想要BMP280壓力溫度傳感器就需要先定義BMP280壓力溫度傳感器的對象。

2.1.1、對象類型抽象

我們要得到BMP280壓力溫度傳感器對象,需要先分析其基本特性。一般來說,一個對象至少包含兩方面的特性:屬性與操作。接下來我們就來從這兩個方面思考一下BMP280壓力溫度傳感器的對象。

先來考慮屬性,作為屬性肯定是用于標識或記錄對象特征的東西。我們來考慮BMP280壓力溫度傳感器對象屬性。BMP280壓力溫度傳感器的ID寄存器用于標識設備是否為BMP280;配置寄存器和測量控制寄存器都用關于系統配置,指示了設備的工作狀態,所以我們將這三個寄存器定義為對象的屬性。而使用的通訊接口決定了訪問BMP280壓力溫度傳感器的行為,所以我們需要記住這一配置;而校準數據則在計算數據時所要使用的,我們也需要記住這些參數,所以我們將它們也都定義為屬性。在I2C接口模式時,設備地址是區分總線上設備的唯一標志,所以我們將其定義為屬性。同樣測量數據指示了設備當前的工作狀態,我們將器作為屬性。

接著我們還需要考慮BMP280壓力溫度傳感器對象的操作問題。我們需要與BMP280壓力溫度傳感器通訊就需要向其寫數據并從其讀數據,而不論是SPI接口還是I2C接口,讀寫操作都以來與具體的硬件平臺,所以我們將他們作為對象的操作。此外,為控制時序,我們需要延時操作,而延時行為的實現亦依賴于具體的軟硬件平臺,所以我們將延時也作為對象的操作。

根據上述我們對BMP280壓力溫度傳感器的分析,我們可以定義BMP280壓力溫度傳感器的對象類型如下:

/*定義BMP280操作對象*/ typedef struct BMP280Object{uint8_t bmpAddress; //I2C接口時設備地址uint8_t chipID;?? //芯片IDuint8_t config;??? //配置寄存器uint8_t ctrlMeas; //測量控制寄存器BMP280PortType port;??? //接口選擇Bmp280CalibParamType caliPara;?????? //校準參數float pressure;???? //壓力值float temperature;????? //溫度值void (*Read)(struct BMP280Object *bmp,uint8_t regAddress,uint8_t *rData,uint16_t rSize);? //讀數據操作指針void (*Write)(struct BMP280Object *bmp,uint8_t regAddress,uint8_t command);?? //寫數據操作指針void (*Delayms)(volatile uint32_t nTime);??? //延時操作指針void (*ChipSelect)(BMP280CSType en);?? //使用SPI接口時,片選操作 }BMP280ObjectType;

2.1.2、對象初始化

我們知道,一個對象僅作聲明是不能使用的,我們需要先對其進行初始化,所以這里我們來考慮BMP280壓力溫度傳感器對象的初始化函數。一般來說,初始化函數需要處理幾個方面的問題。一是檢查輸入參數是否合理;二是為對象的屬性賦初值;三是對對象作必要的初始化配置。據此我們設計BMP280壓力溫度傳感器對象的初始化函數如下:

/* 實現BMP280初始化配置 */void BMP280Initialization(BMP280ObjectType *bmp,?????? //BMP280對象uint8_t bmpAddress,??????????//I2C接口是設備地址BMP280PortType port,?????????//接口選擇TimeStandbyType t_sb,????????//間隔周期IIRFilterCoeffType filter,???//過濾器UseSPI3wType spi3W_en,???? ??//3線SPI控制TemperatureSampleType osrs_t,//溫度精度PressureSampleType osrs_p,???//壓力精度PowerModeType mode,???????? ?//電源模式BMP280Read Read,?????????????//讀數據操作指針BMP280Write Write,?????????? //寫數據操作指針BMP280Delayms Delayms,???????//延時操作指針BMP280ChipSelect ChipSelect???//片選操作指針) {uint8_t try_count = 5;uint8_t regAddress=0;uint8_t command=0;bmp->chipID=0x00bmp->pressure=0.0;bmp->temperature=0.0;bmp->bmpAddress=0x00;bmp->port=port;if(bmp->port==I2C){if((bmpAddress==0xEC)||(bmpAddress==0xEE)){bmp->bmpAddress=bmpAddress;}bmp->ChipSelect=NULL;}else{bmp->ChipSelect=ChipSelect;}bmp->Read=Read;bmp->Write=Write;bmp->Delayms=Delayms;bmp->caliPara.t_fine=0;if(!ObjectIsValid(bmp)){return;}while(try_count--){bmp->chipID=ReadBMP280Register(bmp,REG_BMP280_ID);if(0x58==bmp->chipID){BMP280SoftReset(bmp);break;}}if(try_count){/*配置配置寄存器:間隔周期0.5ms、IIR濾波系數16、不使用SPI3線通訊*/regAddress=REG_CONFIG;command=t_sb|filter|spi3W_en;WriteBMP280Register(bmp,regAddress,command);/*配置測量控制寄存器:溫度20位,壓力20位,電源正常模式*/regAddress=REG_CTRL_MEAS;command=osrs_t|osrs_p|mode;WriteBMP280Register(bmp,regAddress,command);bmp->Delayms(10);bmp->config=ReadBMP280Register(bmp,REG_CONFIG);bmp->Delayms(10);bmp->ctrlMeas=ReadBMP280Register(bmp,REG_CTRL_MEAS);bmp->Delayms(10);/*讀取校準值*/GetBMP280CalibrationData(bmp);} }

2.2、對象操作

我們已經完成了BMP280壓力溫度傳感器對象類型的定義和對象初始化函數的設計。但我們的主要目標是獲取對象的信息,接下來我們還要實現面向BMP280壓力溫度傳感器的各類操作。

2.2.1、寫寄存器

我們已經說過了,對BMP280的操作都是通過讀寫寄存器實現的。這里我們先來看寫寄存器。在I2C接口方式下,寫寄存器操作是在從站地址的最后一位來識別的,再加上要寫的寄存器地址和數據來實現的,這也是I2C協議的標準做法。其時序圖如下所示:

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

根據上述描述和時序圖,我們可以實現寫BMP280壓力溫度傳感器寄存器的程序。

/* 向BMP280寄存器寫一個字節 */ static void WriteBMP280Register(BMP280ObjectType *bmp,uint8_t regAddress,uint8_t command) {if(ObjectIsValid(bmp)){if(bmp->port==BMP280_SPI){regAddress&=0x7F;bmp->ChipSelect(BMP280CS_Enable);bmp->Delayms(1);bmp->Write(bmp,regAddress,command);bmp->Delayms(1);bmp->ChipSelect(BMP280CS_Disable);}else{bmp->Write(bmp,regAddress,command);}} }

2.2.2、讀寄存器

讀寄存器的處理方式與寫寄存器是類似。在I2C接口方式下,將從站地址的最低位置1來表示讀。在I2C接口方式下,讀寄存器的時序圖如下所示:

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

根據上述描述和時序圖,我們可以實現讀BMP280壓力溫度傳感器寄存器的程序。

/*從BMP280寄存器讀取一個字節*/ static uint8_t ReadBMP280Register(BMP280ObjectType *bmp,uint8_t regAddress) {uint8_t regValue=0xFF;if(ObjectIsValid(bmp)){if(bmp->port==BMP280_SPI){regAddress |= 0x80;bmp->ChipSelect(BMP280CS_Enable);bmp->Delayms(1);bmp->Read(bmp,regAddress,&regValue,1);bmp->Delayms(1);bmp->ChipSelect(BMP280CS_Disable);}else{bmp->Read(bmp,regAddress,&regValue,1);}}return regValue; }

3、驅動的使用

我們已經設計了BMP280壓力溫度傳感器的驅動程序,接下來這一節我們將基于BMP280壓力溫度傳感器的驅動程序設計一個簡單的驗證應用。

3.1、聲明并初始化對象

使用基于對象的操作我們需要先得到這個對象,所以我們先要使用前面定義的BMP280壓力溫度傳感器對象類型聲明一個BMP280壓力溫度傳感器對象變量,具體操作格式如下:

BMP280ObjectType bmp280;

聲明了這個對象變量并不能立即使用,我們還需要使用驅動中定義的初始化函數對這個變量進行初始化。這個初始化函數所需要的輸入參數如下:

BMP280ObjectType *bmpBMP280對象

uint8_t bmpAddressI2C接口是設備地址

BMP280PortType port,接口選擇

BMP280TimeStandbyType t_sb,間隔周期

BMP280IIRFilterCoeffType filter,過濾器

BMP280UseSPI3wType spi3W_en3SPI控制

BMP280TemperatureSampleType osrs_t,溫度精度

BMP280PressureSampleType osrs_,壓力精度

BMP280PowerModeType mode,電源模式

BMP280Read Read,讀數據操作指針

BMP280Write Write,寫數據操作指針

BMP280Delayms Delayms,延時操作指針

BMP280ChipSelect ChipSelect,片選操作指針

對于這些參數,對象變量我們已經定義了。接口選擇、間隔周期、過濾器、3SPI控制、溫度精度、壓力精度、電源模式等都是枚舉量我們根據實際情況輸入即可。而使用I2C接口時需要的設備地址,也按具體地址給入就好。主要的是我們需要定義幾個函數,并將函數指針作為參數。這幾個函數的類型如下:

/* 定義讀數據操作函數指針類型 */ typedef void (*BMP280Read)(BMP280ObjectType *bmp,uint8_t regAddress,uint8_t *rData,uint16_t rSize);/* 定義寫數據操作函數指針類型 */ typedef void (*BMP280Write)(BMP280ObjectType *bmp,uint8_t regAddress,uint8_t command);/* 定義延時操作函數指針類型 */ typedef? void (*BMP280Delayms)(volatile uint32_t nTime);/* 定義使用SPI接口時,片選操作函數指針類型 */ typedef? void (*BMP280ChipSelect)(BMP280CSType cs);

對于這幾個函數我們根據樣式定義就可以了,具體的操作可能與使用的硬件平臺有關系。若采用的SPI接口則需注意片選操作,片選操作函數用于多設備需要軟件操作時,如采用硬件片選可以傳入NULL即可。同樣如果采用的是I2C接口,則片選可以傳入NULL即可。具體函數定義如下:

/*讀BMP280寄存器值*/ static void ReadDataFromBMP280(BMP280ObjectType *bmp280,uint8_t regAddress,uint8_t *rData,uint16_t rSize) {HAL_I2C_Master_Transmit(&bmp280hi2c, bmp280->bmpAddress,&regAddress,1,1000);HAL_I2C_Master_Receive(&bmp280hi2c, bmp280->bmpAddress+1,rData, rSize, 1000); }/*寫BMP280寄存器值*/ static void WriteDataToBMP280(BMP280ObjectType *bmp280,uint8_t regAddress,uint8_t command) {uint8_t pData[2];pData[0]=regAddress;pData[1]=command;HAL_I2C_Master_Transmit(&bmp280hi2c,bmp280->bmpAddress, pData, 2,1000); }

對于延時函數我們可以采用各種方法實現。我們采用的STM32平臺和HAL庫則可以直接使用HAL_Delay()函數。于是我們可以調用初始化函數如下:

BMP280Initialization(&bmp280,? //BMP280對象0xEC,?????????? //I2C接口是設備地址BMP280_I2C,???? //接口選擇BMP280_T_SB_0P5,?????? //間隔周期BMP280_IIR_FILTER_COEFF_X16,???????? //過濾器BMP280_SPI3W_DISABLE,??????????????? //3線SPI控制BMP280_TEMP_SAMPLE_X16,? //溫度精度BMP280_PRES_SAMPLE_X16,????????? //壓力精度BMP280_POWER_NORMAL_MODE,????? //電源模式ReadDataFromBMP280,? //讀數據操作指針WriteDataToBMP280,???? //寫數據操作指針HAL_Delay,???????????????????? //延時操作指針NULL??????????????????????????????? //片選操作指針);

3.2、基于對象進行操作

我們定義了對象變量并使用初始化函數給其作了初始化。接著我們就來考慮操作這一對象獲取我們想要的數據。我們在驅動中已經將獲取數據并轉換為轉換值的比例值,接下來我們使用這一驅動開發我們的應用實例。

/*獲取大氣壓力和溫度*/ void BMP280GetEnvironmentalData(void) {float pressure;?????????????????? //壓力值float temperature;????? //溫度值GetBMP280Measure(&bmp280);pressure=bmp280.pressure;temperature=bmp280.temperature; }

4、應用總結

BMP280壓力溫度傳感器的驅動已經實現并做了簡單的應用。在我們測試時,得到的數據與其它方法獲得的溫度壓力數據基本是一致的,這說明我們的驅動程序總體來說是正確的。

BMP280壓力溫度傳感器支持SPII2C兩種接口,而且SPI也支持3線和4線模式,但我們在測試應用中只使用了I2C接口,SPI接口還有待測試。

在使用驅動時需注意,采用SPI接口的器件需要考慮片選操作的問題。如果片選信號是通過硬件電路來實現的,我們在初始化時給其傳遞NULL值。如果是軟件操作片選則傳遞我們編寫的片選操作函數。而如果采用I2C接口,那么在初始化時也應傳遞NULL值。

BMP280壓力溫度傳感器在使用SPI接口時,支持SPI模式0CPOL=CPHA=0)和模式3CPOL=CPHA=1)。而在使用I2C接口時,支持標準模式、快速模式以及高速模式。而且在使用I2C接口時,SDO引腳必須接高電平或低電平,以確定設備地址。

源碼獲取:https://github.com/foxclever/ExPeriphDriver

歡迎關注:

?

總結

以上是生活随笔為你收集整理的外设驱动库开发笔记19:BMP280压力温度传感器驱动的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。