|
本帖最后由 51黑ren 于 2015-12-27 04:09 編輯
首先講講SHT10這款溫室度傳感器。SHT1x(包括SHT10,SHT11和SHT15)屬于Sersirion溫濕度傳感器家族中的貼片封裝系列。更之前我講過的DHT11這款溫濕度傳感器相比,體積小了許多,特別適合用于產品中。SHT10溫濕度傳感器包括一個電容性聚合體測濕敏感元件、一個用能隙材料制成的測溫元件(文縐縐的),傳感器內部有一個精度高達14為位的A/D轉換器,適應串行接口電路實現無縫連接。該產品具有品質卓越、響應速度速度快,抗干擾能力強、性價比高等優點。
1、接口定義:
SHT10的接口定義如下圖所示:

如上圖所示,1腳為GND,4腳為VDD。它的供電電壓范圍為2.4~5.5V,建議的電壓為3.3V,在電源引腳(VDD、GND)之間必須加上一個0.1uf的電容,應于去耦濾波用。它的2腳DATA為數據引腳,3腳SCK為時鐘控制引腳,沒有發現這兩個引腳很像IIC所使用的引腳功能?沒錯,這個傳感器確實可以認為是IIC接口,但是又有卻別。該傳感器不能按照IIC的協議編址,但是,如果IIC總線上沒有掛接別的元件,傳感器可以直接連到IIC總線上,但是單片機必須按照傳感器的協議工作。傳感器與單片機的接線如下圖所示:

2、傳感器的通訊
2.1、“啟動傳輸”時序
用一組“啟動傳輸”時序來完成數據傳輸的初始化。它包括:當SCK時鐘高電平時DATA翻轉為低電平,緊接著SCK變成低電平,隨后是在SCK時鐘高電平,隨后是在SCK時鐘高電平DATA翻轉位高電平。時序如下:

2.2、復位時序
如果與SHT1x 通訊中斷,可通過下列信號時序復位:當DATA 保持高電平時,觸發SCK 時鐘9 次或更多。時序圖如下:

2.3、命令集
傳感器的命令包含三個地址位(目前只支持000,這就是他只能掛接在空閑的IIC總線上的原因)和五個命令位。。SHT1x 會以下述方式表示已正確地接收到指令:在第8 個SCK 時鐘的下降沿之后,將DATA 下拉為低電平(ACK 位)。在第9 個SCK 時鐘的下降沿之后,釋放DATA(恢復高電平)。命令集如下:

2.4、溫濕度測量
發布一組測量命令(‘00000101’表示相對濕度RH,‘00000011’表示溫度T)后,控制器要等待測量結束。這個過程需要大約20/80/320ms,分別對應8/12/14bit 測量。確切的時間隨內部晶振速度,最多可能有-30%的變化。。SHT1x 通過下拉DATA 至低電平并進入空閑模式,表示測量的結束?刂破髟谠俅斡|發SCK 時鐘前,必須等待這個“數據備妥”信號來讀出數據。檢測數據可以先被存儲,這樣控制器可以繼續執行其它任務在需要時再讀出數據。
在收到CRC 的確認位之后,表明通訊結束。如果不使用CRC-8 校驗,控制器可以在測量值LSB 后,通過保持ACK高電平終止通訊。在測量和通訊完成后,SHT1x 自動轉入休眠模式。
2.5、狀態寄存器
SHT1x 的某些高級功能可以通過給狀態寄存器發送指令來實現,如選擇測量分辨率,電量不足提醒,使用 OTP 加載或啟動加熱功能等。狀態寄存器度、寫如下:
狀態寄存器寫
狀態寄存器讀
狀態寄存器的具體描述如下表所示:
測量分辨率:默認分辨率 14bit (溫度) 和 12bit (濕度) 可以被降低為 12 和 8bit. 尤其適用于要求測量速度極高或者功耗極低的應用。
電量不足檢測功能:在電壓不足 2.47V 發出警告。精度為±0.05 V。
加熱:可通過向狀態寄存器內寫入命令啟動傳感器內部加熱器.。加熱器可以使傳感器的溫度高于周圍環境 5 – 10°C12 。功耗大約為 8mA @ 5V 。
OPT加載:開啟此功能,標定數據將在每次測量前被上傳到寄存器。如果不開啟此功能,可減少大約 10ms的測量時間。
上面的寄存器如果沒有什么特殊要求或應用于特定的場合,則無需配置,選擇默認就可以了。
2.6、通訊過程
傳感器的通訊過程為:發送”啟動傳輸“時序,初始化傳感器——>發送命令——>等待傳感器應答,及測量結束——>接收傳感器的16位數據值——>接收8為的CRC校驗數據——>休眠,等待下一次傳輸開始。
傳輸的過程的測量時序可以由下圖示意:
上圖中 TS = 傳輸開始, MSB = 高有效字節,LSB =低有效字節, LSb = 低有效位。
下面舉個實際測量時的相對濕度測量時序例子。時序如下:
這張圖可以知道:我們接收到的數據數值為”0000 0100 0011 0001“ = 1073 = 35.50% RH (位含溫度補償),至于怎么計算的,請接著往下看。
2.7、信號轉化
2.7.1 溫度的轉化
設T 2 1 SOt為從傳感器上讀出來的測量數值,我們需要用下面的公式將測量數值轉換成整整的溫度值。
T = d1 + d2 * SOt (其中d1,d2的值根據實際情況選擇,選項如下)
2.7.2 濕度的轉換
濕度的轉換公式如下: 。其中濕度的轉化參數如下選擇:根據采樣的精度不同而不同。
99%以上的濕度已經接近飽和必須經過處理顯示100%RH13.請注意 濕度傳感器對電壓無依賴性。測量值與相對濕度的轉化如下圖所示:
相對濕度根據上面的參數與公式算出來之后,還需要考慮當前環境溫度而進行適當的補償。補償的公式及其參數選擇如下:
2.7.3、露點的計算
露點的定義:露點溫度指空氣在此溫度下能保持最多的水汽,當溫度冷卻到露點,空氣變得飽和,就會出現霧、露或霜。
SHT1x 并不直接進行露點測量,,但露點可以通過溫度和濕度讀數計算得到.。由于溫度和濕度在同一塊集成電路上測量,SHT1x 可測量露點。 一塊集成電路上測量,SHT1x 可測量露點。 下面直接給出結論性的露點計算公式了。
LogEW=(0.66077+7.5*T/(237.3+T)+(log10(RH)-2)
露點:Dp=((0.66077-logEW)*237.3/(logEW-8.16077)
例如:RH=10% T=25C ->EW=23.7465->露點=-8.69℃
RH=90% T=50C ->EW=92.4753->露點=47.89℃
2.8、STM32上的SHT10驅動程序
2.8.1、SHT10.h文件的編寫
這個文件主要定義些重要的參數,以及更硬件相關的一些定義。
- /*************************************************************
- \(^o^)/
- Copyright (C), 2013-2020, ZheJiang University of Technology
- File name : SHT10.h
- Author : ziye334
- Version : V1.0
- Data : 2014/3/10
- Description: Digital temperature and humidity sensor driver code
-
- *************************************************************/
- #ifndef __SHT10_H__
- #define __SHT10_H__
- #include "stm32f10x.h"
- enum {TEMP, HUMI};
- /* GPIO相關宏定義 */
- #define SHT10_AHB2_CLK RCC_APB2Periph_GPIOD
- #define SHT10_DATA_PIN GPIO_Pin_0
- #define SHT10_SCK_PIN GPIO_Pin_1
- #define SHT10_DATA_PORT GPIOD
- #define SHT10_SCK_PORT GPIOD
- #define SHT10_DATA_H() GPIO_SetBits(SHT10_DATA_PORT, SHT10_DATA_PIN) //拉高DATA數據線
- #define SHT10_DATA_L() GPIO_ResetBits(SHT10_DATA_PORT, SHT10_DATA_PIN) //拉低DATA數據線
- #define SHT10_DATA_R() GPIO_ReadInputDataBit(SHT10_DATA_PORT, SHT10_DATA_PIN) //讀DATA數據線
- #define SHT10_SCK_H() GPIO_SetBits(SHT10_SCK_PORT, SHT10_SCK_PIN) //拉高SCK時鐘線
- #define SHT10_SCK_L() GPIO_ResetBits(SHT10_SCK_PORT, SHT10_SCK_PIN) //拉低SCK時鐘線
- /* 傳感器相關宏定義 */
- #define noACK 0
- #define ACK 1
- //addr command r/w
- #define STATUS_REG_W 0x06 //000 0011 0 寫狀態寄存器
- #define STATUS_REG_R 0x07 //000 0011 1 讀狀態寄存器
- #define MEASURE_TEMP 0x03 //000 0001 1 測量溫度
- #define MEASURE_HUMI 0x05 //000 0010 1 測量濕度
- #define SOFTRESET 0x1E //000 1111 0 復位
- void SHT10_Config(void);
- void SHT10_ConReset(void);
- u8 SHT10_SoftReset(void);
- u8 SHT10_Measure(u16 *p_value, u8 *p_checksum, u8 mode);
- void SHT10_Calculate(u16 t, u16 rh,float *p_temperature, float *p_humidity);
- float SHT10_CalcuDewPoint(float t, float h);
- #endif
復制代碼
2.8.2、SHT10.c驅動程序的編寫
不廢話了,直接貼代碼:
- /*************************************************************
- \(^o^)/
- Copyright (C), 2013-2020, ZheJiang University of Technology
- File name : SHT10.c
- Author : ziye334
- Version : V1.0
- Data : 2014/3/10
- Description: Digital temperature and humidity sensor driver code
-
- *************************************************************/
- #include "SHT10.h"
- #include <math.h>
- /*************************************************************
- Function :SHT10_Dly
- Description:SHT10時序需要的延時
- Input : none
- return : none
- *************************************************************/
- void SHT10_Dly(void)
- {
- u16 i;
- for(i = 500; i > 0; i--);
- }
- /*************************************************************
- Function :SHT10_Config
- Description:初始化 SHT10引腳
- Input : none
- return : none
- *************************************************************/
- void SHT10_Config(void)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
- //初始化SHT10引腳時鐘
- RCC_APB2PeriphClockCmd(SHT10_AHB2_CLK ,ENABLE);
-
- //PD0 DATA 推挽輸出
- GPIO_InitStructure.GPIO_Pin = SHT10_DATA_PIN;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
- GPIO_Init(SHT10_DATA_PORT, &GPIO_InitStructure);
- //PD1 SCK 推挽輸出
- GPIO_InitStructure.GPIO_Pin = SHT10_SCK_PIN;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
- GPIO_Init(SHT10_SCK_PORT, &GPIO_InitStructure);
- SHT10_ConReset(); //復位通訊
- }
- /*************************************************************
- Function :SHT10_DATAOut
- Description:設置DATA引腳為輸出
- Input : none
- return : none
- *************************************************************/
- void SHT10_DATAOut(void)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
- //PD0 DATA 推挽輸出
- GPIO_InitStructure.GPIO_Pin = SHT10_DATA_PIN;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
- GPIO_Init(SHT10_DATA_PORT, &GPIO_InitStructure);
- }
- /*************************************************************
- Function :SHT10_DATAIn
- Description:設置DATA引腳為輸入
- Input : none
- return : none
- *************************************************************/
- void SHT10_DATAIn(void)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
- //PD0 DATA 浮動輸入
- GPIO_InitStructure.GPIO_Pin = SHT10_DATA_PIN;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
- GPIO_Init(SHT10_DATA_PORT, &GPIO_InitStructure);
- }
- /*************************************************************
- Function :SHT10_WriteByte
- Description:寫1字節
- Input : value:要寫入的字節
- return : err: 0-正確 1-錯誤
- *************************************************************/
- u8 SHT10_WriteByte(u8 value)
- {
- u8 i, err = 0;
-
- SHT10_DATAOut(); //設置DATA數據線為輸出
- for(i = 0x80; i > 0; i /= 2) //寫1個字節
- {
- if(i & value)
- SHT10_DATA_H();
- else
- SHT10_DATA_L();
- SHT10_Dly();
- SHT10_SCK_H();
- SHT10_Dly();
- SHT10_SCK_L();
- SHT10_Dly();
- }
- SHT10_DATAIn(); //設置DATA數據線為輸入,釋放DATA線
- SHT10_SCK_H();
- err = SHT10_DATA_R(); //讀取SHT10的應答位
- SHT10_SCK_L();
- return err;
- }
- /*************************************************************
- Function :SHT10_ReadByte
- Description:讀1字節數據
- Input : Ack: 0-不應答 1-應答
- return : err: 0-正確 1-錯誤
- *************************************************************/
- u8 SHT10_ReadByte(u8 Ack)
- {
- u8 i, val = 0;
- SHT10_DATAIn(); //設置DATA數據線為輸入
- for(i = 0x80; i > 0; i /= 2) //讀取1字節的數據
- {
- SHT10_Dly();
- SHT10_SCK_H();
- SHT10_Dly();
- if(SHT10_DATA_R())
- val = (val | i);
- SHT10_SCK_L();
- }
- SHT10_DATAOut(); //設置DATA數據線為輸出
- if(Ack)
- SHT10_DATA_L(); //應答,則會接下去讀接下去的數據(校驗數據)
- else
- SHT10_DATA_H(); //不應答,數據至此結束
- SHT10_Dly();
- SHT10_SCK_H();
- SHT10_Dly();
- SHT10_SCK_L();
- SHT10_Dly();
- return val; //返回讀到的值
- }
- /*************************************************************
- Function :SHT10_TransStart
- Description:開始傳輸信號,時序如下:
- _____ ________
- DATA: |_______|
- ___ ___
- SCK : ___| |___| |______
- Input : none
- return : none
- *************************************************************/
- void SHT10_TransStart(void)
- {
- SHT10_DATAOut(); //設置DATA數據線為輸出
- SHT10_DATA_H();
- SHT10_SCK_L();
- SHT10_Dly();
- SHT10_SCK_H();
- SHT10_Dly();
- SHT10_DATA_L();
- SHT10_Dly();
- SHT10_SCK_L();
- SHT10_Dly();
- SHT10_SCK_H();
- SHT10_Dly();
- SHT10_DATA_H();
- SHT10_Dly();
- SHT10_SCK_L();
- }
- /*************************************************************
- Function :SHT10_ConReset
- Description:通訊復位,時序如下:
- _____________________________________________________ ________
- DATA: |_______|
- _ _ _ _ _ _ _ _ _ ___ ___
- SCK : __| |__| |__| |__| |__| |__| |__| |__| |__| |______| |___| |______
- Input : none
- return : none
- *************************************************************/
- void SHT10_ConReset(void)
- {
- u8 i;
- SHT10_DATAOut();
- SHT10_DATA_H();
- SHT10_SCK_L();
- for(i = 0; i < 9; i++) //觸發SCK時鐘9c次
- {
- SHT10_SCK_H();
- SHT10_Dly();
- SHT10_SCK_L();
- SHT10_Dly();
- }
- SHT10_TransStart(); //啟動傳輸
- }
- /*************************************************************
- Function :SHT10_SoftReset
- Description:軟復位
- Input : none
- return : err: 0-正確 1-錯誤
- *************************************************************/
- u8 SHT10_SoftReset(void)
- {
- u8 err = 0;
- SHT10_ConReset(); //通訊復位
- err += SHT10_WriteByte(SOFTRESET);//寫RESET復位命令
- return err;
- }
- /*************************************************************
- Function :SHT10_ReadStatusReg
- Description:讀狀態寄存器
- Input : p_value-讀到的數據;p_checksun-讀到的校驗數據
- return : err: 0-正確 0-錯誤
- *************************************************************/
- u8 SHT10_ReadStatusReg(u8 *p_value, u8 *p_checksum)
- {
- u8 err = 0;
- SHT10_TransStart(); //開始傳輸
- err = SHT10_WriteByte(STATUS_REG_R);//寫STATUS_REG_R讀取狀態寄存器命令
- *p_value = SHT10_ReadByte(ACK); //讀取狀態數據
- *p_checksum = SHT10_ReadByte(noACK);//讀取檢驗和數據
-
- return err;
- }
- /*************************************************************
- Function :SHT10_WriteStatusReg
- Description:寫狀態寄存器
- Input : p_value-要寫入的數據值
- return : err: 0-正確 1-錯誤
- *************************************************************/
- u8 SHT10_WriteStatusReg(u8 *p_value)
- {
- u8 err = 0;
- SHT10_TransStart(); //開始傳輸
- err += SHT10_WriteByte(STATUS_REG_W);//寫STATUS_REG_W寫狀態寄存器命令
- err += SHT10_WriteByte(*p_value); //寫入配置值
- return err;
- }
- /*************************************************************
- Function :SHT10_Measure
- Description:從溫濕度傳感器讀取溫濕度
- Input : p_value-讀到的值;p_checksum-讀到的校驗數
- return : err: 0-正確 1—錯誤
- *************************************************************/
- u8 SHT10_Measure(u16 *p_value, u8 *p_checksum, u8 mode)
- {
- u8 err = 0;
- u32 i;
- u8 value_H = 0;
- u8 value_L = 0;
- SHT10_TransStart(); //開始傳輸
- switch(mode)
- {
- case TEMP: //測量溫度
- err += SHT10_WriteByte(MEASURE_TEMP);//寫MEASURE_TEMP測量溫度命令
- break;
- case HUMI:
- err += SHT10_WriteByte(MEASURE_HUMI);//寫MEASURE_HUMI測量濕度命令
- break;
- default:
- break;
- }
- SHT10_DATAIn();
- for(i = 0; i < 72000000; i++) //等待DATA信號被拉低
- {
- if(SHT10_DATA_R() == 0) break; //檢測到DATA被拉低了,跳出循環
- }
- if(SHT10_DATA_R() == 1) //如果等待超時了
- err += 1;
- value_H = SHT10_ReadByte(ACK);
- value_L = SHT10_ReadByte(ACK);
- *p_checksum = SHT10_ReadByte(noACK); //讀取校驗數據
- *p_value = (value_H << 8) | value_L;
- return err;
- }
- /*************************************************************
- Function :SHT10_Calculate
- Description:計算溫濕度的值
- Input : Temp-從傳感器讀出的溫度值;Humi-從傳感器讀出的濕度值
- p_humidity-計算出的實際的濕度值;p_temperature-計算出的實際溫度值
- return : none
- *************************************************************/
- void SHT10_Calculate(u16 t, u16 rh, float *p_temperature, float *p_humidity)
- {
- const float d1 = -39.7;
- const float d2 = +0.01;
- const float C1 = -2.0468;
- const float C2 = +0.0367;
- const float C3 = -0.0000015955;
- const float T1 = +0.01;
- const float T2 = +0.00008;
- float RH_Lin; //RH線性值
- float RH_Ture; //RH真實值
- float temp_C;
- temp_C = d1 + d2 * t; //計算溫度值
- RH_Lin = C1 + C2 * rh + C3 * rh * rh; //計算濕度值
- RH_Ture = (temp_C -25) * (T1 + T2 * rh) + RH_Lin; //濕度的溫度補償,計算實際的濕度值
- if(RH_Ture > 100) //設置濕度值上限
- RH_Ture = 100;
- if(RH_Ture < 0.1)
- RH_Ture = 0.1; //設置濕度值下限
- *p_humidity = RH_Ture;
- *p_temperature = temp_C;
- }
- /*************************************************************
- Function :SHT10_CalcuDewPoint
- Description:計算露點
- Input : h-實際的濕度;t-實際的溫度
- return : dew_point-露點
- *************************************************************/
- float SHT10_CalcuDewPoint(float t, float h)
- {
- float logEx, dew_point;
- logEx = 0.66077 + 7.5 * t / (237.3 + t) + (log10(h) - 2);
- dew_point = ((0.66077 - logEx) * 237.3) / (logEx - 8.16077);
- return dew_point;
- }
- 2.8.3、main函數的編寫:
- int main(void)
- {
- u16 humi_val, temp_val;
- u8 err = 0, checksum = 0;
- float humi_val_real = 0.0;
- float temp_val_real = 0.0;
- float dew_point = 0.0;
-
- BSP_Init();
- printf("\nSHT10溫室度測試程序!!!\n");
- SHT10_Config();
- while(1)
- {
- err += SHT10_Measure(&temp_val, &checksum, TEMP); //獲取溫度測量值
- err += SHT10_Measure(&humi_val, &checksum, HUMI); //獲取濕度測量值
- if(err != 0)
- SHT10_ConReset();
- else
- {
- SHT10_Calculate(temp_val, humi_val, &temp_val_real, &humi_val_real); //計算實際的溫濕度值
- dew_point = SHT10_CalcuDewPoint(temp_val_real, humi_val_real); //計算露點溫度
- }
- printf("當前環境溫度為:%2.1f℃,濕度為:%2.1f%%,露點溫度為%2.1f℃\r\n", temp_val_real, humi_val_real, dew_point);
- LED1_Toggle();
- Delay_ms(1000);
- }
- }
復制代碼
|
|