很多時(shí)候我們需要檢測(cè)被控對(duì)象的絕對(duì)壓力,而且在我們的多款產(chǎn)品中也有這樣的需求。當(dāng)然檢測(cè)絕對(duì)壓力的傳感器有很多,我們經(jīng)常使用MS5803來(lái)實(shí)現(xiàn)壓力檢測(cè)。本篇中我們將設(shè)計(jì)并實(shí)現(xiàn)MS5803系列壓力傳感器的驅(qū)動(dòng)。
1 、功能概述
MS5803系列產(chǎn)品包含壓阻傳感器和傳感器接口IC。MS5803系列壓力傳感器的主要功能是將未補(bǔ)償?shù)膲鹤鑹毫鞲衅鞯?a href="http://ttokpm.com/analog/" target="_blank">模擬輸出電壓24位數(shù)字值,以及提供一個(gè)24位數(shù)字值的溫度傳感器。
1.1 、硬件描述
MS5803系列壓力傳感器是新一代高分辨率高度計(jì)傳感器,它是為高度計(jì)和高度分辨率為20厘米的變壓計(jì)優(yōu)化。能夠同時(shí)獲得壓力值和溫度值,其中壓力測(cè)量范圍為10-1100mbar,溫度的測(cè)量范圍是-40-85攝氏度。MS5803系列壓力傳感器各引腳功能如下:
MS5803系列壓力傳感器具有SPI和I2C總線接口。MS5803系列壓力傳感器模塊包括一個(gè)高線性壓力傳感器和一個(gè)超低功率24位ΔΣADC與內(nèi)部工廠校準(zhǔn)系數(shù)。它提供一個(gè)精確的數(shù)字24位壓力和溫度值和不同的操作模式。傳感器內(nèi)部結(jié)構(gòu)圖如下:
我們使用MS5803系列壓力傳感器時(shí),需要做的就是選擇不同的通訊接口與其實(shí)現(xiàn)數(shù)字通訊的過(guò)程。
1.2 、通訊接口
MS5803系列壓力傳感器支持SPI和I2C總線通訊,通過(guò)協(xié)議選擇引腳PS來(lái)決定采用什么接口。將協(xié)議選擇引腳PS拉低,選擇SPI協(xié)議,將PS拉高,激活I(lǐng)2C總線協(xié)議。在不同協(xié)議下相關(guān)引腳的定義如下:
在不同協(xié)議下各引腳所支持的參數(shù)是有些許差異的。在SPI接口模式下時(shí)鐘引腳最大可達(dá)20MHz;在I2C接口模式下時(shí)鐘引腳最大可達(dá)200kHz。具體的參數(shù)如下圖:
在SPI模式下,SCLK作為外部輸入時(shí)鐘,SDI作為串行數(shù)據(jù)輸入,支持Mode0和Mode3的時(shí)鐘極性和相位。傳感器的響應(yīng)數(shù)據(jù)輸出為SDO引腳,片選信號(hào)為CSB引腳。SPI模式下接線示意圖如下:
在I2C模式下,SCLK為外部串行時(shí)鐘輸入,SDA為串行數(shù)據(jù)通訊。CSB引腳作為地址選擇,可以鏈接到VDD或者GND,這也意味著MS5803可以在一條I2C總線接兩個(gè)設(shè)備。在CSP接高電平時(shí),地址為0x76(1110110 b),而CSB接低電平時(shí),地址為0x77 (1110111 b)這個(gè)地址是高七位,最后以為有讀寫(xiě)命令來(lái)決定。實(shí)現(xiàn)寫(xiě)命令時(shí),最后一位為0,實(shí)現(xiàn)讀命令時(shí),最后一位為1。I2C模式下接線圖如下:
1.3 、數(shù)據(jù)訪問(wèn)
無(wú)論是在SPI模式還是在I2C模式,MS5803系列壓力傳感器都是通過(guò)5類命令實(shí)現(xiàn)的。這些命令包括:復(fù)位、讀取出廠校準(zhǔn)值、數(shù)據(jù)1轉(zhuǎn)換(壓力值數(shù)據(jù))、數(shù)據(jù)2轉(zhuǎn)換(溫度值數(shù)據(jù))和讀取ADC的轉(zhuǎn)換結(jié)果。具體命令定義如下:
從上圖,我們知道每個(gè)命令的大小為1字節(jié)(8位)。需要說(shuō)明的是,ADC讀取指令后,設(shè)備將返回24位結(jié)果,PROM讀取則是16位結(jié)果。PROM的地址使用Ad2、Ad1和Ad0位嵌入到PROM讀命令中。關(guān)于這128bit PROM的地址分配如下圖所示:
MS5803系列壓力傳感器每個(gè)模塊都是在兩個(gè)溫度和兩個(gè)壓力下單獨(dú)校準(zhǔn)的。這6個(gè)必要的系數(shù)來(lái)補(bǔ)償工藝變化和溫度變化,就存儲(chǔ)在每個(gè)模塊的128bit PROM中。這些6個(gè)系數(shù)必須由軟件讀取,并在程序中使用,將D1和D2轉(zhuǎn)換成補(bǔ)償?shù)膲毫蜏囟戎怠?/p>
2 、驅(qū)動(dòng)設(shè)計(jì)與實(shí)現(xiàn)
我們已經(jīng)了解了MS5803壓力傳感器基本操作。在此基礎(chǔ)上,我們將設(shè)計(jì)并實(shí)現(xiàn)MS5803壓力傳感器的驅(qū)動(dòng)程序。
2.1 、對(duì)象定義
在使用一個(gè)對(duì)象之前我們需要獲得一個(gè)對(duì)象。同樣的我們想要MS5803壓力傳感器就需要先定義MS5803壓力傳感器的對(duì)象。
2.1.1 、對(duì)象的抽象
我們要得到MS5803壓力傳感器對(duì)象,需要先分析其基本特性。一般來(lái)說(shuō),一個(gè)對(duì)象至少包含兩方面的特性:屬性與操作。接下來(lái)我們就來(lái)從這兩個(gè)方面思考一下MS5803壓力傳感器的對(duì)象。
先來(lái)考慮屬性,作為屬性肯定是用于標(biāo)識(shí)或記錄對(duì)象特征的東西。我們來(lái)考慮MS5803壓力傳感器對(duì)象屬性。首先MS5803有一系列的產(chǎn)品,不同產(chǎn)品線的補(bǔ)償計(jì)算方式有很大差異,所以我們將產(chǎn)品類型作為屬性以區(qū)別不同的產(chǎn)品。MS5803擁有SPI和I2C兩種通訊方式可供選擇,為了確定具體設(shè)備所采用的接口,我們將其作為對(duì)象的屬性以記錄其使用的接口方式。在采用I2C接口模式時(shí),每臺(tái)設(shè)備都有一個(gè)設(shè)備地址,這個(gè)地址用于區(qū)分同一總線上不同的設(shè)備,所以我們將地址作為對(duì)象的屬性。而對(duì)于MS5803每臺(tái)都有6個(gè)校準(zhǔn)參數(shù),這些參數(shù)在測(cè)量是需要用到,所以我們需要保存這些參數(shù),所以我們將其作為屬性。
接著我們還需要考慮MS5803壓力傳感器對(duì)象的操作問(wèn)題。無(wú)論是使用SPI接口還是使用I2C接口我們都需要向MS5803寫(xiě)命令和從MS5803讀數(shù)據(jù),而讀寫(xiě)行為都與所處的硬件平臺(tái)相關(guān),所以我們將讀和寫(xiě)數(shù)據(jù)作為對(duì)象的操作。為控制時(shí)序,我們需要延時(shí)操作,但延時(shí)操作也與具體的軟硬件平臺(tái)相關(guān),所以我們將其作為對(duì)象的操作。在使用SPI接口方式時(shí),若使用軟件控制片選信號(hào),則會(huì)依賴于硬件,我們將針對(duì)片選信號(hào)的操作作為對(duì)象的操作。
根據(jù)上述我們對(duì)MS5803壓力傳感器的分析,我們可以定義MS5803壓力傳感器的對(duì)象類型如下:
1 typedef struct MS5803Object {
2 uint8_t devAddress; //設(shè)備地址
3 MS5803PortType port; //通訊端口協(xié)議
4 MS5803ModelType model; //設(shè)備的類型
5 uint16_t caliData[6]; //校準(zhǔn)數(shù)據(jù)
6 float temperature;
7 float pressure;
8 void (*Write)(struct MS5803Object *ms,uint8_t command);//向MS5803寫(xiě)信息
9 void (*Read)(struct MS5803Object *ms,uint8_t *rData,uint16_t rSize);//從MS5803讀數(shù)據(jù)
10 void (*ChipSelcet)(MS5803CSType en); //片選信號(hào),用于SPI接口
11 void (*Delayms)(volatile uint32_t nTime); //毫秒秒延時(shí)函數(shù)
12 }MS5803ObjectType;
2.1.2 、對(duì)象初始化
我們知道,一個(gè)對(duì)象僅作聲明是不能使用的,我們需要先對(duì)其進(jìn)行初始化,所以這里我們來(lái)考慮MS5803壓力傳感器對(duì)象的初始化函數(shù)。一般來(lái)說(shuō),初始化函數(shù)需要處理幾個(gè)方面的問(wèn)題。一是檢查輸入?yún)?shù)是否合理;二是為對(duì)象的屬性賦初值;三是對(duì)對(duì)象作必要的初始化配置。據(jù)此我們?cè)O(shè)計(jì)MS5803壓力傳感器對(duì)象的初始化函數(shù)如下:
1 /* MS5803對(duì)象初始化 */
2 void MS5803Initialization(MS5803ObjectType *ms, //MS5803對(duì)象
3 MS5803ModelType model, //類型
4 MS5803PortType port, //通訊端口
5 uint8_t address, //I2C設(shè)備地址
6 MS5803Write write, //寫(xiě)數(shù)據(jù)函數(shù)
7 MS5803Read read, //讀數(shù)據(jù)函數(shù)
8 MS5803ChipSelcet cs, //SPI片選信號(hào)
9 MS5803Delayms delayms //毫秒延時(shí)
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 、對(duì)象操作
我們已經(jīng)完成了MS5803壓力傳感器對(duì)象類型的定義和對(duì)象初始化函數(shù)的設(shè)計(jì)。但我們的主要目標(biāo)是獲取對(duì)象的信息,接下來(lái)我們還要實(shí)現(xiàn)面向MS5803壓力傳感器的各類操作。
對(duì)MS5803壓力傳感器的其實(shí)就是基于前面我們所說(shuō)的命令來(lái)實(shí)現(xiàn)的。根據(jù)這些命令的作用,我們可以大致分為三個(gè)方面:設(shè)備復(fù)位、ADC轉(zhuǎn)換配置及數(shù)據(jù)獲取、校準(zhǔn)系數(shù)的獲取。下面我么五年就從這三個(gè)方面來(lái)看一看MS5803壓力傳感器的操作。
2.2.1 、復(fù)位操作
復(fù)位操作可以在電源供電后的任意時(shí)刻發(fā)送,但一般要求在開(kāi)機(jī)后首先發(fā)送復(fù)位程序。這樣可以確保校準(zhǔn)PROM加載到內(nèi)部寄存器。當(dāng)然復(fù)位操作也可以用來(lái)重置設(shè)備ROM以便從我們未知的情況中恢復(fù)。
在使用SPI通訊接口時(shí),無(wú)論是模式0還是模式3其操作是一樣的,SPI方式下的時(shí)序圖如下:
在I2C通訊接口時(shí),有時(shí)候通訊可能會(huì)出現(xiàn)SDA被未定義的狀態(tài)阻塞的時(shí)候,可以通過(guò)復(fù)位操作來(lái)恢復(fù)通訊。I2C方式下的時(shí)序圖如下:
1 /*復(fù)位MS5803操作*/
2 void ResetForMS5803(MS5803ObjectType *ms)
3 {
4 uint8_t command=COMMAND_RESET;
5 /*下發(fā)復(fù)位命令*/
6 ms->Write(ms,command);
7
8 ms->Delayms(3);
9 }
2.2.2 、讀取校準(zhǔn)值
校準(zhǔn)值是出廠時(shí)廠家校準(zhǔn)的各種系數(shù),每臺(tái)設(shè)備都有差異,但每臺(tái)設(shè)備是固定不變的,只需要一次讀取就可以了,共有6個(gè)系數(shù),均為16為整數(shù)。
用戶復(fù)位后,執(zhí)行一次PROM的read命令,讀取校準(zhǔn)PROM的內(nèi)容,計(jì)算校準(zhǔn)系數(shù)。關(guān)于PROM我們前面已經(jīng)描述過(guò)了,總共有8個(gè)地址,地址0包含工廠數(shù)據(jù)和設(shè)置,地址1-6校準(zhǔn)系數(shù),地址7包含串行代碼和CRC。
在SPI接口通訊模式下,我們發(fā)送都對(duì)應(yīng)地址的命令,等待接收數(shù)據(jù)即可。命令為8位,返回?cái)?shù)據(jù)為16位,時(shí)序圖如下:
在I2C接口通訊模式下,PROM讀命令由兩部分組成。第一個(gè)命令將系統(tǒng)設(shè)置為PROM讀模式。第二部分從系統(tǒng)中獲取數(shù)據(jù)。首先發(fā)送讀系數(shù)的命令,然后讀取就可以了,每次讀取1個(gè),分6次讀取。I2C模式下的時(shí)序圖如下所示:
1 /*讀取MS5803內(nèi)存寄存器的數(shù)據(jù)*/
2 static uint16_t ReadPromFromMS5803(MS5803ObjectType *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ì)算出最終的物理值。
對(duì)于配置轉(zhuǎn)換及讀取轉(zhuǎn)換的結(jié)果,在SPI接口模式下,按兩步實(shí)現(xiàn):先設(shè)置轉(zhuǎn)換精度,等待轉(zhuǎn)換結(jié)束再讀取數(shù)據(jù)。具體的時(shí)序圖如下:
對(duì)于配置轉(zhuǎn)換及讀取轉(zhuǎn)換的結(jié)果,在I2C接口模式下,按三步實(shí)現(xiàn):先設(shè)置轉(zhuǎn)換精度,等待轉(zhuǎn)換結(jié)束發(fā)送讀ADC命令,最后讀取數(shù)據(jù)。具體的時(shí)序圖如下:
1 /*讀取MS5803ADC的轉(zhuǎn)換值*/
2 static uint32_t ReadConversionFromMS5803(MS5803ObjectType *ms,uint8_t command)
3 {
4 /*下發(fā)轉(zhuǎn)化對(duì)象及精度配置命令*/
5 ms->Write(ms,command);
6
7 ms->Delayms(10);
8
9 /*下發(fā)讀取ADC的命令*/
10 ms->Write(ms,COMMAND_ADC_READ);
11
12 if(ms->port==I2C)
13 {
14 ms->Delayms(10);
15 }
16
17 /*接收讀取的ADC轉(zhuǎn)換結(jié)果*/
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 、驅(qū)動(dòng)的使用
我們已經(jīng)設(shè)計(jì)并實(shí)現(xiàn)了MS5803壓力傳感器的驅(qū)動(dòng)程序,這個(gè)驅(qū)動(dòng)程序是否符合要求還需要驗(yàn)證。這一節(jié)我們就來(lái)設(shè)計(jì)一個(gè)簡(jiǎn)單的應(yīng)用驗(yàn)證這一驅(qū)動(dòng)程序。
3.1 、聲明并初始化對(duì)象
使用基于對(duì)象的操作我們需要先得到這個(gè)對(duì)象,所以我們先要使用前面定義的MS5803壓力傳感器對(duì)象類型聲明一個(gè)MS5803壓力傳感器對(duì)象變量,具體操作格式如下:
MS5803ObjectType ms5803;
聲明了這個(gè)對(duì)象變量并不能立即使用,我們還需要使用驅(qū)動(dòng)中定義的初始化函數(shù)對(duì)這個(gè)變量進(jìn)行初始化。這個(gè)初始化函數(shù)所需要的輸入?yún)?shù)如下:
MS5803ObjectType *ms,MS5803對(duì)象
MS5803ModelType model,類型
MS5803PortType port,通訊端口
uint8_t address,I2C設(shè)備地址
MS5803Write write,寫(xiě)數(shù)據(jù)函數(shù)
MS5803Read read,讀數(shù)據(jù)函數(shù)
MS5803ChipSelcet cs,SPI片選信號(hào)
MS5803Delayms delayms,毫秒延時(shí)
對(duì)于這些參數(shù),對(duì)象變量我們已經(jīng)定義了。設(shè)備類型和通訊端口都是枚舉,我們只需要根據(jù)實(shí)際的配置情況選擇就可以了。設(shè)備地址則在采用I2C通訊時(shí),根據(jù)實(shí)際輸入。我們主要需要關(guān)注的是定義幾個(gè)函數(shù),并將函數(shù)指針作為參數(shù)。這幾個(gè)函數(shù)的類型如下:
1 /*向MS5803下發(fā)指令,指令格式均為1個(gè)字節(jié)*/
2 typedef void (*MS5803Write)(MS5803ObjectType *ms,uint8_t command);
3
4 /*從MS5803讀取多個(gè)字節(jié)數(shù)據(jù)的值*/
5 typedef void (*MS5803Read)(MS5803ObjectType *ms,uint8_t *rData,uint16_t rSize);
6
7 /*片選信號(hào),用于SPI接口*/
8 typedef void (*MS5803ChipSelcet)(MS5803CSType en);
9
10 /*毫秒秒延時(shí)函數(shù)*/
11 typedef void (*MS5803Delayms)(volatile uint32_t nTime);
對(duì)于這幾個(gè)函數(shù)我們根據(jù)樣式定義就可以了,具體的操作可能與使用的硬件平臺(tái)有關(guān)系。若采用的SPI接口則需注意片選操作,片選操作函數(shù)用于多設(shè)備需要軟件操作時(shí),如采用硬件片選可以傳入NULL即可。同樣如果采用的是I2C接口,則片選可以傳入NULL即可。具體函數(shù)定義如下:
1 /*通過(guò)I2C1接口下發(fā)命令*/
2 static void SendCommandToMS5803(MS5803ObjectType *ms,uint8_t command)
3 {
4 HAL_I2C_Master_Transmit(&ms5803hi2c,ms->devAddress,&command,1,1000);
5 }
6
7 /*通過(guò)I2C1接口讀取數(shù)據(jù)*/
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 }
對(duì)于延時(shí)函數(shù)我們可以采用各種方法實(shí)現(xiàn)。我們采用的STM32平臺(tái)和HAL庫(kù)則可以直接使用HAL_Delay()函數(shù)。于是我們可以調(diào)用初始化函數(shù)如下:
MS5803Initialization(&ms5803,MS580302BA,I2C,0xEC,SendCommandToMS5803,GetDatasFromMS5803,NULL,HAL_Delay);
這里我們使用的型號(hào)是MS580302BA,采用I2C接口,地址為0xEC。因?yàn)槭褂玫氖荌2C接口所以片選輸入NULL。
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)開(kāi)發(fā)我們的應(yīng)用實(shí)例。
1 /*獲取壓力變送器數(shù)據(jù)*/
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 、應(yīng)用總結(jié)
在本篇中,我們實(shí)現(xiàn)了MS5803壓力傳感器的驅(qū)動(dòng)程序,并基于驅(qū)動(dòng)程序開(kāi)發(fā)了簡(jiǎn)單的驗(yàn)證應(yīng)用。我們也多次在項(xiàng)目中使用MS5803壓力傳感器,使用的就是這一套驅(qū)動(dòng)程序,應(yīng)用的效果非常不錯(cuò)。
在使用I2C接口時(shí),引腳CSB應(yīng)連接到VDD或GND。因?yàn)镸S5803的地址位僅有1位是可以通過(guò)CSB設(shè)定的,所以一條I2C總線最多只能掛2個(gè)MS5803模塊。當(dāng)CSB接VDD時(shí)地址最低位為1;當(dāng)CSB接GND時(shí)地址最低位為0。
在使用驅(qū)動(dòng)時(shí)需注意,采用SPI接口的器件需要考慮片選操作的問(wèn)題。如果片選信號(hào)是通過(guò)硬件電路來(lái)實(shí)現(xiàn)的,我們?cè)诔跏蓟瘯r(shí)給其傳遞NULL值。如果是軟件操作片選則傳遞我們編寫(xiě)的片選操作函數(shù)。
源碼下載:https://github.com/foxclever/ExPeriphDriver
評(píng)論
查看更多