在我們的產(chǎn)品中經(jīng)常會遇到溫濕度檢測的需求。可以用于檢測溫濕度的傳感器元件也有很多。我們經(jīng)常使用的SHT各系列數(shù)字溫濕度傳感器來實現(xiàn)應(yīng)用需求。在這里我們將設(shè)計并實現(xiàn)SHT3x系列溫濕度傳感器的驅(qū)動。
1 、功能概述
SHT3x系列溫濕度傳感器是適用于各種應(yīng)用的高品質(zhì)濕度傳感器。SHT3x溫濕度傳感器系列結(jié)合了多種功能和各種接口適合各類應(yīng)用。
1.1 、硬件描述
SHT3x建立在全新和優(yōu)化的CMOSens?芯片之上,進(jìn)一步提高了產(chǎn)品可靠性和精度規(guī)格。SHT3x提供了一系列新功能,如增強(qiáng)信號處理、兩個獨特和用戶可選I2C地址、一個可編程溫濕度極限的報警模式,以及高達(dá)1 MHz的通信速度。SHT3x系列溫濕度傳感器的引腳排布及說明如下圖所示:
SHT3x系列溫濕度傳感器適用于2.15至5.5 V的寬電源電壓范圍。電源插腳必須與一個100nf電容解耦,該電容應(yīng)盡可能靠近傳感器。
SCL和SDA線都是開放式I/O,帶有到VDD和VSS的二極管。它們應(yīng)該連接到外部上拉電阻。I2C總線上的設(shè)備必須只驅(qū)動線路到地面。外部上拉電阻必須把信號高。上拉電阻可能包括在微控制器的I/O電路中。SHT3x系列溫濕度傳感器接線方式如下圖:
SCL用于同步微控制器與傳感器之間的通信。時鐘頻率可以自由選擇在0到1000千赫之間。支持根據(jù)I2C標(biāo)準(zhǔn)伸縮時鐘的命令。SDA引腳用于在傳感器之間傳輸數(shù)據(jù)。頻率高達(dá)400khz的通信必須滿足I2C快速模式標(biāo)準(zhǔn)。
1.2 、信息通訊
SHT3x系列溫濕度傳感器支持I2C快速模式(頻率高達(dá)1000千赫)??梢酝ㄟ^適當(dāng)?shù)挠脩裘顔⒂煤徒脮r鐘拉伸。
向傳感器發(fā)送一個命令后,傳感器需要最少等待1ms的時間才能接收到另一個命令。所有SHT3x命令和數(shù)據(jù)都映射到16位地址空間。此外,數(shù)據(jù)和命令由CRC校驗和保護(hù)。這增加了通信的可靠性。傳感器的16位命令已經(jīng)包含一個3位CRC校驗和。傳感器發(fā)送和接收的數(shù)據(jù)總是由一個8位CRC來完成。在寫方向上,必須傳輸校驗和,因為SHT3x只接受后面跟著正確校驗和的數(shù)據(jù)。在讀取方向上,由主程序讀取和處理校驗和。
SHT3x系列溫濕度傳感器可以通過ADDR引腳設(shè)置設(shè)備的通訊地址。請注意,I2C地址是通過I2C讀寫頭的7個msb表示的,LSB在讀寫操作之間切換。具體的地址如下:
1.3 、數(shù)據(jù)轉(zhuǎn)換
測量數(shù)據(jù)總是以16位無符號整數(shù)的形式傳輸。這些值已經(jīng)線性化,并補(bǔ)償了溫度和電源電壓的影響??梢允褂煤唵蔚墓綄⑦@些原始值轉(zhuǎn)換為物理量值。相對濕度換算公式(結(jié)果為%RH):
溫度轉(zhuǎn)換公式(結(jié)果為攝氏度和華氏度):
SRH和ST分別表示原始傳感器輸出的濕度和溫度。只有當(dāng)SRH和ST用十進(jìn)制表示時,這些公式才能正確工作。
2 、驅(qū)動設(shè)計與實現(xiàn)
我們已經(jīng)了解了SHT3x系列溫濕度傳感器基本技術(shù)特性,接下來我們進(jìn)一步考慮如何設(shè)計并實現(xiàn)SHT3x系列溫濕度傳感器的驅(qū)動。
2.1 、對象定義
在使用一個對象之前我們需要獲得一個對象。同樣的我們想要SHT3x系列溫濕度傳感器就需要先定義SHT3x系列溫濕度傳感器的對象。
2.1.1 、對象的抽象
我們要得到SHT3x系列溫濕度傳感器對象,需要先分析其基本特性。一般來說,一個對象至少包含兩方面的特性:屬性與操作。接下來我們就來從這兩個方面思考一下SHT3x系列溫濕度傳感器的對象。
先來考慮屬性,作為屬性肯定是用于標(biāo)識或記錄對象特征的東西。我們來考慮SHT3x系列溫濕度傳感器對象屬性。作為一個I2C總線設(shè)備,設(shè)備地址用于標(biāo)識設(shè)備在總線上的唯一性,所以我們將設(shè)備地址作為SHT3x對象的一個屬性。對于每一個SHT3x設(shè)備都有一個電子標(biāo)識碼,它是標(biāo)識SHT3x設(shè)備個體的東西,所以我們將其作為SHT3x對象的屬性。此外,溫濕度的當(dāng)前值標(biāo)識了當(dāng)前的狀態(tài)我們將其作為兩個屬性。還有SHT3x的狀態(tài)寄存器也是記錄SHT3x配置及工作狀態(tài)的,所以我們也將其作為SHT3x對象的屬性。
接著我們還需要考慮SHT3x系列溫濕度傳感器對象的操作問題。作為數(shù)字通訊設(shè)備,我們向其發(fā)送數(shù)據(jù)和從其接收數(shù)據(jù)都是必要,但接收與發(fā)送數(shù)據(jù)依賴于所處的硬件平臺,所以我們將發(fā)送數(shù)據(jù)與接收數(shù)據(jù)作為SHT3x對象的兩個操作?;跁r序操作的需要,在通訊過程中需要作延時處理,但如何實現(xiàn)延時依賴于具體的硬件平臺,所以我們也將延時處理作為SHT3x對象的一個操作。
根據(jù)上述我們對SHT3x溫濕度傳感器的分析,我們可以定義SHT3x溫濕度傳感器的對象類型如下:
/* 定義SHT3x對象類型 */
typedef structSHT3xObject{
uint8_t devAddress; // SHT3x對象的地址
SHT3xStatusRegister status; // SHT3x狀態(tài)及存期的值
uint32_t serialNumber; // SHT3x對象的序列號
float temperature;
float humidity;
void (*Delayms)(volatile uint32_tnTime); //延時操作指針
void (*Receive)(uint8_t devAddress,uint8_t *rData,uint16_t rSize); //接收數(shù)據(jù)操作指針
void (*Transmit)(uint8_t devAddress,uint8_t *tData,uint16_t tSize); //發(fā)送數(shù)據(jù)操作指針
}SHT3xObjectType;
2.1.2 、對象初始化
我們知道,一個對象僅作聲明是不能使用的,我們需要先對其進(jìn)行初始化,所以這里我們來考慮SHT3x系列溫濕度傳感器對象的初始化函數(shù)。一般來說,初始化函數(shù)需要處理幾個方面的問題。一是檢查輸入參數(shù)是否合理;二是為對象的屬性賦初值;三是對對象作必要的初始化配置。這里我們就從這幾個方面入手設(shè)計SHT3x系列溫濕度傳感器對象的初始化函數(shù)。
/* SHT3x對象初始化 */
SHT3xErrorTypeSHT3xInitialization(SHT3xObjectType *sht,
uint8_t address,
SHT3xTransmit transmit,
SHT3xReceive receive,
SHT3xDelayms delayms)
{
SHT3xErrorType error=SHT3X_NO_ERROR;
if((sht==NULL)||(transmit==NULL)||(receive==NULL)||(delayms==NULL))
{
returnSHT3X_PARM_ERROR;
}
sht->Transmit=transmit;
sht->Receive=receive;
sht->Delayms=delayms;
sht->temperature=0.0;
sht->humidity=0.0;
if((address==0x44)||(address==0x45))
{
sht->devAddress=(address<<1);
}
else if((address==0x88)||(address==0x8A))
{
sht->devAddress=address;
}
else
{
sht->devAddress=0;
error|=SHT3X_PARM_ERROR;
}
sht->status.word=0;
error|=SHT3xReadStatusRegister(sht);
if(error==SHT3X_NO_ERROR)
{
error|=SHT3xReadSerialNumber(sht);
}
return error;
}
2.2 、對象操作
我們已經(jīng)完成了SHT3x系列溫濕度傳感器對象類型的定義和對象初始化函數(shù)的設(shè)計。但我們的主要目標(biāo)是獲取對象的信息,接下來我們還要實現(xiàn)面向SHT3x溫濕度傳感器的各類操作。
2.2.1 、單次測量
SHT3X溫濕度傳感器有一種單次測量模式。這種模式只按我們規(guī)定的方式運行一次,測量通信序列由一個啟動條件、I2C寫標(biāo)頭和一個16位測量命令組成。在傳感器完成測量后,通過發(fā)送一個START條件和一個I2C讀標(biāo)頭,主控可以讀取測量結(jié)果。具體的格式如下:
根據(jù)這一單次數(shù)據(jù)測量并讀取的流程圖,我們可以很方便的得到單次讀取SHT3X溫濕度傳感器數(shù)據(jù)的程序。
/* 獲取一次性采集 */
SHT3xErrorTypeSHT3xGetSingleShotData(SHT3xObjectType *sht,SHT3xRepeatabilityrepeatability,SHT3xMode mode)
{
SHT3xErrorType error=SHT3X_NO_ERROR;
uint8_t data[6];
uint16_t tempCode;
uint16_t humiCode;
SHT3xCommandscommands[2][3]={{CMD_MEAS_CLOCKSTR_H, // 單次數(shù)據(jù)采集模式,時鐘延展,高重復(fù)性
CMD_MEAS_CLOCKSTR_M, // 單次數(shù)據(jù)采集模式,時鐘延展,中重復(fù)性
CMD_MEAS_CLOCKSTR_L, // 單次數(shù)據(jù)采集模式,時鐘延展,低重復(fù)性
},
{CMD_MEAS_POLLING_H, // 單次數(shù)據(jù)采集模式,輪詢,高重復(fù)性
CMD_MEAS_POLLING_M, // 單次數(shù)據(jù)采集模式,輪詢,中重復(fù)性
CMD_MEAS_POLLING_L, // 單次數(shù)據(jù)采集模式,輪詢,低重復(fù)性
}};
SHT3xWriteCommand(sht,commands[mode][repeatability]);
if(mode==MODE_CLKSTRETCH)
{
sht->Delayms(1);
}
else if(mode==MODE_POLLING)
{
sht->Delayms(20);
}
sht->Receive(sht,data,6);
error|=CheckCRC8ForSHT3x(&data[0],2,data[2]);
error|=CheckCRC8ForSHT3x(&data[3],2,data[5]);
if(error==SHT3X_NO_ERROR)
{
tempCode=(data[0]<<8)+data[1];
humiCode=(data[3]<<8)+data[4];
sht->temperature=CalcTemperatureValue(tempCode);
sht->humidity=CalcHumidityValue(humiCode);
}
return error;
}
2.2.2 、周期測量
SHT3X溫濕度傳感器還有一種周期性檢測數(shù)據(jù)的方式。這種方式先將SHT3X溫濕度傳感器配置為周期獲取模式。在這一模式下就可以周期獲取數(shù)據(jù)了。周期獲取數(shù)據(jù)的格式如下圖:
根據(jù)上述周期讀取數(shù)據(jù)的字節(jié)順序圖我們可以編寫周期獲取的程序如下:
/* 讀取周期性采集的數(shù)據(jù) */
SHT3xErrorTypeSHT3xFetchPeriodicMeasurmentData(SHT3xObjectType *sht)
{
SHT3xErrorType error=SHT3X_NO_ERROR;
uint8_t data[6];
uint16_t tempCode;
uint16_t humiCode;
SHT3xWriteCommand(sht,CMD_FETCH_DATA);
sht->Delayms(1);
sht->Receive(sht,data,6);
error|=CheckCRC8ForSHT3x(&data[0],2,data[2]);
error|=CheckCRC8ForSHT3x(&data[3],2,data[5]);
if(error==SHT3X_NO_ERROR)
{
tempCode=(data[0]<<8)+data[1];
humiCode=(data[3]<<8)+data[4];
sht->temperature=CalcTemperatureValue(tempCode);
sht->humidity=CalcHumidityValue(humiCode);
}
return error;
}
2.2.3 、系統(tǒng)復(fù)位
對于SHT3X來說系統(tǒng)復(fù)位包括的內(nèi)容比較多,有接口復(fù)位、軟件復(fù)位、廣播復(fù)位和硬件復(fù)位引腳復(fù)位。這里我們需要考慮的主要是軟件復(fù)位,其操作方式如下圖:
根據(jù)上圖我們可以很輕松的實現(xiàn)軟件復(fù)位操作。
2.2.4 、內(nèi)部加熱器
SHT3x配備了內(nèi)部加熱器,但僅用于可靠性檢查。加熱器可以通過命令開關(guān),控溫范圍大約在幾度范圍之內(nèi)。其狀態(tài)可在狀態(tài)寄存器中查看,默認(rèn)加熱器是關(guān)閉。器操作命令如下:
但是不建議操作加熱器。
2.2.5 、狀態(tài)寄存器
狀態(tài)寄存器包含有關(guān)加熱器運行狀態(tài)、警報模式以及最后一個命令的執(zhí)行狀態(tài)和最后一個寫序列的信息。讀取狀態(tài)寄存器的命令如下所示:
狀態(tài)寄存器的第15、11、10、4位等是我們關(guān)系比較多的,這些報警標(biāo)志位可以通過命令清楚。根據(jù)上述數(shù)據(jù)字節(jié)流圖我們可以得到讀狀態(tài)寄存器的函數(shù)如下:
/* 讀取狀態(tài)寄存器的值 */
SHT3xErrorTypeSHT3xReadStatusRegister(SHT3xObjectType *sht,SHT3xStatusRegister*status)
{
SHT3xErrorType error=SHT3X_NO_ERROR;
uint8_t sta[3];
SHT3xWriteCommand(sht,CMD_READ_STATUS);
sht->Delayms(1);
sht->Receive(sht,sta,3);
error|=CheckCRC8ForSHT3x(&sta[0],2,sta[2]);
if(error==SHT3X_NO_ERROR)
{
status->word=(sta[0]<<8)+sta[1];
}
else
{
status->word=0;
}
return error;
}
3 、驅(qū)動的使用
我們已經(jīng)設(shè)計并實現(xiàn)了SHT3x溫濕度傳感器驅(qū)動,接下來我們還需要對這一驅(qū)動進(jìn)行驗證,所以我們要基于此驅(qū)動設(shè)計一個簡單的應(yīng)用。
3.1 、聲明并初始化對象
使用基于對象的操作我們需要先得到這個對象,所以我們先要使用前面定義的SHT3X溫濕度傳感器對象類型聲明一個SHT3X溫濕度傳感器對象變量,具體操作格式如下:
SHT3xObjectTypesht3x;
聲明了這個對象變量并不能立即使用,我們還需要使用驅(qū)動中定義的初始化函數(shù)對這個變量進(jìn)行初始化。這個初始化函數(shù)有很多的輸入?yún)?shù),要求如下:
SHT3xObjectType*sht,待初始化的SHT3X
uint8_t address,設(shè)備地址
SHT3xReceivereceive,接收數(shù)據(jù)函數(shù)指針
SHT3xTransmittransmit,發(fā)送數(shù)據(jù)函數(shù)指針
SHT3xDelaymsdelayms,毫秒延時函數(shù)指針
對于這些參數(shù),對象變量我們已經(jīng)定義了。設(shè)備地址則根據(jù)實際的使用地址輸入即可。主要的是我們需要定義幾個函數(shù),并將函數(shù)指針作為參數(shù)。這幾個函數(shù)的類型如下:
/* 毫秒延時函數(shù)指針類型 */
typedef void (*SHT3xDelayms)(volatileuint32_t nTime);
/* 接收數(shù)據(jù)函數(shù)指針類型 */
typedef void(*SHT3xReceive)(SHT3xObjectType *sht,uint8_t *rData,uint16_t rSize);
/* 發(fā)送數(shù)據(jù)函數(shù)指針類型 */
typedef void(*SHT3xTransmit)(SHT3xObjectType *sht,uint8_t *tData,uint16_t tSize);
對于這幾個函數(shù)我們根據(jù)樣式定義就可以了,具體的操作可能與使用的硬件平臺有關(guān)系。我們的應(yīng)用基于STM32F4平臺實現(xiàn),接下來將基于我們的平臺實現(xiàn)這些函數(shù)。具體函數(shù)定義如下:
/*從SHT3X接收數(shù)據(jù)*/
static voidReceiveFromSHT3x(SHT3xObjectType *sht,uint8_t *rData,uint16_t rSize)
{
HAL_I2C_Master_Receive(&sht3xi2c,sht->devAddress,rData, rSize, 1000);
}
/*向SHT3X傳送數(shù)據(jù)*/
static void TransmitToSHT3x(SHT3xObjectType*sht,uint8_t *tData,uint16_t tSize)
{
HAL_I2C_Master_Transmit(&sht3xi2c,sht->devAddress,tData,tSize,1000);
}
對于延時函數(shù)我們可以采用各種方法實現(xiàn)。我們采用的STM32平臺和HAL庫則可以直接使用HAL_Delay()函數(shù)。于是我們可以調(diào)用初始化函數(shù)如下:
SHT3xInitialization(&sht3x,0x88,TransmitToSHT3x,ReceiveFromSHT3x,HAL_Delay);
其中0x88為設(shè)備地址。
3.2 、基于對象進(jìn)行操作
我們定義了對象變量并使用初始化函數(shù)給其作了初始化。接著我們就來考慮操作這一對象獲取我們想要的數(shù)據(jù)。我們在驅(qū)動中已經(jīng)將獲取數(shù)據(jù)并轉(zhuǎn)換為轉(zhuǎn)換值的比例值,接下來我們使用這一驅(qū)動開發(fā)我們的應(yīng)用實例。
/*獲取溫濕度計數(shù)據(jù)*/
void SHT3xMeasureData(void)
{
float humidity;
float temperature;
SHT3xErrorType error=SHT3X_NO_ERROR;
SHT3xStatusRegister status;
error|=SHT3xReadStatusRegister(&sht3x,&status);
if(error!=SHT3X_NO_ERROR)
{
return ;
}
if(status.bit.ResetDetected)
{
SHT3xClearStatusRegister(&sht3x);
SHT3xStartPeriodicMeasurment(&sht3x,REPEATAB_HIGH,F(xiàn)REQUENCY_1HZ);
}
error|=SHT3xFetchPeriodicMeasurmentData(&sht3x);
if(error==SHT3X_NO_ERROR)
{
temperature=sht3x.temperature;
humidity=sht3x.humidity;
}
}
4 、應(yīng)用總結(jié)
我們已經(jīng)設(shè)計并實現(xiàn)了SHT3x溫濕度傳感器的驅(qū)動程序,也使用這一驅(qū)動程序?qū)崿F(xiàn)了讀取SHT3x溫濕度傳感器溫度、濕度數(shù)據(jù)的簡單應(yīng)用。經(jīng)我們測試所得到的結(jié)果是符合我們期望的,這也說明驅(qū)動程序的設(shè)計是成功的。
在使用驅(qū)動時還需注意,在做初始化配置時,對狀態(tài)寄存器的寫操作需注意不得變更預(yù)留位且相關(guān)的預(yù)留位的默認(rèn)值以后可能會改變。因此,在進(jìn)行任何寫用戶寄存器的操作之前,必須先讀預(yù)留位的默認(rèn)值。而且在初始化配置時,還要注意SHT3X 中OTP功能默認(rèn)為禁止?fàn)顟B(tài),且不推薦用戶使用。
因為SHT3x溫濕度傳感器采用的是標(biāo)準(zhǔn)I2C接口,所以在驅(qū)動設(shè)計中沒有考慮硬件接口相關(guān)的內(nèi)容。我們只專注于SHT3x溫濕度傳感器的配置與操作。所以在使用驅(qū)動程序時,無論是使用硬件I2C收發(fā)控制器還是使用GPIO模擬的軟件收發(fā)控制都需要單獨做相應(yīng)的配置。
評論