STM32 SHT10溫濕度傳感器的信號采集


       首先講講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_CLKRCC_APB2Periph_GPIOD
#define SHT10_DATA_PINGPIO_Pin_0
#define SHT10_SCK_PINGPIO_Pin_1
#define SHT10_DATA_PORTGPIOD
#define SHT10_SCK_PORTGPIOD

#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時鍾線

/* 傳感器相關宏定義 */
#definenoACK0
#define ACK1
//addr command r/w
#define STATUS_REG_W0x06//000 0011 0 寫狀態寄存器
#define STATUS_REG_R0x07//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 floatC2 = +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);
}
}
原文出處: http://ziye334.blog.163.com/blog/static/224306191201421265639956/


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com