絕對壓力的檢測是常見的需求。在我們的系統(tǒng)中也常常會遇到。而MS5837壓力傳感器也是我們進場會采用的方案。在這篇里我們將討論并實現(xiàn)MS5837壓力傳感器的驅(qū)動。
1 、功能概述
MS5837壓力傳感器是一種可用于電路板上,適用于檢測10-1200mbar壓力范圍的傳感器,靈敏度非常高,理論上能夠檢測到0.01mbar的壓力變化,實際使用過程中測試并無明顯的變化。
MS5837壓力傳感器采用I2C總線通訊,與MCU可以實現(xiàn)I2C通訊。硬件連接方式如下:
MS5837壓力傳感器擁有5類基本命令:復(fù)位、讀取出廠校準值、數(shù)據(jù)1轉(zhuǎn)換(壓力值數(shù)據(jù))、數(shù)據(jù)2轉(zhuǎn)換(溫度值數(shù)據(jù))和讀取ADC的轉(zhuǎn)換結(jié)果。具體分配如下:
因為MS5837的地址是固定的,所以一個I2C總線只能掛1個MS5837模塊。其設(shè)備地址固定為:0xEC。
2 、驅(qū)動設(shè)計與實現(xiàn)
我們已經(jīng)了解了MS5837的基本功能和操作方式。接下來我們就根據(jù)前面的分析實現(xiàn)MS5837的驅(qū)動。
2.1 、對象定義
在使用該對象之前,我們需要定義對象,我們根據(jù)MS5837的屬性和操作來定義對象。
2.1.1 、對象類型抽象
為了方便操作與復(fù)用,我們使用基于對象的操作。這里我們先來抽象MS5837壓力傳感器對象的類型,該類型包含了MS5837的必要屬性和對MS5837基本操作。
我們先來分析MS5837壓力傳感器對象的屬性。MS5837壓力傳感器使用的是I2C通訊接口,需要一個地址分辨總線上的不同設(shè)備,所以我們將I2C設(shè)備地址作為MS5837壓力傳感器對象的一個屬性。此外,在計算MS5837壓力傳感器測量的壓力、溫度值時需要使用6個校準參數(shù),而且這些參數(shù)每臺設(shè)備都是不一樣的,所以我們將這些參數(shù)作為屬性來保存其值。
接下來我們再來分析MS5837壓力傳感器對象的操作。我們使用MS5837壓力傳感器時,需要向其寫命令和從其讀數(shù)據(jù),而讀寫操作都依賴于具體的硬件平臺,所以我們將寫數(shù)據(jù)和讀數(shù)據(jù)作為對象的操作。此外,為控制時序,我們需要延時操作,而延時行為的實現(xiàn)亦依賴于具體的軟硬件平臺,所以我們將延時也作為對象的操作。
根據(jù)上述我們對MS5837壓力傳感器對象的分析,我們可以抽象MS5837壓力傳感器的對象類型為:
1 /* 定義MS5837對象類型 */
2 typedef struct MS5837Object {
3 uint8_t devAddress; //設(shè)備地址
4 uint16_t caliData[6]; //校準數(shù)據(jù)
5 float temperature;
6 float pressure;
7 void (*Write)(struct MS5837Object *ms,uint8_t command);/*向MS5837下發(fā)指令,指令格式均為1個字節(jié)*/
8 void (*Read)(struct MS5837Object *ms,uint8_t *rData,uint16_t rSize);/*從MS5837讀取多個字節(jié)數(shù)據(jù)的值*/
9 void (*Delayms)(volatile uint32_t nTime); //毫秒秒延時函數(shù)
10 }MS5837ObjectType;
2.1.2 、對象初始化
在使用之前,我們先要使用對象類型聲明對象,但聲明的對象只是一個變量,該對象變量在使用前必須初始化,所以我們定義了對象初始化函數(shù)。
1 /* 初始化MS5837對象 */
2 void MS5837Initialization(MS5837ObjectType *ms,MS5837Write write,MS5837Read read,MS5837Delayms delay)
3 {
4 if((ms==NULL)||(write==NULL)||(read==NULL)||(delay==NULL))
5 {
6 return;
7 }
8
9 ms->Write=write;
10 ms->Read=read;
11 ms->Delayms=delay;
12
13 ms->devAddress=0b11101100;
14 ms->pressure=0.0;
15 ms->temperature=0.0;
16
17 ResetForMs5837(ms);
18
19 GetCalibrationData(ms);
20 }
2.2 、對象操作
完成了對象的聲明與初始化之后,我們就可以使用對象變量來操作對象了。關(guān)于MS5837的操作主要有:設(shè)備復(fù)位、校準值獲取、轉(zhuǎn)換值的讀取。下面將一一實現(xiàn)。
2.2.1 、復(fù)位操作
復(fù)位操作在MS5837壓力傳感器有電時就可執(zhí)行,但一般會在上電之后需要復(fù)位一下,以保持內(nèi)存中的校準參數(shù)值是正確的。此外,當I2C的SDA引腳因未知原因出現(xiàn)阻塞時,復(fù)位能消除這種不確定性。復(fù)位操作只需要發(fā)送一條命令,其時序圖如下:
1 /*復(fù)位MS5837操作*/
2 void ResetForMs5837(MS5837ObjectType *ms)
3 {
4 uint8_t command=COMMAND_RESET;
5
6 /*下發(fā)復(fù)位命令*/
7 ms->SendCommand(ms,command);
8 }
2.2.2 、讀取校準值
校準值是出廠時廠家校準的各種系數(shù),每臺設(shè)備都有差異,是固定不變的,只需要一次讀取就可以了,共有6個系數(shù),均為16為整數(shù)。首先發(fā)送讀系數(shù)的命令,然后讀取就可以了,每次讀取1個,分6次讀取。過程數(shù)據(jù)流如下圖所示:
1 /*讀取MS5837內(nèi)存寄存器的數(shù)據(jù)*/
2 static uint16_t ReadPromFromMs5837(MS5837ObjectType *ms,uint8_t command)
3 {
4 /*下發(fā)讀取指定內(nèi)存單元的命令*/
5 ms->Write(ms,command);
6
7 /*接收讀取的指定內(nèi)存單元的值*/
8 uint8_t promValue[2];
9 ms->Read(ms,promValue,2);
10
11 uint16_t result=(uint16_t)promValue[0];
12 result=(result<<8)+(uint16_t)promValue[1];
13
14 return result;
15 }
2.2.3 、讀取轉(zhuǎn)換值
讀取轉(zhuǎn)換結(jié)果值是我們的目的,可以讀取溫度和壓力兩個量,不過一次只能讀一個。首先發(fā)送命令設(shè)定采集壓力還是溫度,并設(shè)定精度。然后發(fā)送讀取的命令,最后讀取對應(yīng)的值。再使用校準系數(shù)計算出最終的物理值。
1 /*讀取MS5837ADC的轉(zhuǎn)換值*/
2 static uint32_t ReadConversionFromMs5837(MS5837ObjectType *ms,uint8_t command)
3 {
4 /*下發(fā)轉(zhuǎn)化對象及精度配置命令*/
5
6 ms->Write(ms,command);
7
8 ms->Delayms(10);
9
10 /*下發(fā)讀取ADC的命令*/
11 ms->Write(ms,COMMAND_ADC_READ);
12
13 ms->Delayms(10);
14
15 /*接收讀取的ADC轉(zhuǎn)換結(jié)果*/
16 uint8_t adcValue[3];
17 ms->Read(ms,adcValue,3);
18
19 uint32_t result=(uint32_t)adcValue[0];
20 result=(result<<8)+(uint32_t)adcValue[1];
21 result=(result<<8)+(uint32_t)adcValue[2];
22
23 return result;
24 }
這里獲取的只是ADC的數(shù)字碼值。我們想要得到溫度和壓力的物理量值還需要使用校準值,通過廠家提供的公式計算得到。
3 、驅(qū)動的使用
在前面我們描述了MS5837壓力傳感器的基本情況,在此基礎(chǔ)上設(shè)計并實現(xiàn)了MS5837壓力傳感器對象的驅(qū)動程序。這一節(jié)我們將設(shè)計一個簡單的應(yīng)用來驗證驅(qū)動設(shè)計是否符合要求。
3.1 、聲明并初始化對象
使用基于對象的操作我們需要先得到這個對象,所以我們先要使用前面定義的MS5837壓力傳感器對象類型聲明一個MS5837壓力傳感器對象變量,具體操作格式如下:
MS5837ObjectType ms5837;
聲明了這個對象變量并不能立即使用,我們還需要使用驅(qū)動中定義的初始化函數(shù)對這個變量進行初始化。這個初始化函數(shù)所需要的輸入?yún)?shù)如下:
MS5837ObjectType *ms,MS5837對象
MS5837Write write,向MS5837寫數(shù)據(jù)函數(shù)指針
MS5837Read read,從MS5837讀數(shù)據(jù)函數(shù)指針
MS5837Delayms delayms,毫秒延時函數(shù)指針
對于這些參數(shù),對象變量我們已經(jīng)定義了。我們需要重點關(guān)注幾個函數(shù)指針,首先要定義這幾個函數(shù),并將函數(shù)指針作為參數(shù)。這幾個函數(shù)的類型如下:
1 /*向MS5837下發(fā)指令,指令格式均為1個字節(jié)*/
2 typedef void (*MS5837Write)(struct MS5837Object *ms,uint8_t command);
3
4 /*從MS5837讀取多個字節(jié)數(shù)據(jù)的值*/
5 typedef void (*MS5837Read)(struct MS5837Object *ms,uint8_t *rData,uint16_t rSize);
6
7 /*毫秒秒延時函數(shù)*/
8 typedef void (*MS5837Delayms)(volatile uint32_t nTime);
對于這幾個函數(shù)我們根據(jù)樣式定義就可以了,具體的操作可能與使用的硬件平臺有關(guān)系。片選操作函數(shù)用于多設(shè)備需要軟件操作時,如采用硬件片選可以傳入NULL即可。具體函數(shù)定義如下:
1 /*通過I2C1接口下發(fā)命令*/
2 static void SendCommandToMS5837(MS5837ObjectType *ms,uint8_t command)
3 {
4 HAL_I2C_Master_Transmit(&ms5837hi2c,ms->devAddress,&command,1,1000);
5 }
6
7 /*通過I2C1接口讀取數(shù)據(jù)*/
8 static void GetDatasFromMS5837(MS5837ObjectType *ms,uint8_t *rData,uint16_t rSize)
9 {
10 HAL_I2C_Master_Receive(&ms5837hi2c,ms->devAddress,rData,rSize,1000);
11 }
對于延時函數(shù)我們可以采用各種方法實現(xiàn)。我們采用的STM32平臺和HAL庫則可以直接使用HAL_Delay()函數(shù)。于是我們可以調(diào)用初始化函數(shù)如下:
MS5837Initialization(&ms5837,SendCommandToMS5837,GetDatasFromMS5837,HAL_Delay);
3.2 、基于對象進行操作
我們定義了對象變量并使用初始化函數(shù)給其作了初始化。接著我們就來考慮操作這一對象獲取我們想要的數(shù)據(jù)。我們在驅(qū)動中已經(jīng)將獲取數(shù)據(jù)并轉(zhuǎn)換為轉(zhuǎn)換值的比例值,接下來我們使用這一驅(qū)動開發(fā)我們的應(yīng)用實例。
1 /*獲取壓力變送器數(shù)據(jù)*/
2 void MS5837GetMeasureData(void)
3 {
4 float pressure=0.0;
5 float temperature=0.0;
6
7 GetMS5837ConversionValue(&ms5837,MS5837_OSR8192,MS5837_OSR8192);
8
9 pressure=ms5837.pressure;
10 temperature=ms5837.temperature;
11 }
4 、應(yīng)用總結(jié)
我們已經(jīng)實現(xiàn)了MS5837壓力傳感器的驅(qū)動程序,也設(shè)計了一個簡單的應(yīng)用來驗證這一驅(qū)動程序。驗證的結(jié)果與我們預(yù)期一樣,得到了我們需要的數(shù)據(jù)。我們也曾將這一驅(qū)動應(yīng)用于實際項目,效果也是令人滿意的。
使用驅(qū)動是需要注意,MS5837壓力傳感器雖然采用了I2C接口,但它的地址是固定的,所以一條總線上只能有一臺MS5837壓力傳感器。所以在驅(qū)動中地址是固化在驅(qū)動程序中不可修改的。
源碼下載: https://github.com/foxclever/ExPeriphDriver
評論
查看更多