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