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