檢測流量數據的方法有很多種,這一次我們就是使用SDP800差壓傳感器來測量流量數據。 所以在這一篇中,我們將討論如何實現SDP800差壓傳感器的驅動,并使用它實現流量數據的檢測。
1、功能概述
??SDP800差壓傳感器系列是Sensirion為大批量應用設計的數字壓差傳感器系列。 傳感器測量空氣和非腐蝕性氣體的壓力,具有極高的精度,沒有偏移。 該傳感器覆蓋的壓力范圍高達±500 Pa,并提供卓越的精度。 其結構及引腳定義如下圖所示:
??SDP800系列差壓傳感器具有數字2線I2C接口,這使得它很容易直接連接到微處理器。 在I2C總線上每一臺設備都有一個地址,SDP800差壓傳感器不同的型號設備地址略有差異,具體如下表:
??雖然I2C接口基本有規范的通訊格式,但不同的設備在通訊報文的設置上還是有一下差異。 這里SDP800差壓傳感器其通訊報文的格式如下:
??在這一報文格式中,除了地址和數據還有一個16位的命令。 這些命令是廠商設定的,用于實現對SDP800差壓傳感器的各種操作。 這里我們只列出數據獲取的命令。
??對于SDP800差壓傳感器操作命令還有很多如配置、復位等我們在此不作詳述。
2、驅動設計與實現
??我們已經簡單的描述了SDP800差壓傳感器的基本情況。 這一節我們將進一步考慮SDP800差壓傳感器的驅動設計與實現。
2.1、對象定義
??首先我們來考慮SDP800差壓傳感器的對象定義。 關于對象總是存在對象的屬性和操作,SDP800差壓傳感器對象我們也從這兩個方面來考慮。
??我們先來分析一下SDP800差壓傳感器對象的屬性問題。 SDP800差壓傳感器采用I2C接口,所以設備地址必不可少,而且每一個地址都唯一標識一臺設備,所以我們將其設定為對象的屬性。 此外,SDP800差壓傳感器的產品編號和產品序列號都是唯一標識SDP800差壓傳感器設備,所以我們也將其設定為屬性。 我們也希望記錄設備的狀態、測量的壓力、溫度以及差壓系數等。 這些兩標識了SDP800差壓傳感器設備的狀態,所以我們也將其作為對象的屬性。
??而對象的操作,SDP800差壓傳感器采用I2C接口,所以需要接收和發送數據、為了控制時序我們需要延時操作函數。 而這些函數的實現都依賴于具體的軟硬件平臺,所以我們將它們設置為對象的操作,以便于通過回調函數來實現對象平臺無關性。 根據上述分析我們可以定義SDP800差壓傳感器的對象類型如下:
/* 定義SDP800對象類型 */
typedef struct SDP800Object{
uint8_t devAddress; //SDP800對象的地址
uint8_t status; //SDP800狀態信息
uint8_t pn[4]; //SDP800對象的產品號
uint8_t sn[8]; //SDP800對象的序列號
float dpressure; //差壓
float temperature; //溫度
float dpFactor; //差壓系數
void (*Delayms)(volatile uint32_t nTime); //延時操作指針
void (*Receive)(struct SDP800Object *sdp,uint8_t *rData,uint16_t rSize); //接收數據操作指針
void (*Transmit)(struct SDP800Object *sdp,uint8_t *tData,uint16_t tSize); //發送數據操作指針
}SDP800ObjectType;
??有了對象類型,我們就可以獲得對象變量,但對象變量需要初始化后才能進行各種操作,所以我們需要實現一個SDP800差壓傳感器對象變量初始化的函數。
/*SDP800對象初始化配置*/
SDP800ErrorType Sdp800Initialization(SDP800ObjectType *sdp, //SDP800對象
uint8_t i2cAddress, //設備地址
SDP800Receive recieve, //接收函數指針
SDP800Transmit transmit, //發送函數指針
SDP800Delayms delayms //毫秒演示函數
)
{
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;
}
??在初始化函數中,我們對對象的屬性以及操作函數的指針變量都做了初始化,并讀取了設備的序列號。
2.2、對象操作
??我們定義了SDP800差壓傳感器的對像類型,也設計了對象變量的初始化函數。 這一節我們來看一看我們所要實現的操作。
2.2.1、數據的獲取
??我們需要對SDP800差壓傳感器所做的首要操作就是獲取測量數據。 根據不同的命令,SDP800差壓傳感器可以做單次測量,也可以做連續測量。 這里我們采用連續測量的方式。 連續測量設計到三類操作:開啟連續測量、讀取測量數據以及結束連續測量。 根據通訊命令及報文格式要求,我們實現數據連續讀取的代碼如下:
/*連續讀取測量值*/
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;
}
/*啟動連續測量*/
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;
}
/*停止連續測量*/
SDP800ErrorType Sdp800StopContinousMeasurement(SDP800ObjectType *sdp)
{
Sdp800WriteCommand(sdp,COMMAND_STOP_CONTINOUS_MEASUREMENT);
return SDP800_ERROR_NONE;
}
2.2.2、設備控制
??有一些命令是用來實現對SDP800差壓傳感器的控制的,如設備的復位、休眠及各種配置。 這里我們主要用到SDP800差壓傳感器的軟件復位及休眠。
/*軟件復位*/
SDP800ErrorType Sdp800SoftReset(SDP800ObjectType *sdp)
{
Sdp800WriteCommand(sdp,COMMAND_ENTER_SLEEP_MODE);
// 等待 20 ms
sdp->Delayms(20);
return SDP800_ERROR_NONE;
}
/*進入休眠模式*/
SDP800ErrorType SDP800EnterSleepMode(SDP800ObjectType *sdp)
{
Sdp800WriteCommand(sdp,COMMAND_ENTER_SLEEP_MODE);
return SDP800_ERROR_NONE;
}
3、驅動的使用
??我們設計并實現了SDP800差壓傳感器的驅動程序。 接下來,我們使用設計的驅動實現基于SDP800差壓傳感器傳感器的流量檢測。
3.1、聲明并初始化對象
??在前面我們已經定義了SDP800差壓傳感器對象類型。 在這里,我們先聲明一個SDP800差壓傳感器對象變量。
SDP800ObjectType sdp;
??有了這個對象變量,我們還需要調用初始化函數對其進行實例化。 初始化函數具有讀個參數:
SDP800ObjectType *sdp, //SDP800對象
uint8_t i2cAddress, //設備地址
SDP800Receive recieve, //接收函數指針
SDP800Transmit transmit, //發送函數指針
SDP800Delayms delayms //毫秒演示函數
??第一個參數是需要初始化的對象變量。 第二個參數則是SDP800差壓傳感器的設備地址。 而后面的三個參數則是函數指針,我們需要實現這三個函數,它們的原型定義如下:
//延時操作指針
typedef void (*SDP800Delayms)(volatile uint32_t nTime);
//接收數據操作指針
typedef void (*SDP800Receive)(struct SDP800Object *sdp,uint8_t *rData,uint16_t rSize);
//發送數據操作指針
typedef void (*SDP800Transmit)(struct SDP800Object *sdp,uint8_t *tData,uint16_t tSize);
??結合這三個函數的原型要求以及我們所使用平臺的具體特點,我們實現這幾個函數如下:
/*向DSP800下發指令,指令格式均為1個字節*/
static void WriteToSDP(SDP800ObjectType *sdp,uint8_t *wData,uint16_t wSize)
{
HAL_I2C_Master_Transmit(&hi2c2,sdp->devAddress,wData,wSize,1000);
}
/*從DSP800讀取多個字節數據的值*/
static void ReadFromSDP(SDP800ObjectType *sdp,uint8_t *rData,uint16_t rSize)
{
HAL_I2C_Master_Receive(&hi2c2,sdp->devAddress,rData, rSize, 1000);
}
??我們實現了這些函數后,我們就可以將這些變量及函數作為初始化函數的參數來對SDP800差壓傳感器對象變量進行實例化,具體實現:
/*SDP800對象初始化配置*/
SDP800ErrorType error=Sdp800Initialization(&sdp, //SDP800對象
0x4A, //設備地址
ReadFromSDP, //接收函數指針
WriteToSDP, //發送函數指針
HAL_Delay //毫秒延時函數
);
Sdp800StartContinousMeasurement(&sdp,SDP800_TEMPCOMP_MASS_FLOW,SDP800_AVERAGING_TILL_READ);
3.2、基于對象進行操作
??初始化完成后,我們則可以使用該對象獲取測量數據并計算流量值。 具體實現如下:
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差壓傳感器的值,并根據差壓數據計算了流量數據。 并實現了修正、濾波以及小信號切除等處理。
4、應用總結
??在這一篇中,我們設計并實現了SDP800差壓傳感器的驅動程序,而且使用我們設計的驅動實現了一個具體示例。 事實上,這個示例是從我們的實際項目中提煉出來的,實際的使用效果良好。
評論