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