找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 5901|回复: 0
收起左侧

DHT90温湿度实时显示单片机小系统详解

[复制链接]
ID:161768 发表于 2017-4-23 16:59 | 显示全部楼层 |阅读模式
1.003.jpg
数据类型
长 度
值 域
unsigned char
单字节
0~255
signed char
单字节
-128~+127
unsigned int
双字节
0~65535
signed int
双字节
-32768~+32767
unsigned long
四字节
0~4294967295
signed long
四字节
-2147483648~+2147483647
float
四字节
±1.175494E-38~±3.402823E+38
*
1~3字节
对象的地址
bit
0或1
sfr
单字节
0~255
sfr16
双字节
0~65535
sbit
0或1

一、        目的与要求
制作一个温湿度实时显示小系统,响应时间控制在1s左右,探头部分能够放进大约10cm直径的容器中。
二、        工作原理
采用AT89S52单片机作为本系统的控制单元,传感器采用DHT90(即把SHT10封装为4个2.54标准插针的独立结构,大连北方测控代理的价格为50元/片),显示模块为LCD1602。单片机收到来自DHT90的温湿度数据,再经过软件线性拟合,最后送到1602上显示并没隔1s刷新一次数据。
三、        原理图
1.001.jpg
图1 温湿度显示系统原理图


四、        硬件设计
电源部分采用+5V开关电源集成模块(实测输出电压5.19V),这符合DHT90和AT89S52单片机的供电要求。本系统电路设计较简单,难点至于软件编写与调试。
五、        软件设计
5.1 流程图
1.002.jpg
软件流程图

  5.2 软件调试过程及经验
    对于本系统,我首先调试1602的显示程序,重点理解时序图。对硬件理解清楚后,参照相关程序,编写自己规范的程序。然后,调试DHT90数据通信显示,在SHT11(DHT90/SHT10也属于同系列)例程中,显示功能是利用51单片机串口向上位机发数据,在上位机上显示温湿度。所以,这部分在我的程序中就去掉了。同样,DHT90程序部分的关键也是时序图,读明白时序图,就可以很快得进入编程调试阶段。
六、        系统实物图

图2 单片机控制及显示部分
1.004.jpg
图3 LCD1602显示特写
1.005.jpg
图4 传感器部分特写(准备封装为一个小的探头)

七、        菜鸟的小结
在两个多月的时间里,我从零开始做这个温湿度测量小系统,现在终于有了初步的成果。在这期间,我学到了很多东西,比如说焊接技术(当然还是比较菜),下载线制作等等。我觉得最重要的一点是锻炼了自己的实践能力。嗯,很多东西难与不难就看你做没做过。呵呵,套用毛主席他老人家的一句话就是:没有实践就没有发言权。一开始,做下载线,我感觉很难很难,但现在回头一看,那就是小case而已。
通过这个小系统的制作,我从一个“理想的电子爱好者”转变为一个“实践的电子爱好者”。从享受电子成品的快乐到享受电子DIY过程的快乐,这是一直升华,DIY很美妙。最后一句与所有DIY爱好者共勉。
最后,欢迎大家交流学习,给我批评指正!


附源程序(调试成功版):


  1. /***********************************************************************************  
  2. ;功能说明:DHT90与LCD1602的温湿度显示  
  3. ;文件名称:DHT90.c     
  4.   
  5. ;微处理器:AT89S52
  6. ;编译环境:Keil uVision V2.38a
  7.   
  8. ;作    者:
  9. ;版    权:(c)
  10. ;修改说明:添加了一个LCD_disp_str()函数
  11. ;***********************************************************************************/

  12. /*************定义接口********************
  13.          P0------DB0~DB7  (LCD1602)      
  14.          P2.0------RS      (LCD1602)
  15.          P2.1------RW      (LCD1602)
  16.          P2.2------E       (LCD1602)
  17.                  P2.6------SCK     (DHT90)
  18.                  P2.7------DATA    (DHT90)
  19. *****************************************/

  20. #include  
  21. #include   
  22. #include     //Keil library   
  23. #include    //Keil library  

  24. //*********************第一部分LCD1602设置 START****************************************
  25. #define LCD_DB        P0
  26.         sbit         LCD_RS=P2^0;   //P2^0是p2.0的意思;LCD_RS与P2.0等效起来,对LCD_RS 读写,就是对P2.0读写 好处在于LCD_RS含义直接明了,写程序多了就会知道有必要de
  27.         sbit         LCD_RW=P2^1;   //P2^1是p2.1的意思
  28.         sbit         LCD_E=P2^2;    //P2^2是p2.2的意思

  29. /******定义函数****************/
  30. #define uchar unsigned char
  31. #define uint unsigned int
  32. void LCD_init(void);                          //初始化函数
  33. void LCD_write_command(uchar command);        //写指令函数
  34. void LCD_write_data(uchar dat);               //写数据函数
  35. void LCD_disp_char(uchar x,uchar y,uchar dat);//在某个屏幕位置上显示一个字符,X(0-15),y(1-2)
  36. void LCD_disp_str(uchar x,uchar y,uchar *str); //LCD1602显示字符串函数
  37. void delay_n10us(uint n);                     //延时函数


  38. /*--------------------------------------  
  39. ;模块名称:LCD_init();  
  40. ;功    能:初始化LCD1602  
  41. ;占用资源:--
  42. ;参数说明:--
  43. ;创建日期:2008.08.15  
  44. ;版    本:FV1.0(函数版本Function Version)
  45. ;修改日期:--
  46. ;修改说明:--
  47. ;-------------------------------------*/  
  48. void LCD_init(void)
  49. {
  50. delay_n10us(10);
  51. LCD_write_command(0x38);//设置8位格式,2行,5x7
  52. delay_n10us(10);
  53. LCD_write_command(0x0c);//整体显示,关光标,不闪烁
  54. delay_n10us(10);
  55. LCD_write_command(0x06);//设定输入方式,增量不移位
  56. delay_n10us(10);
  57. LCD_write_command(0x01);//清除屏幕显示
  58. delay_n10us(100);       //延时清屏,延时函数,延时约n个10us
  59. }


  60. /*--------------------------------------  
  61. ;模块名称:LCD_write_command();  
  62. ;功    能:LCD1602写指令函数  
  63. ;占用资源: P2.0--RS(LCD_RS),P2.1--RW(LCD_RW),P2.2--E(LCD_E).
  64. ;参数说明:dat为写命令参数
  65. ;创建日期:2008.08.15  
  66. ;版    本:FV1.0(函数版本Function Version)
  67. ;修改日期:--
  68. ;修改说明:--
  69. ;-------------------------------------*/  
  70. void LCD_write_command(uchar dat)
  71. {
  72. delay_n10us(10);
  73. LCD_RS=0;         //指令
  74. LCD_RW=0;         //写入
  75. LCD_E=1;          //允许
  76. LCD_DB=dat;
  77. delay_n10us(10);  //实践证明,我的LCD1602上,用for循环1次就能完成普通写指令。
  78. LCD_E=0;
  79. delay_n10us(10);  //实践证明,我的LCD1602上,用for循环1次就能完成普通写指令。
  80. }


  81. /*--------------------------------------  
  82. ;模块名称:LCD_write_data();  
  83. ;功    能:LCD1602写数据函数  
  84. ;占用资源: P2.0--RS(LCD_RS),P2.1--RW(LCD_RW),P2.2--E(LCD_E).
  85. ;参数说明:dat为写数据参数
  86. ;创建日期:2008.08.15  
  87. ;版    本:FV1.0(函数版本Function Version)
  88. ;修改日期:--
  89. ;修改说明:--
  90. ;-------------------------------------*/
  91. void LCD_write_data(uchar dat)
  92. {
  93. delay_n10us(10);
  94. LCD_RS=1;          //数据
  95. LCD_RW=0;          //写入
  96. LCD_E=1;           //允许
  97. LCD_DB=dat;
  98. delay_n10us(10);
  99. LCD_E=0;
  100. delay_n10us(10);
  101. }


  102. /*--------------------------------------  
  103. ;模块名称:LCD_disp_char();  
  104. ;功    能:LCD1602显示一个字符函数,在某个屏幕位置上显示一个字符,X(0-15),y(1-2)。
  105. ;占用资源:--
  106. ;参数说明:X为1602的列值(取值范围是0-15),y为1602的行值(取值范围是1-2),dat为所要显示字符对应的地址参数。
  107. ;创建日期:2008.08.15  
  108. ;版    本:FV1.0(函数版本Function Version)
  109. ;修改日期:--
  110. ;修改说明:--
  111. ;-------------------------------------*/
  112. void LCD_disp_char(uchar x,uchar y,uchar dat)
  113. {
  114.   uchar address;
  115.   if(y==1)
  116.          address=0x80+x;
  117.   else
  118.          address=0xc0+x;
  119.   LCD_write_command(address);
  120.   LCD_write_data(dat);
  121. }



  122. /*--------------------------------------  
  123. ;模块名称:LCD_disp_str();  
  124. ;功    能:LCD1602显示字符串函数,在某个屏幕起始位置{X(0-15),y(1-2)}上显示一个字符串。
  125. ;占用资源:--
  126. ;参数说明:X为1602的列值(取值范围是0-15),y为1602的行值(取值范围是1-2),str为所要显示字符串对应的指针参数。
  127. ;创建日期:2008.08.16  
  128. ;版    本:FV1.0(函数版本Function Version)
  129. ;修改日期:--
  130. ;修改说明:--  
  131. ;-------------------------------------*/
  132. void LCD_disp_str(uchar x,uchar y,uchar *str)
  133. {
  134.   uchar address;
  135.   if(y==1)
  136.          address=0x80+x;
  137.   else
  138.          address=0xc0+x;
  139.   LCD_write_command(address);
  140.   while(*str!='')
  141.   {  
  142.     LCD_write_data(*str);   
  143.     str++;
  144.   }
  145. }


  146. /*--------------------------------------  
  147. ;模块名称:delay_n10us();  
  148. ;功    能:延时函数,延时约n个10us
  149. ;占用资源:--
  150. ;参数说明:--
  151. ;创建日期:2008.08.15  
  152. ;版    本:FV1.1(函数版本Function Version)
  153. ;修改日期:2008.08.16
  154. ;修改说明:修改为较精确的延时函数
  155. ;-------------------------------------*/
  156. void delay_n10us(uint n)
  157. {        
  158.         uint i;            
  159.         for(i=n;i>0;i--)
  160.         {
  161.         _nop_();_nop_();_nop_();_nop_();_nop_();_nop_(); //延时10us@12M晶振
  162.                 }
  163. }                                    

  164. //*********************第一部分LCD1602设置 END****************************************


  165. //*********************第二部分DHT90设置   START****************************************  
  166. sbit SCK  = P2^6;      //定义通讯时钟端口
  167. sbit DATA = P2^7;      //定义通讯数据端口

  168. typedef union   
  169. { unsigned int i;      //定义了两个共用体
  170.   float f;  
  171. } value;  

  172. enum {TEMP,HUMI};      //TEMP=0,HUMI=1
  173.   

  174. #define noACK 0             //用于判断是否结束通讯
  175. #define ACK   1             //结束数据传输
  176.                             //adr  command  r/w  
  177. #define STATUS_REG_W 0x06   //000   0011    0  
  178. #define STATUS_REG_R 0x07   //000   0011    1  
  179. #define MEASURE_TEMP 0x03   //000   0001    1  
  180. #define MEASURE_HUMI 0x05   //000   0010    1  
  181. #define RESET        0x1e   //000   1111    0  

  182. /****************定义函数****************/
  183. void s_transstart(void);               //启动传输函数
  184. void s_connectionreset(void);          //连接复位函数
  185. char s_write_byte(unsigned char value);//DHT90写函数
  186. char s_read_byte(unsigned char ack);   //DHT90读函数
  187. char s_measure(unsigned char *p_value, unsigned char *p_checksum, unsigned char mode);//测量温湿度函数
  188. void calc_dht90(float *p_humidity ,float *p_temperature);//温湿度补偿



  189. /*--------------------------------------  
  190. ;模块名称:s_transstart();  
  191. ;功    能:启动传输函数
  192. ;占用资源:--
  193. ;参数说明:--
  194. ;创建日期:2008.08.15  
  195. ;版    本:FV1.0(函数版本Function Version)
  196. ;修改日期:--
  197. ;修改说明:--
  198. ;-------------------------------------*/   
  199. void s_transstart(void)  
  200. // generates a transmission start   
  201. //       _____         ________  
  202. // DATA:      |_______|  
  203. //           ___     ___  
  204. // SCK : ___|   |___|   |______  
  205. {   
  206.    DATA=1; SCK=0;                   //Initial state  
  207.    _nop_();  
  208.    SCK=1;  
  209.    _nop_();  
  210.    DATA=0;  
  211.    _nop_();  
  212.    SCK=0;   
  213.    _nop_();_nop_();_nop_();  
  214.    SCK=1;  
  215.    _nop_();  
  216.    DATA=1;         
  217.    _nop_();  
  218.    SCK=0;         
  219. }  

  220. /*--------------------------------------  
  221. ;模块名称:s_connectionreset();  
  222. ;功    能:连接复位函数
  223. ;占用资源:--
  224. ;参数说明:--
  225. ;创建日期:2008.08.15  
  226. ;版    本:FV1.0(函数版本Function Version)
  227. ;修改日期:--
  228. ;修改说明:--
  229. ;-------------------------------------*/  
  230. void s_connectionreset(void)  
  231. // communication reset: DATA-line=1 and at least 9 SCK cycles followed by transstart  
  232. //       _____________________________________________________         ________  
  233. // DATA:                                                      |_______|  
  234. //          _    _    _    _    _    _    _    _    _        ___     ___  
  235. // SCK : __| |__| |__| |__| |__| |__| |__| |__| |__| |______|   |___|   |______  
  236. {   
  237.   unsigned char i;   
  238.   DATA=1; SCK=0;                    //Initial state  
  239.   for(i=0;i<9;i++)                  //9 SCK cycles  
  240.   {  
  241.     SCK=1;
  242.     SCK=0;  
  243.   }  
  244.   s_transstart();                   //transmission start  
  245. }  


  246. /*--------------------------------------  
  247. ;模块名称:s_write_byte();  
  248. ;功    能:DHT90写函数
  249. ;占用资源:--
  250. ;参数说明:--
  251. ;创建日期:2008.08.15  
  252. ;版    本:FV1.0(函数版本Function Version)
  253. ;修改日期:--
  254. ;修改说明:--
  255. ;-------------------------------------*/  
  256. char s_write_byte(unsigned char value)  
  257. //----------------------------------------------------------------------------------  
  258. // writes a byte on the Sensibus and checks the acknowledge   
  259. {   
  260.   unsigned char i,error=0;   
  261.   for (i=0x80;i>0;i/=2)             //shift bit for masking  
  262.   {   
  263.     if (i & value) DATA=1;          //masking value with i , write to SENSI-BUS  
  264.     else DATA=0;                          
  265.     SCK=1;                          //clk for SENSI-BUS  
  266.     _nop_();_nop_();_nop_();        //pulswith approx. 5 us      
  267.     SCK=0;  
  268.   }  
  269.   DATA=1;                           //release DATA-line  
  270.   SCK=1;                            //clk #9 for ack   
  271.   error=DATA;                       //check ack (DATA will be pulled down by DHT90),DATA在第9个上升沿将被DHT90自动下拉为低电平。  
  272.   _nop_();_nop_();_nop_();
  273.   SCK=0;
  274.   DATA=1;                           //release DATA-line  
  275.   return error;                     //error=1 in case of no acknowledge //返回:0成功,1失败
  276. }  
  277.   

  278. /*--------------------------------------  
  279. ;模块名称:s_read_byte();  
  280. ;功    能:DHT90读函数
  281. ;占用资源:--
  282. ;参数说明:--
  283. ;创建日期:2008.08.15  
  284. ;版    本:FV1.0(函数版本Function Version)
  285. ;修改日期:--
  286. ;修改说明:--
  287. ;-------------------------------------*/  
  288. char s_read_byte(unsigned char ack)   
  289. // reads a byte form the Sensibus and gives an acknowledge in case of "ack=1"   
  290. {   
  291.   unsigned char i,val=0;  
  292.   DATA=1;                           //release DATA-line  
  293.   for (i=0x80;i>0;i/=2)             //shift bit for masking  
  294.   { SCK=1;                          //clk for SENSI-BUS  
  295.     if (DATA) val=(val | i);        //read bit   
  296.         _nop_();_nop_();_nop_();        //pulswith approx. 5 us
  297.     SCK=0;               
  298.   }  
  299.   if(ack==1)DATA=0;                 //in case of "ack==1" pull down DATA-Line  
  300.   else DATA=1;                      //如果是校验(ack==0),读取完后结束通讯
  301.   _nop_();_nop_();_nop_();          //pulswith approx. 5 us  
  302.   SCK=1;                            //clk #9 for ack  
  303.   _nop_();_nop_();_nop_();          //pulswith approx. 5 us   
  304.   SCK=0;                  
  305.   _nop_();_nop_();_nop_();          //pulswith approx. 5 us  
  306.   DATA=1;                           //release DATA-line  
  307.   return val;  
  308. }  
  309.   

  310.   

  311. /*--------------------------------------  
  312. ;模块名称:s_measure();  
  313. ;功    能:测量温湿度函数
  314. ;占用资源:--
  315. ;参数说明:--
  316. ;创建日期:2008.08.15  
  317. ;版    本:FV1.0(函数版本Function Version)
  318. ;修改日期:--
  319. ;修改说明:--
  320. ;-------------------------------------*/  
  321. char s_measure(unsigned char *p_value, unsigned char *p_checksum, unsigned char mode)  
  322. // makes a measurement (humidity/temperature) with checksum  
  323. {   
  324.   unsigned error=0;  
  325.   unsigned int i;  
  326.   
  327.   s_transstart();                   //transmission start  
  328.   switch(mode){                     //send command to sensor  
  329.     case TEMP  : error+=s_write_byte(MEASURE_TEMP); break;  
  330.     case HUMI  : error+=s_write_byte(MEASURE_HUMI); break;  
  331.     default     : break;     
  332.   }  
  333.   for (i=0;i<65535;i++) if(DATA==0) break; //wait until sensor has finished the measurement  
  334.   if(DATA) error+=1;                // or timeout (~2 sec.) is reached  
  335.   *(p_value)  =s_read_byte(ACK);    //read the first byte (MSB)  
  336.   *(p_value+1)=s_read_byte(ACK);    //read the second byte (LSB)  
  337.   *p_checksum =s_read_byte(noACK);  //read checksum  
  338.   return error;  
  339. }  
  340.   

  341. /*--------------------------------------  
  342. ;模块名称:calc_dht90();  
  343. ;功    能:温湿度补偿函数
  344. ;占用资源:--
  345. ;参数说明:--
  346. ;创建日期:2008.08.15  
  347. ;版    本:FV1.0(函数版本Function Version)
  348. ;修改日期:--
  349. ;修改说明:--
  350. ;-------------------------------------*/  
  351. void calc_dht90(float *p_humidity ,float *p_temperature)
  352. // calculates temperature [C] and humidity [%RH]  
  353. // input :  humi [Ticks] (12 bit)  
  354. //          temp [Ticks] (14 bit)
  355. // output:  humi [%RH]
  356. //          temp [C]
  357. { const float C1=-4.0;              // for 12 Bit
  358.   const float C2=+0.0405;           // for 12 Bit
  359.   const float C3=-0.0000028;        // for 12 Bit
  360.   const float T1=+0.01;             // for 14 Bit @ 5V
  361.   const float T2=+0.00008;           // for 14 Bit @ 5V  

  362.   float rh=*p_humidity;             // rh:      Humidity [Ticks] 12 Bit  
  363.   float t=*p_temperature;           // t:       Temperature [Ticks] 14 Bit
  364.   float rh_lin;                     // rh_lin:  Humidity linear
  365.   float rh_true;                    // rh_true: Temperature compensated humidity
  366.   float t_C;                        // t_C   :  Temperature [C]

  367.   t_C=t*0.01 - 40;                  //calc. temperature from ticks to [C]
  368.   rh_lin=C3*rh*rh + C2*rh + C1;     //calc. humidity from ticks to [%RH]
  369.   rh_true=(t_C-25)*(T1+T2*rh)+rh_lin;   //calc. temperature compensated humidity [%RH]
  370.   if(rh_true>100)rh_true=100;       //cut if the value is outside of
  371.   if(rh_true<0.1)rh_true=0.1;       //the physical possible range

  372.   *p_temperature=t_C;               //return temperature [C]
  373.   *p_humidity=rh_true;              //return humidity[%RH]
  374. }




  375. //*********************第二部分DHT90设置   END****************************************

  376. //*********主函数*****************
  377. void main(void)
  378. {
  379.                 value humi_val,temp_val;
  380.         unsigned char error,checksum;  
  381.         unsigned int wendu,shidu;
  382.         LCD_init();         
  383.         s_connectionreset();  
  384.         LCD_disp_str(0,1,"TE");
  385.                 LCD_disp_str(0,2,"RH");


  386. //*********初始化温度显示区*********
  387.         LCD_disp_str(2,1,"TTT.TC");

  388. //*********初始化湿度显示区*********
  389.         LCD_disp_str(2,2,"RRR.R%");

  390.         delay_n10us(20000);     //延时0.2s

  391.         while(1)  
  392.         { error=0;  
  393.           error+=s_measure((unsigned char*) &humi_val.i,&checksum,HUMI);  //measure humidity  
  394.           error+=s_measure((unsigned char*) &temp_val.i,&checksum,TEMP);  //measure temperature  
  395.           if(error!=0) s_connectionreset();                 //in case of an error: connection reset  
  396.           else  
  397.           { humi_val.f=(float)humi_val.i;                   //converts integer to float //加入温湿度比较程序
  398.             temp_val.f=(float)temp_val.i;                   //converts integer to float //比较输出控制信号
  399.             calc_dht90(&humi_val.f,&temp_val.f);            //calculate humidity, temperature
  400.                         wendu=10*temp_val.f;
  401.                         LCD_disp_char(2,1,wendu/1000+'0');              //显示温度百位
  402.             LCD_disp_char(3,1,(wendu%1000)/100+'0');        //显示温度十位
  403.             LCD_disp_char(4,1,(wendu%100)/10+'0');          //显示温度个位
  404.                         LCD_disp_char(6,1,(wendu%10)+'0');              //显示温度小数点后第一位

  405.                         shidu=10*humi_val.f;
  406.                         LCD_disp_char(2,2,shidu/1000+'0');               //显示湿度百位


  407. …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码


完整的资料下载(包含论文与代码):
http://www.51hei.com/bbs/dpj-82305-1.html

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表