溫濕度檢測(cè)是嵌入式編程中經(jīng)常應(yīng)用到的一項(xiàng)功能。在我們的產(chǎn)品中亦經(jīng)常使用。SHT2x系列溫濕度傳感器作為一種高精度低成本的集成模塊,一直應(yīng)用于我們的產(chǎn)品中。在這里我們討論如何封裝SHT2x系列溫濕度傳感器的驅(qū)動(dòng)。
1 、功能概述
SHT20配有一個(gè)全新設(shè)計(jì)的CMOSens芯片、一個(gè)經(jīng)過改進(jìn)的電容式濕度傳感元件和一個(gè)標(biāo)準(zhǔn)的能隙溫度傳感元件,其性能已經(jīng)大大提升甚至超出了前一代傳感器(SHT1x和SHT7x)的可靠性水平。
1.1 、硬件描述
SHT2x濕度和溫度傳感器采用了新的封裝模式和數(shù)字接口,每一個(gè)傳感器都經(jīng)過校準(zhǔn)和測(cè)試。在產(chǎn)品表面印有產(chǎn)品批號(hào),同時(shí)在芯片內(nèi)存儲(chǔ)了電子識(shí)別碼-可以通過輸入命令讀出這些識(shí)別碼。此外,SHT2x溫濕度傳感器的分辨率可以通過輸入命令進(jìn)行改變(8/12bit乃至12/14bit的RH/T),傳感器可以檢測(cè)到電池低電量狀態(tài),并且輸出校驗(yàn)和,有助于提高通信的可靠性。SHT2x溫濕度傳感器的封裝及引腳定義如下圖:
SHT2x 溫濕度傳感器的供電范圍為 2.1-3.6V,推薦電壓為 3.0V。電源(VDD)和接地(VSS)之間須連接一個(gè)100nF的去耦電容,且電容的位置應(yīng)盡可能靠近傳感器。數(shù)字接口為標(biāo)準(zhǔn)I2C總線。接線方式如下圖:
1.2 、串行通訊
SHT2x溫濕度傳感器采用標(biāo)準(zhǔn)的 I2C協(xié)議進(jìn)行通訊。在啟動(dòng)傳輸后,隨后傳輸?shù)腎2C首字節(jié)包括 7位的I2C設(shè)備地址(B-范例地址“1000’000”)和一個(gè)SDA方向位(讀 R:“1”,寫 W:“0”)。在第 8個(gè)SCL時(shí)鐘下降沿之后,通過拉低 SDA引腳(ACK位),指示傳感器數(shù)據(jù)接收正常。在發(fā)出測(cè)量命令之后(“1110’0011”代表溫度測(cè)量,“1110’0101”代表相對(duì)濕度測(cè)量),MCU必須等待測(cè)量完成?;镜拿盍斜砣缦拢?/p>
從上表我們知道,讀取SHT2x溫濕度傳感器數(shù)據(jù)有兩種不同的方式可選,主機(jī)模式或非主機(jī)模式。在主機(jī)模式下,在測(cè)量的過程中, SCL線被封鎖(由傳感器進(jìn)行控制),在非主機(jī)模式下,當(dāng)傳感器在執(zhí)行測(cè)量任務(wù)時(shí),SCL線仍然保持開放狀態(tài),可進(jìn)行其他通訊。非主機(jī)模式允許傳感器進(jìn)行測(cè)量時(shí)在總線上處理其他 I2C總線通訊任務(wù)。
1.3 、數(shù)據(jù)轉(zhuǎn)換
傳感器內(nèi)部設(shè)置的默認(rèn)分辨率為相對(duì)濕度12位和溫度14位。SDA的輸出數(shù)據(jù)被轉(zhuǎn)換成兩個(gè)字節(jié)的數(shù)據(jù)包,高字節(jié)MSB在前(左對(duì)齊)。每個(gè)字節(jié)后面都跟隨一個(gè)應(yīng)答位。兩個(gè)狀態(tài)位,即LSB的后兩位在進(jìn)行物理計(jì)算前須置“0”。
不論基于哪種分辨率,相對(duì)濕度RH都可以根據(jù)SDA輸出的相對(duì)濕度信號(hào) SRH通過如下公式計(jì)算獲得(結(jié)果以%RH表示)。
以上所給出的 RH物理值對(duì)應(yīng)于世界氣象組織(WMO)所規(guī)定的基于液態(tài)水的相對(duì)濕度。基于冰的相對(duì)濕度RHi可通過特定溫度t下基于水的相對(duì)濕度 RHw轉(zhuǎn)換而來,同樣參照應(yīng)用說明:
相對(duì)濕度單位為 %RH溫度單位為°C fortemperature. 相關(guān)系數(shù)如下:
不論基于哪種分辨率,溫度 T都可以通過將溫度輸出信號(hào) ST代入到下面的公式計(jì)算得到(結(jié)果以溫度°C表示):
2 、驅(qū)動(dòng)設(shè)計(jì)與實(shí)現(xiàn)
我們已經(jīng)了解了SHT2x系列溫濕度傳感器基本技術(shù)特性,接下來我們進(jìn)一步考慮如何設(shè)計(jì)并實(shí)現(xiàn)SHT2x系列溫濕度傳感器的驅(qū)動(dòng)。
2.1 、對(duì)象定義
在使用一個(gè)對(duì)象之前我們需要獲得一個(gè)對(duì)象。同樣的我們想要SHT2x系列溫濕度傳感器就需要先定義SHT2x系列溫濕度傳感器的對(duì)象。
2.1.1 、對(duì)象的抽象
我們要得到SHT2x系列溫濕度傳感器對(duì)象,需要先分析其基本特性。一般來說,一個(gè)對(duì)象至少包含兩方面的特性:屬性與操作。接下來我們就來從這兩個(gè)方面思考一下SHT2x系列溫濕度傳感器的對(duì)象。
先來考慮屬性,作為屬性肯定是用于標(biāo)識(shí)或記錄對(duì)象特征的東西。我們來考慮SHT2x系列溫濕度傳感器對(duì)象屬性。首先對(duì)于I2C設(shè)備會(huì)有一個(gè)地址,用于表示總線上不同的通訊節(jié)點(diǎn),所以我們將設(shè)備地址作為SHT2x系列溫濕度傳感器對(duì)象的一個(gè)屬性。用戶寄存器標(biāo)識(shí)了設(shè)備的配置狀態(tài),所以我們也將其作為SHT2x系列溫濕度傳感器對(duì)象的一個(gè)屬性。同樣的每個(gè)SHT2X都有一個(gè)電子識(shí)別碼,用以標(biāo)識(shí)SHT2X設(shè)備的身份,所以我們也將其作為SHT2x系列溫濕度傳感器對(duì)象的一個(gè)屬性。此外我們也將讀出來的溫濕度的數(shù)字編碼所以我們也將其作為SHT2x系列溫濕度傳感器對(duì)象的屬性以記錄當(dāng)前狀態(tài)。
接著我們還需要考慮SHT2x系列溫濕度傳感器對(duì)象的操作問題。通過I2C總線發(fā)送數(shù)據(jù)或者接收數(shù)據(jù)均依賴于具體的操作平臺(tái),所以我們將向SHT2x發(fā)送數(shù)據(jù)以及從SHT2x獲取數(shù)據(jù)均作為SHT2x系列溫濕度傳感器對(duì)象的操作。此外,在驅(qū)動(dòng)中會(huì)用到延時(shí)操作函數(shù),延時(shí)操作一般也會(huì)依賴于具體平臺(tái)的實(shí)現(xiàn),所以我們也將其作為SHT2x系列溫濕度傳感器對(duì)象的操作。
根據(jù)上述我們對(duì)SHT2x溫濕度傳感器的分析,我們可以定義SHT2x溫濕度傳感器的對(duì)象類型如下:
/*定義SHT2x對(duì)象*/
typedef structSHT2xObject{
uint8_t userReg; //用戶寄存器
uint8_t devAddress; //設(shè)備地址
uint8_t sn[8]; //設(shè)備序列號(hào)
uint16_t tempCode; //溫度的數(shù)值碼
uint16_t humiCode; //濕度的數(shù)值碼
void (*Delayms)(volatile uint32_tnTime); //毫秒延時(shí)操作指針
void (*Transmit)(struct SHT2xObject *sht,uint8_t *tData,uint16_t tSize); //發(fā)送數(shù)據(jù)操作指針
void (*Receive)(struct SHT2xObject *sht,uint8_t *rData,uint16_t rSize); //接收數(shù)據(jù)操作指針
}SHT2xObjectType;
2.1.2 、對(duì)象初始化
我們知道,一個(gè)對(duì)象僅作聲明是不能使用的,我們需要先對(duì)其進(jìn)行初始化,所以這里我們來考慮SHT2x系列溫濕度傳感器對(duì)象的初始化函數(shù)。一般來說,初始化函數(shù)需要處理幾個(gè)方面的問題。一是檢查輸入參數(shù)是否合理;二是為對(duì)象的屬性賦初值;三是對(duì)對(duì)象作必要的初始化配置。據(jù)此我們?cè)O(shè)計(jì)SHT2x系列溫濕度傳感器對(duì)象的初始化函數(shù)如下:
/* 初始化配置SHT2x */
void SHT2xInitialization(SHT2xObjectType*sht,
SHT2xDPIType dpi,
SHT2xBatteryType endBat,
SHT2xHeaterType heater,
SHT2xOTPType otp,
SHT2xTransmit write,
SHT2xReceive read,
SHT2xDelayms delayms)
{
uint8_t userReg=0;
uint8_t dpiSet[4]={DPI_RH12_T14,DPI_RH8_T13,DPI_RH10_T12,DPI_RH11_T11};
uint8_t batEnd[2]={END_OF_BATTERY_H,END_OF_BATTERY_L};
uint8_t heaterSet[2]={ONCHIPHEATERDISABLE,ONCHIPHEATERENABLE};
uint8_t otpSet[2]={OTPENABLE,OTPDISABLE};
if((sht==NULL)||(write==NULL)||(read==NULL)||(delayms==NULL))
{
return;
}
sht->Transmit=write;
sht->Receive=read;
sht->Delayms=delayms;
sht->devAddress=SHT2X_ADDRESS;
sht->tempCode=0;
sht->humiCode=0;
userReg=dpiSet[dpi]|batEnd[endBat]|heaterSet[heater]|otpSet[otp];
SetSHT2xUserRegister(sht,userReg); //配置用戶寄存器
sht->Delayms(20);
GetSHT2xUserRegister(sht); //讀取用戶寄存器
GetSHT2xSerialNumber(sht); //獲取電子識(shí)別碼
}
2.2 、對(duì)象操作
我們已經(jīng)完成了SHT2x系列溫濕度傳感器對(duì)象類型的定義和對(duì)象初始化函數(shù)的設(shè)計(jì)。但我們的主要目標(biāo)是獲取對(duì)象的信息,接下來我們還要實(shí)現(xiàn)面向SHT2x溫濕度傳感器的各類操作。
2.2.1 、軟件復(fù)位
軟件復(fù)位命令用于在無需關(guān)閉和再次打開電源的情況下,重新啟動(dòng)傳感器系統(tǒng)。在接收到這個(gè)命令之后,傳感器系統(tǒng)開始重新初始化,并恢復(fù)默認(rèn)設(shè)置狀態(tài),用戶寄存器的加熱器位除外。軟復(fù)位所需時(shí)間不超過15毫秒。命令格式如下:
/*軟件復(fù)位*/
void SoftResetSHT2x(SHT2xObjectType*sht)
{
uint8_t tData=SOFT_RESET;
sht->Transmit(sht,&tData,1);
}
2.2.2 、用戶寄存器操作
用戶寄存器用于配置SHT2X的工作特性,包括測(cè)量分辨率、電池電壓、OTP加載和片內(nèi)加熱器配置等。用戶寄存器的結(jié)構(gòu)及各位的定義如下:
電池電量不足警報(bào)在電源電壓下降到 2.25V 以下時(shí)激活。內(nèi)部加熱器用于傳感器功能性診斷,溫度升高時(shí)相對(duì)濕度降低。OTP重加載為一個(gè)安全功能,可以在每次測(cè)量前將整個(gè)OTP設(shè)置加載到寄存器,加熱器位除外。SHT2X中此功能默認(rèn)為禁止?fàn)顟B(tài),且不推薦用戶使用。請(qǐng)采用軟復(fù)位代替它包含OTP重加載。
/*配置用戶寄存器*/
static voidSetSHT2xUserRegister(SHT2xObjectType *sht,uint8_t cmd)
{
uint8_t status;
uint8_t command;
uint8_t pData[2];
GetSHT2xUserRegister(sht);
status=sht->userReg&0x38;
command=cmd&0xC7;
command=command|status;
if(command!=sht->userReg)
{
pData[0]=WRITE_USER_REGISTER;
pData[1]=command;
sht->Transmit(sht,pData,2);
sht->Delayms(10);
GetSHT2xUserRegister(sht);
}
}
在配置用戶寄存器時(shí),需注意不得變更預(yù)留位且相關(guān)的預(yù)留位的默認(rèn)值以后可能會(huì)改變。因此,在進(jìn)行任何寫寄存器的操作之前,必須先讀預(yù)留位的默認(rèn)值。之后,用戶寄存器字節(jié)由對(duì)應(yīng)的預(yù)留位的默認(rèn)值和其他剩余位的默認(rèn)值或者寫入值組成。
2.2.3 、數(shù)據(jù)獲取
SHT2x溫濕度傳感器數(shù)據(jù)獲取有主機(jī)模式或非主機(jī)模式兩種。我們?cè)谶@里先看看非主機(jī)模式,在非主機(jī)模式下,MCU需要對(duì)傳感器狀態(tài)進(jìn)行查詢。此過程通過發(fā)送一個(gè)啟動(dòng)傳輸時(shí)序,之后緊接著是如下圖所示的I2C首字節(jié)(1000’0001)來完成。如果內(nèi)部處理工作完成,單片機(jī)查詢到傳感器發(fā)出的確認(rèn)信號(hào)后,相關(guān)數(shù)據(jù)就可以通過MCU進(jìn)行讀取。如果測(cè)量處理工作沒有完成,傳感器無確認(rèn)位(ACK)輸出,此時(shí)必須重新發(fā)送啟動(dòng)傳輸時(shí)序。
根據(jù)上述描述和時(shí)序圖我們可以得到獲取數(shù)據(jù)的函數(shù)如下:
/*讀取SHT2x的濕度數(shù)據(jù)*/
floatGetSHT2xHumidityValue(SHT2xObjectType *sht,uint8_t cmd)
{
uint8_t data[3]={0,0,0};
uint16_t result=0;
/*設(shè)置轉(zhuǎn)換命令*/
sht->Transmit(sht,&cmd,1);
sht->Delayms(29);
/*讀取數(shù)據(jù)*/
sht->Receive(sht,data,3);
if(CheckCRC8ForSHT2x(data,2,data[2]))
{
result=(uint16_t)(data[0]);
result=(result<<8)+(uint16_t)(data[1]);
}
sht->humiCode=result;
return CalcSHT2xHumidity(result);
}
3 、驅(qū)動(dòng)的使用
我們已經(jīng)設(shè)計(jì)并實(shí)現(xiàn)了SHT2x溫濕度傳感器驅(qū)動(dòng),接下來我們還需要對(duì)這一驅(qū)動(dòng)進(jìn)行驗(yàn)證,所以我們要基于此驅(qū)動(dòng)設(shè)計(jì)一個(gè)簡(jiǎn)單的應(yīng)用。
3.1 、聲明并初始化對(duì)象
使用基于對(duì)象的操作我們需要先得到這個(gè)對(duì)象,所以我們先要使用前面定義的SHT2X溫濕度傳感器對(duì)象類型聲明一個(gè)SHT2X溫濕度傳感器對(duì)象變量,具體操作格式如下:
SHT2xObjectTypesht2x;
聲明了這個(gè)對(duì)象變量并不能立即使用,我們還需要使用驅(qū)動(dòng)中定義的初始化函數(shù)對(duì)這個(gè)變量進(jìn)行初始化。這個(gè)初始化函數(shù)所需要的輸入?yún)?shù)如下:
SHT2xObjectType*sht,SHT2X對(duì)象變量
SHT2xDPIType dpi,測(cè)量分辨率配置
SHT2xBatteryTypeendBat,電池結(jié)束狀態(tài)配置
SHT2xHeaterTypeheater,加熱器是否啟用配置
SHT2xOTPType otp,是否加載OTP配置
SHT2xTransmitwrite,寫操作指針
SHT2xReceive read,讀操作指針
SHT2xDelaymsdelayms,毫秒延時(shí)指針
對(duì)于這些參數(shù),對(duì)象變量我們已經(jīng)定義了。所使用的測(cè)量分辨率配置、電池結(jié)束狀態(tài)配置、加熱器是否啟用配置以及是否加載OTP配置均為枚舉,根據(jù)實(shí)際情況選擇就好了。主要的是我們需要定義幾個(gè)函數(shù),并將函數(shù)指針作為參數(shù)。這幾個(gè)函數(shù)的類型如下:
/* 毫秒延時(shí)函數(shù)指針類型 */
typedef void (*SHT2xDelayms)(volatileuint32_t nTime);
/* 發(fā)送數(shù)據(jù)函數(shù)指針類型 */
typedef void (*SHT2xTransmit)(structSHT2xObject *sht,uint8_t *tData,uint16_t tSize);
/* 接收數(shù)據(jù)函數(shù)指針類型 */
typedef void (*SHT2xReceive)(structSHT2xObject *sht,uint8_t *rData,uint16_t rSize);
對(duì)于這幾個(gè)函數(shù)我們根據(jù)樣式定義就可以了,具體的操作可能與使用的硬件平臺(tái)有關(guān)系。所以我們定義在STM32平臺(tái)下使用硬件接口I2C收發(fā)器的函數(shù)。具體函數(shù)定義如下:
/*從SHT20接收數(shù)據(jù)*/
static voidReceiveFromSHT20(SHT2xObjectType *sht,uint8_t *rData,uint16_t rSize)
{
HAL_I2C_Master_Receive(&sht2xi2c,sht->devAddress,rData, rSize, 1000);
}
/*向SHT20傳送數(shù)據(jù)*/
static voidTransmitToSHT20(SHT2xObjectType *sht,uint8_t *tData,uint16_t tSize)
{
HAL_I2C_Master_Transmit(&sht2xi2c,sht->devAddress,tData,tSize,1000);
}
對(duì)于延時(shí)函數(shù)我們可以采用各種方法實(shí)現(xiàn)。我們采用的STM32平臺(tái)和HAL庫則可以直接使用HAL_Delay()函數(shù)。于是我們可以調(diào)用初始化函數(shù)如下:
SHT2xInitialization(&sht2x,SHT2x_DPI_RH12_T14,SHT2x_End_High,SHT2xHEATERDISABLE,SHT2xOTPDISABLE,TransmitToSHT20,ReceiveFromSHT20,HAL_Delay);
在這里我們將SHT2x溫濕度控制器對(duì)象變量初始化為:最高分辨率,在大于2.25V結(jié)束電池狀態(tài),不加載OTP,不使用加熱器。
3.2 、基于對(duì)象進(jìn)行操作
我們定義了對(duì)象變量并使用初始化函數(shù)給其作了初始化。接著我們就來考慮操作這一對(duì)象獲取我們想要的數(shù)據(jù)。我們?cè)隍?qū)動(dòng)中已經(jīng)將獲取數(shù)據(jù)并轉(zhuǎn)換為相應(yīng)的物理量值,接下來我們使用這一驅(qū)動(dòng)開發(fā)我們的應(yīng)用實(shí)例。
/* 獲取SHT2x溫適度數(shù)據(jù) */
void GetSHT2xMeasureData(void)
{
float humidity;
float temperature;
humidity=GetSHT2xHumidityValue(&sht2x,MEASURE_RH_COMMAND_NOHOST);
temperature=GetSHT2xTemperatureValue(&sht2x,MEASURE_T_COMMAND_NOHOST);
}
這里我們?cè)O(shè)計(jì)了一個(gè)簡(jiǎn)單的應(yīng)用,直接獲取SHT2x溫濕度傳感器測(cè)量到的溫濕度數(shù)據(jù)。
4 、應(yīng)用總結(jié)
因?yàn)镾HT2x溫濕度傳感器采用的是標(biāo)準(zhǔn)I2C接口,所以在驅(qū)動(dòng)設(shè)計(jì)中沒有考慮硬件接口相關(guān)的內(nèi)容。我們只專注于SHT2x溫濕度傳感器的配置與操作。所以在使用驅(qū)動(dòng)程序時(shí),無論是使用硬件I2C收發(fā)控制器還是使用GPIO模擬的軟件收發(fā)控制都需要單獨(dú)做相應(yīng)的配置。
我們已經(jīng)設(shè)計(jì)并實(shí)現(xiàn)了SHT2x溫濕度傳感器的驅(qū)動(dòng)程序,也使用這一驅(qū)動(dòng)程序?qū)崿F(xiàn)了讀取SHT2x溫濕度傳感器溫度、濕度數(shù)據(jù)的簡(jiǎn)單應(yīng)用。經(jīng)我們測(cè)試所得到的結(jié)果是符合我們期望的,這也說明驅(qū)動(dòng)程序的設(shè)計(jì)是成功的。
在使用驅(qū)動(dòng)時(shí)還需注意,在做初始化配置時(shí),對(duì)用戶寄存器的寫操作需注意不得變更預(yù)留位且相關(guān)的預(yù)留位的默認(rèn)值以后可能會(huì)改變。因此,在進(jìn)行任何寫用戶寄存器的操作之前,必須先讀預(yù)留位的默認(rèn)值。而且在初始化配置時(shí),還要注意SHT2X 中OTP功能默認(rèn)為禁止?fàn)顟B(tài),且不推薦用戶使用。
評(píng)論