猪无忌 发表于 2012-10-26 00:05:46

基于SHT11的温湿度测控系统的设计

    QQ:314443526


SHT11是一种包含相对湿度温度多传感器模块的校准数字输出的单芯片,该设备包括一个电容聚合物敏感元件作为相对湿度和带隙温度传感器。两者都是无缝整合一个14位ADC和一个串行接口电路在同一个芯片上,这样可以具有高信号质量,快速相应时间和抗干扰能力(电磁兼容性),每一个SHT11都是被独立校准的并且标定系数被编程到OTP存储器。二线串行接口和内部电压调节完成了简便快速的系统整合。
该SHT11如图所示。

图一:传感器结构

温湿度测控系统所需要配件如下

图二:实物相片

图三:单片机及电源继电器控制板

图四:单片机系统(含12864显示)

图五:原理图一
其中:P1^6接串口时钟(SCK),P1^7接数据(DATA);
P2^4,P2^5,P2^6,P2^7分别接四个控制继电器;       

图六:液晶接口原理图
源程序如下:
#include <reg52.h>
#include <intrins.h>
#include <math.h>

#define uchar unsigned char
#define uintunsigned int

//宏定义
#define noACK 0
#define ACK   1
#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 RESET      0x1e   //000   1111    0

typedef union
{ unsigned int i;
float f;
} value;


enum {TEMP,HUMI};


//12864LCD引脚定义
#define LCD_dataP0       //数据口
sbit LCD_RS=P1^2;      //寄存器选择输入
sbit LCD_RW=P1^1;      //液晶读/写控制
sbit LCD_EN=P1^0;      //液晶使能控制
sbit SCK=P1^6;      //定义SHT11的数据端
sbit DATA=P1^7;   
sbit Relay5=P2^4;       //定义制冷
sbit Relay6=P2^5;       //定义加热
sbit Relay7=P2^6;        //定义加湿
sbit Relay8=P2^7;        //定义风机

#define delayNOP(); {_nop_();_nop_();_nop_();_nop_();};
//-------------------------------------------------------
ucharDIS1[] = {"当前温度:       "};
ucharDIS2[] = {"当前湿度:       "};
ucharDIS3[] = {"系统当前工作状态"};
ucharDIS4[] = {"制冷"};
ucharDIS5[] = {"加热"};
ucharDIS6[] = {"加湿"};
ucharDIS7[] = {" "};
//-------------------------------------------------------


char s_write_byte(unsigned char value)

// SHT11写字节程序
{
unsigned char i,error=0;
for (i=0x80;i>0;i/=2)            
{ if (i & value) DATA=1;      
    else DATA=0;                        
    SCK=1;                        
    _nop_();_nop_();_nop_();      
    SCK=0;
}
DATA=1;                        
SCK=1;                           
error=DATA;                     
SCK=0;      
return error;                  
}

char s_read_byte(unsigned char ack)

// SHT11读字节程序
{
unsigned char i,val=0;
DATA=1;                           
for (i=0x80;i>0;i/=2)            
{ SCK=1;                        
    if (DATA) val=(val | i);      
    SCK=0;                                       
}
DATA=!ack;                        
SCK=1;                           
_nop_();_nop_();_nop_();         
SCK=0;                                                  
DATA=1;                        
return val;
}

//----------------------------------------------------------------------------------
void s_transstart(void)

{
   DATA=1; SCK=0;                   //SHT11启动传输
   _nop_();
   SCK=1;
   _nop_();
   DATA=0;
   _nop_();
   SCK=0;
   _nop_();_nop_();_nop_();
   SCK=1;
   _nop_();
   DATA=1;                  
   _nop_();
   SCK=0;                  
}


void s_connectionreset(void)

{
unsigned char i;
DATA=1; SCK=0;                  //Initial state
for(i=0;i<9;i++)                  //9 SCK cycles
{ SCK=1;
    SCK=0;
}
s_transstart();                   //transmission start
}

char s_measure(unsigned char *p_value, unsigned char *p_checksum, unsigned char mode)
// SHT11温湿度检测
{
unsigned error=0;
unsigned int i;

s_transstart();                  
switch(mode){                  
    case TEMP        : error+=s_write_byte(MEASURE_TEMP); break;
    case HUMI        : error+=s_write_byte(MEASURE_HUMI); break;
    default   : break;       
}
for (i=0;i<65535;i++) if(DATA==0) break;
if(DATA) error+=1;               
*(p_value)=s_read_byte(ACK);   
*(p_value+1)=s_read_byte(ACK);   
*p_checksum =s_read_byte(noACK);
return error;
}


void calc_sth11(float *p_humidity ,float *p_temperature)
// SHT11温湿度值标度变换及温度补偿
{ const float C1=-4.0;            
const float C2=+0.0405;         
const float C3=-0.0000028;      
const float T1=+0.01;            
const float T2=+0.00008;         

float rh=*p_humidity;         
float t=*p_temperature;         
float rh_lin;                  
float rh_true;               
float t_C;                  

t_C=t*0.01 - 40;               
rh_lin=C3*rh*rh + C2*rh + C1;   
rh_true=(t_C-25)*(T1+T2*rh)+rh_lin;   
if(rh_true>100)rh_true=100;      
if(rh_true<0.1)rh_true=0.1;      

*p_temperature=t_C;            
*p_humidity=rh_true;            
}

char s_read_statusreg(unsigned char *p_value, unsigned char *p_checksum)
//----------------------------------------------------------------------------------
// reads the status register with checksum (8-bit)
{
unsigned char error=0;
s_transstart();                   //transmission start
error=s_write_byte(STATUS_REG_R); //send command to sensor
*p_value=s_read_byte(ACK);      //read status register (8-bit)
*p_checksum=s_read_byte(noACK);   //read checksum (8-bit)
return error;                     //error=1 in case of no response form the sensor
}

//----------------------------------------------------------------------------------
char s_write_statusreg(unsigned char *p_value)
//----------------------------------------------------------------------------------
// writes the status register with checksum (8-bit)
{
unsigned char error=0;
s_transstart();                   //transmission start
error+=s_write_byte(STATUS_REG_W);//send command to sensor
error+=s_write_byte(*p_value);    //send value of status register
return error;                     //error>=1 in case of no response form the sensor
}
float calc_dewpoint(float h,float t)

{ float logEx,dew_point;
logEx=0.66077+7.5*t/(237.3+t)+(log10(h)-2);
dew_point = (logEx - 0.66077)*237.3/(0.66077+7.5-logEx);
return dew_point;
}
void DelayXus(uint x)
{
        uchar i;
        while(x--)
        {
               for(i=0;i<200;i++);
        }
}

void Delay(uint x)
{
        while(--x);
}


//ms延时函数
void Delay_xms(uint x)
{
uint i,j;
for(i=0;i<x;i++)
   for(j=0;j<112;j++);
}
/*******************************************************************/
/*                                                               */
/*写指令数据到LCD                                                */
/*RS=L,RW=L,E=高脉冲,D0-D7=指令码。                           */
/*                                                               */
/*******************************************************************/
void lcd_wcmd(uchar cmd)
{                     

    Delay_xms(5);
    LCD_RS = 0;
    LCD_RW = 0;
    LCD_EN = 0;
    _nop_();
    _nop_();
    LCD_data = cmd;
    delayNOP();
    LCD_EN = 1;
    delayNOP();
    LCD_EN = 0;
}
/*******************************************************************/
/*                                                               */
/*写显示数据到LCD                                                */
/*RS=H,RW=L,E=高脉冲,D0-D7=数据。                               */
/*                                                               */
/*******************************************************************/
void lcd_wdat(uchar dat)
{               
    Delay_xms(5);
    LCD_RS = 1;
    LCD_RW = 0;
    LCD_EN = 0;
    LCD_data = dat;
    delayNOP();
    LCD_EN = 1;
    delayNOP();
    LCD_EN = 0;
}
/*******************************************************************/
/*                                                               */
/*LCD初始化设定                                                */
/*                                                               */
/*******************************************************************/
void lcd_init()
{
//    LCD_PSB = 1;         //并口方式
   
//        LCD_RST = 0;               //液晶复位
    Delay_xms(3);                  
//    LCD_RST = 1;      
    Delay_xms(3);
   
    lcd_wcmd(0x34);      //扩充指令操作
    Delay_xms(5);
    lcd_wcmd(0x30);      //基本指令操作
    Delay_xms(5);
    lcd_wcmd(0x0C);      //显示开,关光标
    Delay_xms(5);
    lcd_wcmd(0x01);      //清除LCD的显示内容
    Delay_xms(5);
}
/*********************************************************/
/*                                                       */
/* 设定显示位置                                          */
/*                                                       */
/*********************************************************/
void lcd_pos(uchar X,uchar Y)
{                        
   ucharpos;
   if (X==1)
   {X=0x80;}
   else if (X==2)
   {X=0x90;}
   else if (X==3)
   {X=0x88;}
   else if (X==4)
   {X=0x98;}
   pos = X+Y ;

   lcd_wcmd(pos);   //显示地址
}


/*********************************************************
*                                                      *
* 主函数                                                 *
*                                                      *
*********************************************************/
void main()
{
   uchar i1;
   value humi_val,temp_val;
   float dew_point;
   unsigned char error,checksum;
   unsigned int temp,humi;
   unsigned int dew;
   Delay_xms(100);               //上电,等待稳定
   lcd_init();   //初始化LCD
   
   Delay(50000);
   Delay(50000);
   s_connectionreset();

   while(1)
   {
       
   error=0;
   error+=s_measure((unsigned char*) &humi_val.i,&checksum,HUMI);//湿度测量
   error+=s_measure((unsigned char*) &temp_val.i,&checksum,TEMP);//温度测量
   if(error!=0) s_connectionreset();               //如果发生错误,系统复位
   else
          {
          
           humi_val.f=(float)humi_val.i;                   //转换为浮点数
       temp_val.f=(float)temp_val.i;                   //转换为浮点数
       calc_sth11(&humi_val.f,&temp_val.f);            //修正相对湿度和温度
           dew_point=calc_dewpoint(humi_val.f,temp_val.f); //计算露点值
           dew=dew_point*10;

       temp=temp_val.f*10;
       DIS1=temp/1000+'0';                   //温度百位
       DIS1=temp%1000/100+'0';            //温度十位      
       DIS1=temp%100/10+'0';                     //温度个位
       DIS1=0x2E;                                          //小数点
       DIS1=temp%10+'0';         //温度小数点后第一位
           lcd_pos(1,0);             //设置显示位置为第一行
       for(i1=0;i1<16;i1++)
          {
         lcd_wdat(DIS1);
         Delay_xms(30);
         }
                      
       humi=humi_val.f*10;
       DIS2=humi/1000+'0';                   //湿度百位
       DIS2=humi%1000/100+'0';            //湿度十位      
       DIS2=humi%100/10+'0';                     //湿度个位
       DIS2=0x2E;                                          //小数点
       DIS2=humi%10+'0';                    //湿度小数点后第一位
           lcd_pos(2,0);             //设置显示位置为第二行
       for(i1=0;i1<16;i1++)
          {
         lcd_wdat(DIS2);
         Delay_xms(30);
         }
           lcd_pos(3,0);             //设置显示位置为第三行
       for(i1=0;i1<16;i1++)
          {
         lcd_wdat(DIS3);
         Delay_xms(30);
                   }

           if (temp>dew)        //比对露点和实际温度
         {s_write_statusreg(0x00);}
           else
             {s_write_statusreg(0x04);}                        

       if (temp>=209)
                  { Relay5=0;
                     lcd_pos(4,0);
                     for(i1=0;i1<4;i1++)
               {
                        lcd_wdat(DIS4);
                  Delay_xms(30);
                  }
                   }
           if (temp<=201)
                  { Relay5=1;
                     lcd_pos(4,0);
                     lcd_wdat(DIS7);
                       lcd_pos(4,1);
                     lcd_wdat(DIS7);
                       lcd_pos(4,2);
                     lcd_wdat(DIS7);
                       lcd_pos(4,3);
                     lcd_wdat(DIS7);
             Delay_xms(30);
                  }
                   }
           if (temp>=200)
                  { Relay6=1;
                       if (Relay5!=0)
                     {
                       lcd_pos(4,0);
                     lcd_wdat(DIS7);
                       lcd_pos(4,1);
                     lcd_wdat(DIS7);
                       lcd_pos(4,2);
                     lcd_wdat(DIS7);
                       lcd_pos(4,3);
                     lcd_wdat(DIS7);
             Delay_xms(30);
                               }
                   }

           if (temp<=192)
                  { Relay6=0;
                     lcd_pos(4,0);
                          for(i1=0;i1<4;i1++)
               {
                        lcd_wdat(DIS5);
                  Delay_xms(30);
                  }
                  
                   }

           if ((temp<230)&&(humi<900))
             { Relay7=0;
                     lcd_pos(4,8);
                          for(i1=0;i1<4;i1++)
               {
                        lcd_wdat(DIS6);
                  Delay_xms(30);
                  }
                   }
           if ((temp>=230)&&(humi>960))
             { Relay7=1;
                     lcd_pos(4,8);
                     lcd_wdat(DIS7);
                       lcd_pos(4,9);
                     lcd_wdat(DIS7);
                       lcd_pos(4,10);
                     lcd_wdat(DIS7);
                       lcd_pos(4,11);
                     lcd_wdat(DIS7);
             Delay_xms(30);
                   }
   }
    }
/*********************************************************/




Randy 发表于 2012-10-26 09:13:34

51单片机控制的!来一个Arduino控制的!
页: [1]
查看完整版本: 基于SHT11的温湿度测控系统的设计