檢測(cè)流量數(shù)據(jù)的方法有很多種,這一次我們就是使用SDP800差壓傳感器來測(cè)量流量數(shù)據(jù)。 所以在這一篇中,我們將討論如何實(shí)現(xiàn)SDP800差壓傳感器的驅(qū)動(dòng),并使用它實(shí)現(xiàn)流量數(shù)據(jù)的檢測(cè)。
1、功能概述
??SDP800差壓傳感器系列是Sensirion為大批量應(yīng)用設(shè)計(jì)的數(shù)字壓差傳感器系列。 傳感器測(cè)量空氣和非腐蝕性氣體的壓力,具有極高的精度,沒有偏移。 該傳感器覆蓋的壓力范圍高達(dá)±500 Pa,并提供卓越的精度。 其結(jié)構(gòu)及引腳定義如下圖所示:
??SDP800系列差壓傳感器具有數(shù)字2線I2C接口,這使得它很容易直接連接到微處理器。 在I2C總線上每一臺(tái)設(shè)備都有一個(gè)地址,SDP800差壓傳感器不同的型號(hào)設(shè)備地址略有差異,具體如下表:
??雖然I2C接口基本有規(guī)范的通訊格式,但不同的設(shè)備在通訊報(bào)文的設(shè)置上還是有一下差異。 這里SDP800差壓傳感器其通訊報(bào)文的格式如下:
??在這一報(bào)文格式中,除了地址和數(shù)據(jù)還有一個(gè)16位的命令。 這些命令是廠商設(shè)定的,用于實(shí)現(xiàn)對(duì)SDP800差壓傳感器的各種操作。 這里我們只列出數(shù)據(jù)獲取的命令。
??對(duì)于SDP800差壓傳感器操作命令還有很多如配置、復(fù)位等我們?cè)诖瞬蛔髟斒觥?/p>
2、驅(qū)動(dòng)設(shè)計(jì)與實(shí)現(xiàn)
??我們已經(jīng)簡(jiǎn)單的描述了SDP800差壓傳感器的基本情況。 這一節(jié)我們將進(jìn)一步考慮SDP800差壓傳感器的驅(qū)動(dòng)設(shè)計(jì)與實(shí)現(xiàn)。
2.1、對(duì)象定義
??首先我們來考慮SDP800差壓傳感器的對(duì)象定義。 關(guān)于對(duì)象總是存在對(duì)象的屬性和操作,SDP800差壓傳感器對(duì)象我們也從這兩個(gè)方面來考慮。
??我們先來分析一下SDP800差壓傳感器對(duì)象的屬性問題。 SDP800差壓傳感器采用I2C接口,所以設(shè)備地址必不可少,而且每一個(gè)地址都唯一標(biāo)識(shí)一臺(tái)設(shè)備,所以我們將其設(shè)定為對(duì)象的屬性。 此外,SDP800差壓傳感器的產(chǎn)品編號(hào)和產(chǎn)品序列號(hào)都是唯一標(biāo)識(shí)SDP800差壓傳感器設(shè)備,所以我們也將其設(shè)定為屬性。 我們也希望記錄設(shè)備的狀態(tài)、測(cè)量的壓力、溫度以及差壓系數(shù)等。 這些兩標(biāo)識(shí)了SDP800差壓傳感器設(shè)備的狀態(tài),所以我們也將其作為對(duì)象的屬性。
??而對(duì)象的操作,SDP800差壓傳感器采用I2C接口,所以需要接收和發(fā)送數(shù)據(jù)、為了控制時(shí)序我們需要延時(shí)操作函數(shù)。 而這些函數(shù)的實(shí)現(xiàn)都依賴于具體的軟硬件平臺(tái),所以我們將它們?cè)O(shè)置為對(duì)象的操作,以便于通過回調(diào)函數(shù)來實(shí)現(xiàn)對(duì)象平臺(tái)無關(guān)性。 根據(jù)上述分析我們可以定義SDP800差壓傳感器的對(duì)象類型如下:
/* 定義SDP800對(duì)象類型 */
typedef struct SDP800Object{
uint8_t devAddress; //SDP800對(duì)象的地址
uint8_t status; //SDP800狀態(tài)信息
uint8_t pn[4]; //SDP800對(duì)象的產(chǎn)品號(hào)
uint8_t sn[8]; //SDP800對(duì)象的序列號(hào)
float dpressure; //差壓
float temperature; //溫度
float dpFactor; //差壓系數(shù)
void (*Delayms)(volatile uint32_t nTime); //延時(shí)操作指針
void (*Receive)(struct SDP800Object *sdp,uint8_t *rData,uint16_t rSize); //接收數(shù)據(jù)操作指針
void (*Transmit)(struct SDP800Object *sdp,uint8_t *tData,uint16_t tSize); //發(fā)送數(shù)據(jù)操作指針
}SDP800ObjectType;
??有了對(duì)象類型,我們就可以獲得對(duì)象變量,但對(duì)象變量需要初始化后才能進(jìn)行各種操作,所以我們需要實(shí)現(xiàn)一個(gè)SDP800差壓傳感器對(duì)象變量初始化的函數(shù)。
/*SDP800對(duì)象初始化配置*/
SDP800ErrorType Sdp800Initialization(SDP800ObjectType *sdp, //SDP800對(duì)象
uint8_t i2cAddress, //設(shè)備地址
SDP800Receive recieve, //接收函數(shù)指針
SDP800Transmit transmit, //發(fā)送函數(shù)指針
SDP800Delayms delayms //毫秒演示函數(shù)
)
{
SDP800ErrorType error=SDP800_ERROR_NONE;
if((sdp==NULL)||(recieve==NULL)||(transmit==NULL)||(delayms==NULL))
{
return SDP800_ERROR_IVALID_PARAMETER;
}
sdp->Receive=recieve;
sdp->Transmit=transmit;
sdp->Delayms=delayms;
sdp->temperature=0.0;
sdp->dpressure=0.0;
if((i2cAddress==0x25)||(i2cAddress==0x26))
{
sdp->devAddress=(i2cAddress<<1);
}
else if((i2cAddress==0x4A)||(i2cAddress==0x4C))
{
sdp->devAddress=i2cAddress;
}
else
{
sdp->devAddress=0;
error|=SDP800_ERROR_IVALID_PARAMETER;
}
if(error==SDP800_ERROR_NONE)
{
error|=Sdp800ReadSerialNumber(sdp);
}
return error;
}
??在初始化函數(shù)中,我們對(duì)對(duì)象的屬性以及操作函數(shù)的指針變量都做了初始化,并讀取了設(shè)備的序列號(hào)。
2.2、對(duì)象操作
??我們定義了SDP800差壓傳感器的對(duì)像類型,也設(shè)計(jì)了對(duì)象變量的初始化函數(shù)。 這一節(jié)我們來看一看我們所要實(shí)現(xiàn)的操作。
2.2.1、數(shù)據(jù)的獲取
??我們需要對(duì)SDP800差壓傳感器所做的首要操作就是獲取測(cè)量數(shù)據(jù)。 根據(jù)不同的命令,SDP800差壓傳感器可以做單次測(cè)量,也可以做連續(xù)測(cè)量。 這里我們采用連續(xù)測(cè)量的方式。 連續(xù)測(cè)量設(shè)計(jì)到三類操作:開啟連續(xù)測(cè)量、讀取測(cè)量數(shù)據(jù)以及結(jié)束連續(xù)測(cè)量。 根據(jù)通訊命令及報(bào)文格式要求,我們實(shí)現(xiàn)數(shù)據(jù)連續(xù)讀取的代碼如下:
/*連續(xù)讀取測(cè)量值*/
SDP800ErrorType Sdp800ReadContinousMeasurement(SDP800ObjectType *sdp)
{
SDP800ErrorType error=SDP800_ERROR_NONE;
uint8_t rDatas[9];
int16_t diffPressureTicks;
int16_t temperatureTicks;
uint16_t scaleFactorDiffPressure;
sdp->Receive(sdp,rDatas,9);
if((rDatas[0]==0xFF)&&(rDatas[1]==0xFF)&&(rDatas[2]==0xAC)
&&(rDatas[3]==0xFF)&&(rDatas[4]==0xFF)&&(rDatas[5]==0xAC)
&&(rDatas[6]==0xFF)&&(rDatas[7]==0xFF)&&(rDatas[8]==0xAC))
{
sdp->status=0;
return SDP800_ERROR_ACK;
}
error|=CheckCRC8ForSDP800(&rDatas[0],2,rDatas[2]);
error|=CheckCRC8ForSDP800(&rDatas[3],2,rDatas[5]);
error|=CheckCRC8ForSDP800(&rDatas[6],2,rDatas[8]);
if(error==SDP800_ERROR_NONE)
{
diffPressureTicks=rDatas[0]*256+rDatas[1];
temperatureTicks=rDatas[3]*256+rDatas[4];
scaleFactorDiffPressure=rDatas[6]*256+rDatas[7];
sdp->temperature=(float)temperatureTicks/200.0;
sdp->dpFactor=(float)scaleFactorDiffPressure;
sdp->dpressure=(float)diffPressureTicks/sdp->dpFactor;
}
return error;
}
/*啟動(dòng)連續(xù)測(cè)量*/
SDP800ErrorType Sdp800StartContinousMeasurement(SDP800ObjectType *sdp,Sdp800TempCompType tempComp,Sdp800AveragingType averaging)
{
SDP800ErrorType error=SDP800_ERROR_NONE;
SDP800Command commands[2][2]={{COMMAND_START_MEASUREMENT_MF_AVERAGE,COMMAND_START_MEASUREMENT_MF_NONE},
{COMMAND_START_MEASUREMENT_DP_AVERAGE,COMMAND_START_MEASUREMENT_DP_NONE}};
switch (commands[tempComp][averaging])
{
case COMMAND_START_MEASUREMENT_MF_AVERAGE:
{
sdp->status=1;
break;
}
case COMMAND_START_MEASUREMENT_MF_NONE:
{
sdp->status=2;
break;
}
case COMMAND_START_MEASUREMENT_DP_AVERAGE:
{
sdp->status=3;
break;
}
case COMMAND_START_MEASUREMENT_DP_NONE:
{
sdp->status=4;
break;
}
default:
{
sdp->status=0;
error=SDP800_ERROR_IVALID_PARAMETER;
break;
}
}
if(SDP800_ERROR_NONE==error)
{
Sdp800WriteCommand(sdp,commands[tempComp][averaging]);
sdp->Delayms(20);
}
if(SDP800_ERROR_NONE!=error)
{
sdp->status=0;
}
return error;
}
/*停止連續(xù)測(cè)量*/
SDP800ErrorType Sdp800StopContinousMeasurement(SDP800ObjectType *sdp)
{
Sdp800WriteCommand(sdp,COMMAND_STOP_CONTINOUS_MEASUREMENT);
return SDP800_ERROR_NONE;
}
2.2.2、設(shè)備控制
??有一些命令是用來實(shí)現(xiàn)對(duì)SDP800差壓傳感器的控制的,如設(shè)備的復(fù)位、休眠及各種配置。 這里我們主要用到SDP800差壓傳感器的軟件復(fù)位及休眠。
/*軟件復(fù)位*/
SDP800ErrorType Sdp800SoftReset(SDP800ObjectType *sdp)
{
Sdp800WriteCommand(sdp,COMMAND_ENTER_SLEEP_MODE);
// 等待 20 ms
sdp->Delayms(20);
return SDP800_ERROR_NONE;
}
/*進(jìn)入休眠模式*/
SDP800ErrorType SDP800EnterSleepMode(SDP800ObjectType *sdp)
{
Sdp800WriteCommand(sdp,COMMAND_ENTER_SLEEP_MODE);
return SDP800_ERROR_NONE;
}
3、驅(qū)動(dòng)的使用
??我們?cè)O(shè)計(jì)并實(shí)現(xiàn)了SDP800差壓傳感器的驅(qū)動(dòng)程序。 接下來,我們使用設(shè)計(jì)的驅(qū)動(dòng)實(shí)現(xiàn)基于SDP800差壓傳感器傳感器的流量檢測(cè)。
3.1、聲明并初始化對(duì)象
??在前面我們已經(jīng)定義了SDP800差壓傳感器對(duì)象類型。 在這里,我們先聲明一個(gè)SDP800差壓傳感器對(duì)象變量。
SDP800ObjectType sdp;
??有了這個(gè)對(duì)象變量,我們還需要調(diào)用初始化函數(shù)對(duì)其進(jìn)行實(shí)例化。 初始化函數(shù)具有讀個(gè)參數(shù):
SDP800ObjectType *sdp, //SDP800對(duì)象
uint8_t i2cAddress, //設(shè)備地址
SDP800Receive recieve, //接收函數(shù)指針
SDP800Transmit transmit, //發(fā)送函數(shù)指針
SDP800Delayms delayms //毫秒演示函數(shù)
??第一個(gè)參數(shù)是需要初始化的對(duì)象變量。 第二個(gè)參數(shù)則是SDP800差壓傳感器的設(shè)備地址。 而后面的三個(gè)參數(shù)則是函數(shù)指針,我們需要實(shí)現(xiàn)這三個(gè)函數(shù),它們的原型定義如下:
//延時(shí)操作指針
typedef void (*SDP800Delayms)(volatile uint32_t nTime);
//接收數(shù)據(jù)操作指針
typedef void (*SDP800Receive)(struct SDP800Object *sdp,uint8_t *rData,uint16_t rSize);
//發(fā)送數(shù)據(jù)操作指針
typedef void (*SDP800Transmit)(struct SDP800Object *sdp,uint8_t *tData,uint16_t tSize);
??結(jié)合這三個(gè)函數(shù)的原型要求以及我們所使用平臺(tái)的具體特點(diǎn),我們實(shí)現(xiàn)這幾個(gè)函數(shù)如下:
/*向DSP800下發(fā)指令,指令格式均為1個(gè)字節(jié)*/
static void WriteToSDP(SDP800ObjectType *sdp,uint8_t *wData,uint16_t wSize)
{
HAL_I2C_Master_Transmit(&hi2c2,sdp->devAddress,wData,wSize,1000);
}
/*從DSP800讀取多個(gè)字節(jié)數(shù)據(jù)的值*/
static void ReadFromSDP(SDP800ObjectType *sdp,uint8_t *rData,uint16_t rSize)
{
HAL_I2C_Master_Receive(&hi2c2,sdp->devAddress,rData, rSize, 1000);
}
??我們實(shí)現(xiàn)了這些函數(shù)后,我們就可以將這些變量及函數(shù)作為初始化函數(shù)的參數(shù)來對(duì)SDP800差壓傳感器對(duì)象變量進(jìn)行實(shí)例化,具體實(shí)現(xiàn):
/*SDP800對(duì)象初始化配置*/
SDP800ErrorType error=Sdp800Initialization(&sdp, //SDP800對(duì)象
0x4A, //設(shè)備地址
ReadFromSDP, //接收函數(shù)指針
WriteToSDP, //發(fā)送函數(shù)指針
HAL_Delay //毫秒延時(shí)函數(shù)
);
Sdp800StartContinousMeasurement(&sdp,SDP800_TEMPCOMP_MASS_FLOW,SDP800_AVERAGING_TILL_READ);
3.2、基于對(duì)象進(jìn)行操作
??初始化完成后,我們則可以使用該對(duì)象獲取測(cè)量數(shù)據(jù)并計(jì)算流量值。 具體實(shí)現(xiàn)如下:
if(sdp.status==0)
{
Sdp800SoftReset(&sdp);
Sdp800StartContinousMeasurement(&sdp,SDP800_TEMPCOMP_MASS_FLOW,SDP800_AVERAGING_TILL_READ);
}
else
{
Sdp800ReadContinousMeasurement(&sdp);
}
aPara.phyPara.temperature=sdp.temperature;
dpFilter.newValue=sdp.dpressure;
aPara.phyPara.dpressure=BandSmoothingFilter(&dpFilter);
aPara.phyPara.dpressure=aPara.phyPara.dpressure<0.0?0.0:aPara.phyPara.dpressure;
flow=sqrtf(aPara.phyPara.dpressure);
flowFilter.newValue=Power3Polyfit(flow,aPara.phyPara.factorA,aPara.phyPara.factorB,aPara.phyPara.factorC,aPara.phyPara.factorD);
aPara.phyPara.flowValue=BandSmoothingFilter(&flowFilter);
aPara.phyPara.flowValue=aPara.phyPara.flowValue>0.25?aPara.phyPara.flowValue:0.0;
??在這一事例中,我們讀取了SDP800差壓傳感器的值,并根據(jù)差壓數(shù)據(jù)計(jì)算了流量數(shù)據(jù)。 并實(shí)現(xiàn)了修正、濾波以及小信號(hào)切除等處理。
4、應(yīng)用總結(jié)
??在這一篇中,我們?cè)O(shè)計(jì)并實(shí)現(xiàn)了SDP800差壓傳感器的驅(qū)動(dòng)程序,而且使用我們?cè)O(shè)計(jì)的驅(qū)動(dòng)實(shí)現(xiàn)了一個(gè)具體示例。 事實(shí)上,這個(gè)示例是從我們的實(shí)際項(xiàng)目中提煉出來的,實(shí)際的使用效果良好。
評(píng)論
查看更多