很多時候我們需要檢測流量和壓力這些參數(shù),比如我們要檢測大氣壓,或者通過測量差壓來獲得輸送流體的流量等,都需要用到壓力傳感器。這一篇我們就來討論MS4515DO壓力傳感器的數(shù)據(jù)獲取。
1、功能概述
??MS4515DO是TE公司推出的一款基于PCB安裝的小型陶瓷基壓力傳感器。該傳感器采用最新的CMOS傳感器調(diào)節(jié)電路,制造出一種低成本、高性能的數(shù)字輸出壓力(14bit)和溫度(11bit)傳感器,以滿足OEM客戶最嚴(yán)格的要求。
??MS4515DO完全校準(zhǔn)和溫度補(bǔ)償,總誤差帶在補(bǔ)償范圍內(nèi)小于1.0%。該傳感器采用直流3.3V或5.0V單電源供電模式,對外接口采用I2C總線或三線SPI的模式。其結(jié)構(gòu)圖如下:
??MS4515DO和MS4525DO擁有相同的功能和模式,區(qū)別只在于輸出的物理量單位不同而已。它們都擁有可以檢測差壓和絕壓的型號,但操作是完全一樣的,所以本篇的討論事實(shí)上適用于相關(guān)系列的全部型號的應(yīng)用。
1.1、MS4515DO的I2C地址
??作為I2C接口的設(shè)備都會有一個設(shè)備地址,MS4515DO壓力傳感器也不例外。而MS4515DO和MS4525DO系列傳感器的I2C地址在出廠時已特定寫入,并根據(jù)型號中的字母來指示其地址設(shè)定。具體如下:
??預(yù)設(shè)的設(shè)備地址是7位的,不包含讀寫位的指示。我們使用時需要將其左移一位并根據(jù)讀寫操作來定義讀寫位,0為寫,1為讀。
1.2、數(shù)據(jù)輸出格式
??在I2C通訊模式下,MS4515DO和MS4525DO傳感器有四個I2C讀取命令,分別為:Read_MR、Read_DF2、Read_DF3和Read_DF4。這四個命令可以獲取不同的數(shù)據(jù),這些命令的具體報(bào)文格式定義如下圖:
??所以我們想要獲取MS4515DO和MS4525DO傳感器的數(shù)據(jù)就需要通過上述命令來實(shí)現(xiàn)。從上述的命令報(bào)文格式可以看出,這些命令在本質(zhì)上是沒有差別的,都多少數(shù)據(jù)完全由主機(jī)來控制,也就是我們開發(fā)的驅(qū)動程序來控制。事實(shí)上,我們只需要考慮Read_DF4這個命令就可以涵蓋所有想要的數(shù)據(jù)。
??我們需要注意的是,上述的報(bào)文中有兩位存儲的是狀態(tài)信息,該狀態(tài)信息表示獲取的數(shù)據(jù)是最新的數(shù)據(jù)還是舊數(shù)據(jù)或者錯誤報(bào)警。通過判斷這個數(shù)據(jù)可以決定我們在數(shù)據(jù)解析時如何處理相應(yīng)的報(bào)文。
2、驅(qū)動設(shè)計(jì)與實(shí)現(xiàn)
??我們已經(jīng)了解了MS4515DO和MS4525DO傳感器的結(jié)構(gòu)、接口方式、設(shè)備地址以及數(shù)據(jù)輸出格式。接下來我們就可以考慮如何實(shí)現(xiàn)MS4515DO和MS4525DO傳感器的驅(qū)動程序了。
2.1、對象定義
??我們依然還是先來考慮MS4515DO和MS4525DO傳感器的對象定義。我們定義一個對象無非考慮屬性和操作兩個部分。
??首先我們來考慮MS4515DO和MS4525DO傳感器對象的屬性。首先MS4515DO和MS4525DO傳感器采用I2C接口通訊,所以每臺都有一個設(shè)備地址。這個地址標(biāo)識了I2C總線上該設(shè)備的唯一性,所以我們將設(shè)備地址作為MS4515DO和MS4525DO傳感器對象的一個屬性。對于MS4515DO和MS4525DO傳感器來說存在多種類型,而不同的類型對應(yīng)不同的數(shù)據(jù)計(jì)算方式,所以針對某一具體實(shí)例,我們需要記錄它的類型,所以我們?yōu)槠涠x一個類型屬性。我們在計(jì)算壓力值時,不同的量程最后得到的壓力值與測量量程有關(guān),所以我們還需要記錄實(shí)例的量程上下限,所以將這兩個數(shù)據(jù)也定義為對象的屬性。為了操作方便我們將最終得到的溫度和壓力數(shù)據(jù)也都作為對象的屬性。
??從前面的描述中,我們知道MS4515DO和MS4525DO傳感器的數(shù)據(jù)輸出格式是固定的,這為我們解析這一數(shù)據(jù)提供了思路。我們將讀出的4個字節(jié)與我們想要得到的數(shù)據(jù)組成聯(lián)合體,利用結(jié)構(gòu)體和聯(lián)合體在內(nèi)存中的關(guān)系可以方便的解析數(shù)據(jù)對象,如下圖所示:
??這些個數(shù)據(jù)即是我們想要的先要得到的,同時他們也記錄了MS4515DO和MS4525DO傳感器對象當(dāng)前的狀態(tài),所以我們將其也作為對象的屬性。
??其次我們來考慮MS4515DO和MS4525DO傳感器對象的操作。我們需要將對象的哪些行為定義為操作呢?一般的我們考慮那些不能直接實(shí)現(xiàn),而是要依賴特定的軟硬件平臺才能實(shí)現(xiàn)的對象行為。我們需要向MS4515DO和MS4525DO傳感器發(fā)送命令,也需要從傳感器獲取對象,而無論讀還是寫都是依賴于具體的軟硬件平臺才能去定的,所以我們將向傳感器寫信息和從傳感器讀信息作為對象的2個操作。為了控制時序,我們一般需要演示處理函數(shù),而演示處理函數(shù)的實(shí)現(xiàn)也是依賴于具體的軟硬件平臺的,所以我們將延時函數(shù)定義為對象的一個操作。
??我們分析了MS4515DO和MS4525DO傳感器對象可能的屬性和操作。根據(jù)前述的分析,我們可以定義MS4515DO和MS4525DO傳感器對象的類型如下:
/* 定義MS45x5DO對象類型 */typedef struct MS45x5DOObject {
uint8_t devAddress; //設(shè)備地址
union {
struct {
uint16_t pressure:14; uint16_t status:2; uint16_t insignificance:5; uint16_t temperature:11;
}pData; uint8_t rData[4];
}msData; //讀出的數(shù)值
MS45x5DOType type; //MS4515DO的類型
float pUpperRange; //壓力量程上限
float pLowerRange; //壓力量程下限
float fTemperature; //計(jì)算的溫度值
float fPressure; //計(jì)算的壓力值
void (*Write)(struct MS45x5DOObject *ms,uint8_t *wData,uint16_t wSize); //向MS45x5DO寫數(shù)據(jù)
void (*Read)(struct MS45x5DOObject *ms,uint8_t *rData,uint16_t rSize); //從MS45x5DO讀數(shù)據(jù)
void (*Delayms)(volatile uint32_t nTime); //毫秒秒延時函數(shù)}MS45x5DOObjectType;
??我們定義了MS4515DO和MS4525DO傳感器對象的類型,使用該類型我們可以定義我們想要的對象變量,但對象變量需要進(jìn)行必要的配置才能真正的實(shí)例化,這個過程我們將其稱之為對象的初始化。
/* 初始化MS45x5DO對象 */void MS45x5DOInitialization(MS45x5DOObjectType *ms, //MS5837對象
uint8_t devAddress, //設(shè)備地址
MS45x5DOType type, //MS4515DO的類型
float pMax, //壓力量程上限
float pMin, //壓力量程下限
MS45x5DOWrite write, //向MS45x5DO寫數(shù)據(jù)函數(shù)指針
MS45x5DORead read, //從MS45x5DO讀數(shù)據(jù)函數(shù)指針
MS45x5DODelayms delayms //毫秒延時函數(shù)指針
){ if((ms==NULL)||(write==NULL)||(read==NULL)||(delayms==NULL))
{ return;
}
ms->Write=write;
ms->Read=read;
ms->Delayms=delayms;
if((devAddress==0x28)||(devAddress==0x36)||(devAddress==0x46)||((0x48<=devAddress)&&(devAddress<=0x51)))
{
ms->devAddress=(devAddress<<1);
} else if((devAddress==0x50)||(devAddress==0x6C)||(devAddress==0x8C)||((0x48<=(devAddress/2))&&((devAddress/2)<=0x51)))
{
ms->devAddress=devAddress;
} else
{
ms->devAddress=0x00;
}
ms->type=type;
ms->fPressure=0.0;
ms->fTemperature=0.0;
ms->msData.rData[0]=0;
ms->msData.rData[1]=0;
ms->msData.rData[2]=0;
ms->msData.rData[3]=0;
if((fabs(pMax)<=0.0000001)&&(fabs(pMin)<=0.0000001))
{
ms->pUpperRange=100.0;
ms->pLowerRange=0.0;
} else
{
ms->pUpperRange=pMax;
ms->pLowerRange=pMin;
}
}
2.2、對象操作
??我們已經(jīng)可以得到一個對象變量并將它實(shí)例化,我們還需要考慮它的操作問題。對于MS4515DO和MS4525DO傳感器來說其操作比較簡單,最主要的操作包括數(shù)據(jù)獲取和地址設(shè)定。
2.2.1、獲取數(shù)據(jù)
??對于我們來說獲取MS4515DO和MS4525DO傳感器的測量數(shù)據(jù)是我們的主要目的。我們可以從MS4515DO和MS4525DO傳感器獲取壓力和溫度數(shù)據(jù),其測量范圍與輸出數(shù)據(jù)的對應(yīng)關(guān)系如下圖所示:
??根據(jù)上表中的數(shù)據(jù)對應(yīng)關(guān)系,我們可以編寫獲取MS4515DO和MS4525DO傳感器的數(shù)據(jù)并解析的函數(shù)。
/*獲取轉(zhuǎn)換值,包括溫度和壓力*/void GetMS45x5DOConversionValue(MS45x5DOObjectType *ms){ uint8_t rData[4]={0,0,0,0}; float maxCount=16383; float minCount=0;
if(ms->type==MS45x5DO_TypeA)
{
maxCount=13106;
minCount=1638;
} else
{
maxCount=14746;
minCount=819;
}
ms->Read(ms,rData,4);
ms->msData.rData[0]=rData[1];
ms->msData.rData[1]=rData[0];
ms->msData.rData[2]=rData[3];
ms->msData.rData[3]=rData[2];
if(ms->msData.pData.status!=MS45x5DO_Fault)
{
ms->fPressure=(((float)ms->msData.pData.pressure-minCount)/maxCount)*(ms->pUpperRange-ms->pLowerRange)+ms->pLowerRange;
ms->fTemperature=((float)ms->msData.pData.temperature/2047.0)*200.0-50.0;
}
}
2.2.2、地址設(shè)置
??關(guān)于MS4515DO和MS4525DO傳感器,在出廠時已經(jīng)設(shè)定了設(shè)備地址并在型號編碼中給予指示。但在一些特殊情形下我們可能需要修改它的設(shè)備地址,這就需要用到MS4515DO和MS4525DO傳感器的地址修改操作。
/*修改MS45x5DO的設(shè)備地址*/void ModifyMS45x5DODecAddress(MS45x5DOObjectType *ms,uint8_t newAddress){ uint8_t eepromByte[3]; uint16_t eepromTemp=0x00;
//第1步、進(jìn)入命令模式
eepromByte[0]=0xA0;
eepromByte[1]=0x00;
eepromByte[2]=0x00;
ms->Write(ms,eepromByte,3);
//第2步、發(fā)送讀EEPROM命令
eepromByte[0]=0x02;
eepromByte[1]=0x00;
eepromByte[2]=0x00;
ms->Write(ms,eepromByte,3);
//第3步、獲取EEPROM的值
ms->Read(ms,eepromByte,3);
//第4步、修改為新地址
if(eepromByte[0]==0x5A)
{
eepromTemp=(eepromByte[1]<<8)+eepromByte[2];
eepromTemp=(eepromTemp&0xE007)+0xC00+(newAddress<<3);
eepromByte[1]=(uint8_t)((eepromTemp&0xFF00)>>8);
eepromByte[1]=(uint8_t)(eepromTemp&0x00FF);
} else
{ return;
}
//第5步、將新地址寫入EEPROM
eepromByte[0]=0x02;
ms->Write(ms,eepromByte,3);
//第6步、退出命令模式
eepromByte[0]=0x80;
eepromByte[1]=0x00;
eepromByte[2]=0x00;
ms->Write(ms,eepromByte,3);
}
3、驅(qū)動的使用
??我們已經(jīng)設(shè)計(jì)并實(shí)現(xiàn)了MS4515DO和MS4525DO壓力傳感器的驅(qū)動程序。接下來我們將簡單的說明如何使用這一驅(qū)動,并設(shè)計(jì)一個簡單的示例驗(yàn)證這一驅(qū)動程序的正確性。
3.1、聲明并初始化對象
??我們是基于對象設(shè)計(jì)的MS4515DO和MS4525DO壓力傳感器的驅(qū)動程序,所以在使用驅(qū)動時,我們需要先聲明一個對象變量,然后基于該對象變量來實(shí)現(xiàn)具體的對象操作。我們先聲明對象如下:
MS45x5DOObjectType msDP;
??聲明了這個對象變量之后,我們還需要使用初始化函數(shù)對其進(jìn)行初始化方可使用。這一初始化函數(shù)擁有8個參數(shù):
MS45x5DOObjectType *ms, //MS5837對象uint8_t devAddress, //設(shè)備地址MS45x5DOType type, //MS4515DO的類型float pMax, //壓力量程上限float pMin, //壓力量程下限MS45x5DOWrite write, //向MS45x5DO寫數(shù)據(jù)函數(shù)指針MS45x5DORead read, //從MS45x5DO讀數(shù)據(jù)函數(shù)指針MS45x5DODelayms delayms //毫秒延時函數(shù)指針
??第一個參數(shù)正是我們要初始化的對象變量。第二個參數(shù)為我們所要操作的MS4515DO對象的設(shè)備地址。第三個參數(shù)是MS4515DO對象的具體類型,根據(jù)實(shí)際設(shè)備選擇枚舉即可。第四和第五個參數(shù)是該對象的物理量量程,根據(jù)具體對象而定。后面三個參數(shù)是實(shí)現(xiàn)對象操作的函數(shù)指針。這三個函數(shù)指針需要我們根據(jù)具體的軟硬件平臺來實(shí)現(xiàn)。它們的原型如下:
/*向MS45x5DO下發(fā)指令,指令格式均為1個字節(jié)*/typedef void (*MS45x5DOWrite)(struct MS45x5DOObject *ms,uint8_t *wData,uint16_t wSize);/*從MS45x5DO讀取多個字節(jié)數(shù)據(jù)的值*/typedef void (*MS45x5DORead)(struct MS45x5DOObject *ms,uint8_t *rData,uint16_t rSize);/*毫秒秒延時函數(shù)*/typedef void (*MS45x5DODelayms)(volatile uint32_t nTime);
??我們根據(jù)函數(shù)原型定義,在具體的實(shí)現(xiàn)平臺上實(shí)現(xiàn)它們,如我們在STM32平臺上可以實(shí)現(xiàn)如下:
/ 向MS45x5DO下發(fā)指令,指令格式均為1個字節(jié) /
static void WriteToDP(MS45x5DOObjectType *ms,uint8_t *wData,uint16_t wSize)
{
HAL_I2C_Master_Transmit(&hi2c2,ms->devAddress,wData,wSize,1000);
}
/* 從MS45x5DO讀取多個字節(jié)數(shù)據(jù)的值* /
static void ReadFromDP(MS45x5DOObjectType *ms,uint8_t *rData,uint16_t rSize)
{
HAL_I2C_Master_Receive(&hi2c2,ms->devAddress,rData, rSize, 1000);
}
  延時函數(shù)我們可以直接使用HAL庫中的HAL_Delay也可以自己編寫,在HAL庫中HAL_Delay是一個弱化定義的函數(shù),我們可以重寫這一函數(shù)來實(shí)現(xiàn)不同的應(yīng)用需求。到這里我們就可以使用對象初始化函數(shù)來初始化前面聲明的對象變量了。具體如下:
```C++MS45x5DOInitialization(&msDP, //MS5837對象
0x28, //設(shè)備地址
MS45x5DO_TypeA, //MS4515DO的類型
DPUpperRange, //壓力量程上限
DPLowerRange, //壓力量程下限
WriteToDP, //向MS45x5DO寫數(shù)據(jù)函數(shù)指針
ReadFromDP, //從MS45x5DO讀數(shù)據(jù)函數(shù)指針
HAL_Delay //毫秒延時函數(shù)指針
);
3.2、基于對象進(jìn)行操作
??完成了對象的初始化后,我們就可以基于對象來實(shí)現(xiàn)相應(yīng)的操作了。如我們使用驅(qū)動獲取msDP對象的差壓數(shù)據(jù)如下:
/*差壓數(shù)據(jù)獲取*/void GetFlowDPDatas(void){
GetMS45x5DOConversionValue(&msDP);
aPara.phyPara.dPressure =msDP.fPressure;
aPara.phyPara.dTemperature=msDP.fTemperature;
}
4、應(yīng)用總結(jié)
??我們設(shè)計(jì)并實(shí)現(xiàn)了MS4515DO和MS4525DO壓力傳感器對象的驅(qū)動程序,并基于驅(qū)動程序?qū)崿F(xiàn)了一個簡單的測試實(shí)例,獲得的結(jié)果如下:
??從上述兩圖中我們可以知道我們的驅(qū)動程序是正確的。事實(shí)上這一驅(qū)動已應(yīng)用于我們的流量測量設(shè)備中,實(shí)現(xiàn)的效果良好。
評論
查看更多