很多時候我們需要檢測被控對象的絕對壓力,而且在我們的多款產品中也有這樣的需求。當然檢測絕對壓力的傳感器有很多,我們經常使用MS5803來實現壓力檢測。本篇中我們將設計并實現MS5803系列壓力傳感器的驅動。
1 、功能概述
MS5803系列產品包含壓阻傳感器和傳感器接口IC。MS5803系列壓力傳感器的主要功能是將未補償的壓阻壓力傳感器的模擬輸出電壓24位數字值,以及提供一個24位數字值的溫度傳感器。
1.1 、硬件描述
MS5803系列壓力傳感器是新一代高分辨率高度計傳感器,它是為高度計和高度分辨率為20厘米的變壓計優化。能夠同時獲得壓力值和溫度值,其中壓力測量范圍為10-1100mbar,溫度的測量范圍是-40-85攝氏度。MS5803系列壓力傳感器各引腳功能如下:
MS5803系列壓力傳感器具有SPI和I2C總線接口。MS5803系列壓力傳感器模塊包括一個高線性壓力傳感器和一個超低功率24位ΔΣADC與內部工廠校準系數。它提供一個精確的數字24位壓力和溫度值和不同的操作模式。傳感器內部結構圖如下:
我們使用MS5803系列壓力傳感器時,需要做的就是選擇不同的通訊接口與其實現數字通訊的過程。
1.2 、通訊接口
MS5803系列壓力傳感器支持SPI和I2C總線通訊,通過協議選擇引腳PS來決定采用什么接口。將協議選擇引腳PS拉低,選擇SPI協議,將PS拉高,激活I2C總線協議。在不同協議下相關引腳的定義如下:
在不同協議下各引腳所支持的參數是有些許差異的。在SPI接口模式下時鐘引腳最大可達20MHz;在I2C接口模式下時鐘引腳最大可達200kHz。具體的參數如下圖:
在SPI模式下,SCLK作為外部輸入時鐘,SDI作為串行數據輸入,支持Mode0和Mode3的時鐘極性和相位。傳感器的響應數據輸出為SDO引腳,片選信號為CSB引腳。SPI模式下接線示意圖如下:
在I2C模式下,SCLK為外部串行時鐘輸入,SDA為串行數據通訊。CSB引腳作為地址選擇,可以鏈接到VDD或者GND,這也意味著MS5803可以在一條I2C總線接兩個設備。在CSP接高電平時,地址為0x76(1110110 b),而CSB接低電平時,地址為0x77 (1110111 b)這個地址是高七位,最后以為有讀寫命令來決定。實現寫命令時,最后一位為0,實現讀命令時,最后一位為1。I2C模式下接線圖如下:
1.3 、數據訪問
無論是在SPI模式還是在I2C模式,MS5803系列壓力傳感器都是通過5類命令實現的。這些命令包括:復位、讀取出廠校準值、數據1轉換(壓力值數據)、數據2轉換(溫度值數據)和讀取ADC的轉換結果。具體命令定義如下:
從上圖,我們知道每個命令的大小為1字節(8位)。需要說明的是,ADC讀取指令后,設備將返回24位結果,PROM讀取則是16位結果。PROM的地址使用Ad2、Ad1和Ad0位嵌入到PROM讀命令中。關于這128bit PROM的地址分配如下圖所示:
MS5803系列壓力傳感器每個模塊都是在兩個溫度和兩個壓力下單獨校準的。這6個必要的系數來補償工藝變化和溫度變化,就存儲在每個模塊的128bit PROM中。這些6個系數必須由軟件讀取,并在程序中使用,將D1和D2轉換成補償的壓力和溫度值。
2 、驅動設計與實現
我們已經了解了MS5803壓力傳感器基本操作。在此基礎上,我們將設計并實現MS5803壓力傳感器的驅動程序。
2.1 、對象定義
在使用一個對象之前我們需要獲得一個對象。同樣的我們想要MS5803壓力傳感器就需要先定義MS5803壓力傳感器的對象。
2.1.1 、對象的抽象
我們要得到MS5803壓力傳感器對象,需要先分析其基本特性。一般來說,一個對象至少包含兩方面的特性:屬性與操作。接下來我們就來從這兩個方面思考一下MS5803壓力傳感器的對象。
先來考慮屬性,作為屬性肯定是用于標識或記錄對象特征的東西。我們來考慮MS5803壓力傳感器對象屬性。首先MS5803有一系列的產品,不同產品線的補償計算方式有很大差異,所以我們將產品類型作為屬性以區別不同的產品。MS5803擁有SPI和I2C兩種通訊方式可供選擇,為了確定具體設備所采用的接口,我們將其作為對象的屬性以記錄其使用的接口方式。在采用I2C接口模式時,每臺設備都有一個設備地址,這個地址用于區分同一總線上不同的設備,所以我們將地址作為對象的屬性。而對于MS5803每臺都有6個校準參數,這些參數在測量是需要用到,所以我們需要保存這些參數,所以我們將其作為屬性。
接著我們還需要考慮MS5803壓力傳感器對象的操作問題。無論是使用SPI接口還是使用I2C接口我們都需要向MS5803寫命令和從MS5803讀數據,而讀寫行為都與所處的硬件平臺相關,所以我們將讀和寫數據作為對象的操作。為控制時序,我們需要延時操作,但延時操作也與具體的軟硬件平臺相關,所以我們將其作為對象的操作。在使用SPI接口方式時,若使用軟件控制片選信號,則會依賴于硬件,我們將針對片選信號的操作作為對象的操作。
根據上述我們對MS5803壓力傳感器的分析,我們可以定義MS5803壓力傳感器的對象類型如下:
1 typedef struct MS5803Object {
2 uint8_t devAddress; //設備地址
3 MS5803PortType port; //通訊端口協議
4 MS5803ModelType model; //設備的類型
5 uint16_t caliData[6]; //校準數據
6 float temperature;
7 float pressure;
8 void (*Write)(struct MS5803Object *ms,uint8_t command);//向MS5803寫信息
9 void (*Read)(struct MS5803Object *ms,uint8_t *rData,uint16_t rSize);//從MS5803讀數據
10 void (*ChipSelcet)(MS5803CSType en); //片選信號,用于SPI接口
11 void (*Delayms)(volatile uint32_t nTime); //毫秒秒延時函數
12 }MS5803ObjectType;
2.1.2 、對象初始化
我們知道,一個對象僅作聲明是不能使用的,我們需要先對其進行初始化,所以這里我們來考慮MS5803壓力傳感器對象的初始化函數。一般來說,初始化函數需要處理幾個方面的問題。一是檢查輸入參數是否合理;二是為對象的屬性賦初值;三是對對象作必要的初始化配置。據此我們設計MS5803壓力傳感器對象的初始化函數如下:
1 /* MS5803對象初始化 */
2 void MS5803Initialization(MS5803ObjectType *ms, //MS5803對象
3 MS5803ModelType model, //類型
4 MS5803PortType port, //通訊端口
5 uint8_t address, //I2C設備地址
6 MS5803Write write, //寫數據函數
7 MS5803Read read, //讀數據函數
8 MS5803ChipSelcet cs, //SPI片選信號
9 MS5803Delayms delayms //毫秒延時
10 )
11 {
12 if((ms==NULL)||(write==NULL)||(read==NULL)||(delayms==NULL))
13 {
14 return;
15 }
16 ms->Write=write;
17 ms->Read=read;
18 ms->Delayms=delayms;
19
20 ms->model=model;
21 ms->port=port;
22
23 if(port==I2C)
24 {
25 if((address==0x76)||(address==0x77))
26 {
27 ms->devAddress=(address<<1);
28 }
29 else if((address==0xEC)||(address==0xEE))
30 {
31 ms->devAddress=address;
32 }
33 else
34 {
35 ms->devAddress=0x00;
36 }
37
38 ms->ChipSelcet=cs;
39 }
40 else
41 {
42 ms->devAddress=0xFF;
43
44 if(cs==NULL)
45 {
46 ms->ChipSelcet=MS5803ChipSelect;
47 }
48 else
49 {
50 ms->ChipSelcet=cs;
51 }
52 }
53
54 ms->pressure=0.0;
55 ms->temperature=0.0;
56
57 ResetForMS5803(ms);
58
59 GetMS5803CalibrationData(ms);
60 }
2.2 、對象操作
我們已經完成了MS5803壓力傳感器對象類型的定義和對象初始化函數的設計。但我們的主要目標是獲取對象的信息,接下來我們還要實現面向MS5803壓力傳感器的各類操作。
對MS5803壓力傳感器的其實就是基于前面我們所說的命令來實現的。根據這些命令的作用,我們可以大致分為三個方面:設備復位、ADC轉換配置及數據獲取、校準系數的獲取。下面我么五年就從這三個方面來看一看MS5803壓力傳感器的操作。
2.2.1 、復位操作
復位操作可以在電源供電后的任意時刻發送,但一般要求在開機后首先發送復位程序。這樣可以確保校準PROM加載到內部寄存器。當然復位操作也可以用來重置設備ROM以便從我們未知的情況中恢復。
在使用SPI通訊接口時,無論是模式0還是模式3其操作是一樣的,SPI方式下的時序圖如下:
在I2C通訊接口時,有時候通訊可能會出現SDA被未定義的狀態阻塞的時候,可以通過復位操作來恢復通訊。I2C方式下的時序圖如下:
1 /*復位MS5803操作*/
2 void ResetForMS5803(MS5803ObjectType *ms)
3 {
4 uint8_t command=COMMAND_RESET;
5 /*下發復位命令*/
6 ms->Write(ms,command);
7
8 ms->Delayms(3);
9 }
2.2.2 、讀取校準值
校準值是出廠時廠家校準的各種系數,每臺設備都有差異,但每臺設備是固定不變的,只需要一次讀取就可以了,共有6個系數,均為16為整數。
用戶復位后,執行一次PROM的read命令,讀取校準PROM的內容,計算校準系數。關于PROM我們前面已經描述過了,總共有8個地址,地址0包含工廠數據和設置,地址1-6校準系數,地址7包含串行代碼和CRC。
在SPI接口通訊模式下,我們發送都對應地址的命令,等待接收數據即可。命令為8位,返回數據為16位,時序圖如下:
在I2C接口通訊模式下,PROM讀命令由兩部分組成。第一個命令將系統設置為PROM讀模式。第二部分從系統中獲取數據。首先發送讀系數的命令,然后讀取就可以了,每次讀取1個,分6次讀取。I2C模式下的時序圖如下所示:
1 /*讀取MS5803內存寄存器的數據*/
2 static uint16_t ReadPromFromMS5803(MS5803ObjectType *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 、讀取轉換值
讀取轉換結果值是我們的目的,可以讀取溫度和壓力兩個量,不過一次只能讀一個。首先發送命令設定采集壓力還是溫度,并設定精度。然后發送讀取的命令,最后讀取對應的值。再使用校準系數計算出最終的物理值。
對于配置轉換及讀取轉換的結果,在SPI接口模式下,按兩步實現:先設置轉換精度,等待轉換結束再讀取數據。具體的時序圖如下:
對于配置轉換及讀取轉換的結果,在I2C接口模式下,按三步實現:先設置轉換精度,等待轉換結束發送讀ADC命令,最后讀取數據。具體的時序圖如下:
1 /*讀取MS5803ADC的轉換值*/
2 static uint32_t ReadConversionFromMS5803(MS5803ObjectType *ms,uint8_t command)
3 {
4 /*下發轉化對象及精度配置命令*/
5 ms->Write(ms,command);
6
7 ms->Delayms(10);
8
9 /*下發讀取ADC的命令*/
10 ms->Write(ms,COMMAND_ADC_READ);
11
12 if(ms->port==I2C)
13 {
14 ms->Delayms(10);
15 }
16
17 /*接收讀取的ADC轉換結果*/
18 uint8_t adcValue[3];
19 ms->Read(ms,adcValue,3);
20
21 uint32_t result=(uint32_t)adcValue[0];
22 result=(result<<8)+(uint32_t)adcValue[1];
23 result=(result<<8)+(uint32_t)adcValue[2];
24
25 return result;
26 }
3 、驅動的使用
我們已經設計并實現了MS5803壓力傳感器的驅動程序,這個驅動程序是否符合要求還需要驗證。這一節我們就來設計一個簡單的應用驗證這一驅動程序。
3.1 、聲明并初始化對象
使用基于對象的操作我們需要先得到這個對象,所以我們先要使用前面定義的MS5803壓力傳感器對象類型聲明一個MS5803壓力傳感器對象變量,具體操作格式如下:
MS5803ObjectType ms5803;
聲明了這個對象變量并不能立即使用,我們還需要使用驅動中定義的初始化函數對這個變量進行初始化。這個初始化函數所需要的輸入參數如下:
MS5803ObjectType *ms,MS5803對象
MS5803ModelType model,類型
MS5803PortType port,通訊端口
uint8_t address,I2C設備地址
MS5803Write write,寫數據函數
MS5803Read read,讀數據函數
MS5803ChipSelcet cs,SPI片選信號
MS5803Delayms delayms,毫秒延時
對于這些參數,對象變量我們已經定義了。設備類型和通訊端口都是枚舉,我們只需要根據實際的配置情況選擇就可以了。設備地址則在采用I2C通訊時,根據實際輸入。我們主要需要關注的是定義幾個函數,并將函數指針作為參數。這幾個函數的類型如下:
1 /*向MS5803下發指令,指令格式均為1個字節*/
2 typedef void (*MS5803Write)(MS5803ObjectType *ms,uint8_t command);
3
4 /*從MS5803讀取多個字節數據的值*/
5 typedef void (*MS5803Read)(MS5803ObjectType *ms,uint8_t *rData,uint16_t rSize);
6
7 /*片選信號,用于SPI接口*/
8 typedef void (*MS5803ChipSelcet)(MS5803CSType en);
9
10 /*毫秒秒延時函數*/
11 typedef void (*MS5803Delayms)(volatile uint32_t nTime);
對于這幾個函數我們根據樣式定義就可以了,具體的操作可能與使用的硬件平臺有關系。若采用的SPI接口則需注意片選操作,片選操作函數用于多設備需要軟件操作時,如采用硬件片選可以傳入NULL即可。同樣如果采用的是I2C接口,則片選可以傳入NULL即可。具體函數定義如下:
1 /*通過I2C1接口下發命令*/
2 static void SendCommandToMS5803(MS5803ObjectType *ms,uint8_t command)
3 {
4 HAL_I2C_Master_Transmit(&ms5803hi2c,ms->devAddress,&command,1,1000);
5 }
6
7 /*通過I2C1接口讀取數據*/
8 static void GetDatasFromMS5803(MS5803ObjectType *ms,uint8_t *rData,uint16_t rSize)
9 {
10 HAL_I2C_Master_Receive(&ms5803hi2c,ms->devAddress,rData,rSize,1000);
11 }
對于延時函數我們可以采用各種方法實現。我們采用的STM32平臺和HAL庫則可以直接使用HAL_Delay()函數。于是我們可以調用初始化函數如下:
MS5803Initialization(&ms5803,MS580302BA,I2C,0xEC,SendCommandToMS5803,GetDatasFromMS5803,NULL,HAL_Delay);
這里我們使用的型號是MS580302BA,采用I2C接口,地址為0xEC。因為使用的是I2C接口所以片選輸入NULL。
3.2 、基于對象進行操作
我們定義了對象變量并使用初始化函數給其作了初始化。接著我們就來考慮操作這一對象獲取我們想要的數據。我們在驅動中已經將獲取數據并轉換為轉換值的比例值,接下來我們使用這一驅動開發我們的應用實例。
1 /*獲取壓力變送器數據*/
2 void GetPressureSenserData(void)
3 {
4 float pressure=0.0;
5 float temperature=0.0;
6
7 GetMS5803ConversionValue(&ms5803,MS5803_OSR4096,MS5803_OSR4096);
8
9 pressure=ms5803.pressure;
10 temperature=ms5803.temperature;
11 }
4 、應用總結
在本篇中,我們實現了MS5803壓力傳感器的驅動程序,并基于驅動程序開發了簡單的驗證應用。我們也多次在項目中使用MS5803壓力傳感器,使用的就是這一套驅動程序,應用的效果非常不錯。
在使用I2C接口時,引腳CSB應連接到VDD或GND。因為MS5803的地址位僅有1位是可以通過CSB設定的,所以一條I2C總線最多只能掛2個MS5803模塊。當CSB接VDD時地址最低位為1;當CSB接GND時地址最低位為0。
在使用驅動時需注意,采用SPI接口的器件需要考慮片選操作的問題。如果片選信號是通過硬件電路來實現的,我們在初始化時給其傳遞NULL值。如果是軟件操作片選則傳遞我們編寫的片選操作函數。
源碼下載:https://github.com/foxclever/ExPeriphDriver
評論
查看更多