外設驅動庫開發筆記10:SHT2x系列溫溼度感測器驅動
溫溼度檢測是嵌入式程式設計中經常應用到的一項功能。在我們的產品中亦經常使用。SHT2x系列溫溼度感測器作為一種高精度低成本的整合模組,一直應用於我們的產品中。在這裡我們討論如何封裝SHT2x系列溫溼度感測器的驅動。
1、功能概述
SHT20配有一個全新設計的CMOSens晶片、一個經過改進的電容式溼度感測元件和一個標準的能隙溫度感測元件,其效能已經大大提升甚至超出了前一代感測器(SHT1x和SHT7x)的可靠性水平。
1.1、硬體描述
SHT2x溼度和溫度感測器採用了新的封裝模式和數字介面,每一個感測器都經過校準和測試。在產品表面印有產品批號,同時在晶片記憶體儲了電子識別碼-可以通過輸入命令讀出這些識別碼。此外,SHT2x溫溼度感測器的解析度可以通過輸入命令進行改變(8/12bit乃至12/14bit的RH/T),感測器可以檢測到電池低電量 狀態,並且輸出校驗和,有助於提高通訊的可靠性。SHT2x溫溼度感測器的封裝及引腳定義如下圖:
SHT2x 溫溼度感測器的供電範圍為 2.1-3.6V,推薦電壓為 3.0V。電源(VDD)和接地(VSS)之間須連線一個100nF的去耦電容,且電容的位置應儘可能靠近感測器。數字介面為標準I2C匯流排。接線方式如下圖:
1.2、序列通訊
SHT2x溫溼度感測器採用標準的 I2C協議進行通訊。在啟動傳輸後,隨後傳輸的I2C首位元組包括 7位的I2C裝置地址(B-範例地址“1000’000”)和一個SDA方向位(讀 R:“1”,寫 W:“0”)。在第 8個SCL時鐘下降沿之後,通過拉低 SDA引腳(ACK位),指示感測器資料接收正常。在發出測量命令之後(“1110’0011”代表溫度測量,“1110’0101”代表相對溼度測量),MCU必須等待測量完成。基本的命令列表如下:
從上表我們知道,讀取SHT2x溫溼度感測器資料有兩種不同的方式可選,主機模式或非主機模式。在主機模式下,在測量的過程中, SCL線被封鎖(由 感測器進行控制),在非主機模式下,當傳 感器在執行測量任務時,SCL線仍然保持開 放狀態,可進行其他通訊。非主機模式允許 感測器進行測量時在總線上處理其他 I2C總 線通訊任務。
1.3、資料轉換
感測器內部設定的預設解析度為相對溼度12位和溫度14位。SDA的輸出資料被轉換成兩 個位元組的資料包,高位元組MSB在前(左對齊)。每個位元組後面都跟隨一個應答位。兩個狀態位,即LSB的後兩位在進行物理計算前須置“0”。
不論基於哪種解析度,相對溼度RH都可以根據SDA輸出的相對溼度訊號 SRH通過如下公式計算獲得(結果以%RH表示)。
以上所給出的 RH物理值對應於世界氣象組織(WMO)所規定的基於液態水的相對溼度。基於冰的相對溼度RHi可通過特定溫度t下基於水的 相對溼度 RHw轉換而來,同樣參照應用說明
相對溼度單位為 %RH溫度單位為°C for temperature. 相關係數如下:
不論基於哪種解析度,溫度 T都可以通過將溫度輸 出訊號 ST代入到下面的公式計算得到(結果以溫 度°C表示):
2、驅動設計與實現
我們已經瞭解了SHT2x系列溫溼度感測器基本技術特性,接下來我們進一步考慮如何設計並實現SHT2x系列溫溼度感測器的驅動。
2.1、物件定義
在使用一個物件之前我們需要獲得一個物件。同樣的我們想要SHT2x系列溫溼度感測器就需要先定義SHT2x系列溫溼度感測器的物件。
2.1.1、物件的抽象
我們要得到SHT2x系列溫溼度感測器物件,需要先分析其基本特性。一般來說,一個物件至少包含兩方面的特性:屬性與操作。接下來我們就來從這兩個方面思考一下SHT2x系列溫溼度感測器的物件。
先來考慮屬性,作為屬性肯定是用於標識或記錄物件特徵的東西。我們來考慮SHT2x系列溫溼度感測器物件屬性。首先對於I2C裝置會有一個地址,用於表示總線上不同的通訊節點,所以我們將裝置地址作為SHT2x系列溫溼度感測器物件的一個屬性。使用者暫存器標識了裝置的配置狀態,所以我們也將其作為SHT2x系列溫溼度感測器物件的一個屬性。同樣的每個SHT2X都有一個電子識別碼,用以標識SHT2X裝置的身份,所以我們也將其作為SHT2x系列溫溼度感測器物件的一個屬性。此外我們也將讀出來的溫溼度的數字編碼所以我們也將其作為SHT2x系列溫溼度感測器物件的屬性以記錄當前狀態。
接著我們還需要考慮SHT2x系列溫溼度感測器物件的操作問題。通過I2C匯流排傳送資料或者接收資料均依賴於具體的操作平臺,所以我們將向SHT2x傳送資料以及從SHT2x獲取資料均作為SHT2x系列溫溼度感測器物件的操作。此外,在驅動中會用到延時操作函式,延時操作一般也會依賴於具體平臺的實現,所以我們也將其作為SHT2x系列溫溼度感測器物件的操作。
根據上述我們對SHT2x溫溼度感測器的分析,我們可以定義SHT2x溫溼度感測器的物件型別如下:
1 /*定義SHT2x物件*/ 2 typedef struct SHT2xObject{ 3 uint8_t userReg; //使用者暫存器 4 uint8_t devAddress; //裝置地址 5 uint8_t sn[8]; //裝置序列號 6 uint16_t tempCode; //溫度的數值碼 7 uint16_t humiCode; //溼度的數值碼 8 void (*Delayms)(volatile uint32_t nTime); //毫秒延時操作指標 9 void (*Transmit)(struct SHT2xObject *sht,uint8_t *tData,uint16_t tSize); //傳送資料操作指標 10 void (*Receive)(struct SHT2xObject *sht,uint8_t *rData,uint16_t rSize); //接收資料操作指標 11 }SHT2xObjectType;
2.1.2、物件初始化
我們知道,一個物件僅作宣告是不能使用的,我們需要先對其進行初始化,所以這裡我們來考慮SHT2x系列溫溼度感測器物件的初始化函式。一般來說,初始化函式需要處理幾個方面的問題。一是檢查輸入引數是否合理;二是為物件的屬性賦初值;三是對物件作必要的初始化配置。據此我們設計SHT2x系列溫溼度感測器物件的初始化函式如下:
1 /* 初始化配置SHT2x */ 2 void SHT2xInitialization(SHT2xObjectType *sht, 3 SHT2xDPIType dpi, 4 SHT2xBatteryType endBat, 5 SHT2xHeaterType heater, 6 SHT2xOTPType otp, 7 SHT2xTransmit write, 8 SHT2xReceive read, 9 SHT2xDelayms delayms) 10 11 { 12 uint8_t userReg=0; 13 uint8_t dpiSet[4]={DPI_RH12_T14,DPI_RH8_T13,DPI_RH10_T12,DPI_RH11_T11}; 14 uint8_t batEnd[2]={END_OF_BATTERY_H,END_OF_BATTERY_L}; 15 uint8_t heaterSet[2]={ONCHIPHEATERDISABLE,ONCHIPHEATERENABLE}; 16 uint8_t otpSet[2]={OTPENABLE,OTPDISABLE}; 17 18 if((sht==NULL)||(write==NULL)||(read==NULL)||(delayms==NULL)) 19 { 20 return; 21 } 22 23 sht->Transmit=write; 24 sht->Receive=read; 25 sht->Delayms=delayms; 26 27 sht->devAddress=SHT2X_ADDRESS; 28 sht->tempCode=0; 29 sht->humiCode=0; 30 31 userReg=dpiSet[dpi]|batEnd[endBat]|heaterSet[heater]|otpSet[otp]; 32 33 SetSHT2xUserRegister(sht,userReg); //配置使用者暫存器 34 35 sht->Delayms(20); 36 37 GetSHT2xUserRegister(sht); //讀取使用者暫存器 38 39 GetSHT2xSerialNumber(sht); //獲取電子識別碼 40 }
2.2、物件操作
我們已經完成了SHT2x系列溫溼度感測器物件型別的定義和物件初始化函式的設計。但我們的主要目標是獲取物件的資訊,接下來我們還要實現面向SHT2x溫溼度感測器的各類操作。
2.2.1、軟體復位
軟體復位命令用於在無需關閉和再次開啟電源的情況下,重新啟動感測器系統。在接收到這個命令之後,感測器系統開始重新初始化,並恢復預設設定狀態,使用者暫存器的加熱器位除外。軟復位所需時間不超過15毫秒。命令格式如下:
1 /*軟體復位*/ 2 void SoftResetSHT2x(SHT2xObjectType *sht) 3 { 4 uint8_t tData=SOFT_RESET; 5 sht->Transmit(sht,&tData,1); 6 }
2.2.2、使用者暫存器操作
使用者暫存器用於配置SHT2X的工作特性,包括測量解析度、電池電壓、OTP載入和片內加熱器配置等。使用者暫存器的結構及各位的定義如下:
電池電量不足警報在電源電壓下降到 2.25V 以下時啟用。內部加熱器用於感測器功能性診斷,溫度升高時相對溼度降低。OTP重載入為一個安全功能,可以在每次測量前將整個OTP設定載入到暫存器,加熱器位除外。SHT2X中此功能預設為禁止狀態,且不推薦使用者使用。請採用軟復位代替它包含OTP重載入。
1 /*配置使用者暫存器*/ 2 static void SetSHT2xUserRegister(SHT2xObjectType *sht,uint8_t cmd) 3 { 4 uint8_t status; 5 uint8_t command; 6 uint8_t pData[2]; 7 8 GetSHT2xUserRegister(sht); 9 10 status=sht->userReg&0x38; 11 12 command=cmd&0xC7; 13 command=command|status; 14 15 if(command!=sht->userReg) 16 { 17 pData[0]=WRITE_USER_REGISTER; 18 pData[1]=command; 19 20 sht->Transmit(sht,pData,2); 21 22 sht->Delayms(10); 23 24 GetSHT2xUserRegister(sht); 25 } 26 }
在配置使用者暫存器時,需注意不得變更預留位且相關的預留位的預設值以後可能會改變。因此,在進行任何寫暫存器的操作之前,必須先讀預留位的預設值。之後,使用者暫存器位元組由對應的預留位的預設值和其他剩餘位的預設值或者寫入值組成。
2.2.3、資料獲取
SHT2x溫溼度感測器資料獲取有主機模式或非主機模式兩種。我們在這裡先看看非主機模式,在非主機模式下,MCU需要對感測器狀態進行查詢。此過程通過傳送一個啟動傳輸時序,之後緊接著是如下圖所示的I2C首位元組(1000’0001)來完成。如果內部處理工作完成,微控制器查詢到感測器發出的確認訊號後,相關資料就可以通過MCU進行讀取。如果測量處理工作沒有完成,感測器無確認位(ACK)輸出,此時必須重新發送啟動傳輸時序。
根據上述描述和時序圖我們可以得到獲取資料的函式如下:
1 /*讀取SHT2x的溼度資料*/ 2 float GetSHT2xHumidityValue(SHT2xObjectType *sht,uint8_t cmd) 3 { 4 uint8_t data[3]={0,0,0}; 5 uint16_t result=0; 6 7 /*設定轉換命令*/ 8 sht->Transmit(sht,&cmd,1); 9 10 sht->Delayms(29); 11 12 /*讀取資料*/ 13 sht->Receive(sht,data,3); 14 15 if(CheckCRC8ForSHT2x(data,2,data[2])) 16 { 17 result=(uint16_t)(data[0]); 18 result=(result<<8)+(uint16_t)(data[1]); 19 } 20 21 sht->humiCode=result; 22 23 return CalcSHT2xHumidity(result); 24 }
3、驅動的使用
我們已經設計並實現了SHT2x溫溼度感測器驅動,接下來我們還需要對這一驅動進行驗證,所以我們要基於此驅動設計一個簡單的應用。
3.1、宣告並初始化物件
使用基於物件的操作我們需要先得到這個物件,所以我們先要使用前面定義的SHT2X溫溼度感測器物件型別宣告一個SHT2X溫溼度感測器物件變數,具體操作格式如下:
SHT2xObjectType sht2x;
聲明瞭這個物件變數並不能立即使用,我們還需要使用驅動中定義的初始化函式對這個變數進行初始化。這個初始化函式所需要的輸入引數如下:
SHT2xObjectType *sht,SHT2X物件變數
SHT2xDPIType dpi,測量解析度配置
SHT2xBatteryType endBat,電池結束狀態配置
SHT2xHeaterType heater,加熱器是否啟用配置
SHT2xOTPType otp,是否載入OTP配置
SHT2xTransmit write,寫操作指標
SHT2xReceive read,讀操作指標
SHT2xDelayms delayms,毫秒延時指標
對於這些引數,物件變數我們已經定義了。所使用的測量解析度配置、電池結束狀態配置、加熱器是否啟用配置以及是否載入OTP配置均為列舉,根據實際情況選擇就好了。主要的是我們需要定義幾個函式,並將函式指標作為引數。這幾個函式的型別如下:
1 /* 毫秒延時函式指標型別 */ 2 typedef void (*SHT2xDelayms)(volatile uint32_t nTime); 3 4 /* 傳送資料函式指標型別 */ 5 typedef void (*SHT2xTransmit)(struct SHT2xObject *sht,uint8_t *tData,uint16_t tSize); 6 7 /* 接收資料函式指標型別 */ 8 typedef void (*SHT2xReceive)(struct SHT2xObject *sht,uint8_t *rData,uint16_t rSize);
對於這幾個函式我們根據樣式定義就可以了,具體的操作可能與使用的硬體平臺有關係。所以我們定義在STM32平臺下使用硬體介面I2C收發器的函式。具體函式定義如下:
1 /*從SHT20接收資料*/ 2 static void ReceiveFromSHT20(SHT2xObjectType *sht,uint8_t *rData,uint16_t rSize) 3 { 4 HAL_I2C_Master_Receive(&sht2xi2c, sht->devAddress,rData, rSize, 1000); 5 } 6 7 /*向SHT20傳送資料*/ 8 static void TransmitToSHT20(SHT2xObjectType *sht,uint8_t *tData,uint16_t tSize) 9 { 10 HAL_I2C_Master_Transmit(&sht2xi2c,sht->devAddress,tData,tSize,1000); 11 }
對於延時函式我們可以採用各種方法實現。我們採用的STM32平臺和HAL庫則可以直接使用HAL_Delay()函式。於是我們可以呼叫初始化函式如下:
SHT2xInitialization(&sht2x,SHT2x_DPI_RH12_T14,SHT2x_End_High,SHT2xHEATERDISABLE,SHT2xOTPDISABLE,TransmitToSHT20,ReceiveFromSHT20,HAL_Delay);
在這裡我們將SHT2x溫溼度控制器物件變數初始化為:最高解析度,在大於2.25V結束電池狀態,不載入OTP,不使用加熱器。
3.2、基於物件進行操作
我們定義了物件變數並使用初始化函式給其作了初始化。接著我們就來考慮操作這一物件獲取我們想要的資料。我們在驅動中已經將獲取資料並轉換為相應的物理量值,接下來我們使用這一驅動開發我們的應用例項。
1 /* 獲取SHT2x溫適度資料 */ 2 void GetSHT2xMeasureData(void) 3 { 4 float humidity; 5 float temperature; 6 7 humidity=GetSHT2xHumidityValue(&sht2x,MEASURE_RH_COMMAND_NOHOST); 8 9 temperature=GetSHT2xTemperatureValue(&sht2x,MEASURE_T_COMMAND_NOHOST); 10 }
這裡我們設計了一個簡單的應用,直接獲取SHT2x溫溼度感測器測量到的溫溼度資料。
4、應用總結
因為SHT2x溫溼度感測器採用的是標準I2C介面,所以在驅動設計中沒有考慮硬體介面相關的內容。我們只專注於SHT2x溫溼度感測器的配置與操作。所以在使用驅動程式時,無論是使用硬體I2C收發控制器還是使用GPIO模擬的軟體收發控制都需要單獨做相應的配置。
我們已經設計並實現了SHT2x溫溼度感測器的驅動程式,也使用這一驅動程式實現了讀取SHT2x溫溼度感測器溫度、溼度資料的簡單應用。經我們測試所得到的結果是符合我們期望的,這也說明驅動程式的設計是成功的。
在使用驅動時還需注意,在做初始化配置時,對使用者暫存器的寫操作需注意不得變更預留位且相關的預留位的預設值以後可能會改變。因此,在進行任何寫使用者暫存器的操作之前,必須先讀預留位的預設值。而且在初始化配置時,還要注意SHT2X 中OTP功能預設為禁止狀態,且不推薦使用者使用。
歡迎關注: