找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 9473|回复: 0
打印 上一主题 下一主题
收起左侧

DHT11的原理图及单片机程序(带中文注释,1602液晶显示)

[复制链接]
跳转到指定楼层
楼主
电路原理图如下:

  1. #include <reg52.h>                      // 头文件包含
  2. #include <intrins.h>
  3. #define uchar unsigned char   // 以后unsigned char就可以用uchar代替
  4. #define uint  unsigned int     //以后unsigned int就可以用uint 代替
  5. sfr ISP_DATA  = 0xe2;         // 数据寄存器
  6. sfr ISP_ADDRH = 0xe3;        // 地址寄存器高八位
  7. sfr ISP_ADDRL = 0xe4;                 //地址寄存器低八位
  8. sfr ISP_CMD   = 0xe5;        //命令寄存器
  9. sfr ISP_TRIG  = 0xe6;         // 命令触发寄存器
  10. sfr ISP_CONTR = 0xe7;                //命令寄存器
  11. sbit LcdRs_P   = P1^2;        //1602液晶的RS管脚      
  12. sbit LcdRw_P   = P1^3;      //1602液晶的RW管脚
  13. sbit LcdEn_P   = P1^4;       //1602液晶的EN管脚
  14. sbit DHT11_P   = P1^0;       //温湿度传感器DHT11数据接入
  15. sbit LedTL_P   = P3^4;        //温度过低报警指示灯
  16. sbit LedTH_P   = P3^5;       //温度过高报警指示灯
  17. sbit LedHL_P   = P3^6;        //湿度过低报警指示灯
  18. sbit LedHH_P   = P3^7;       //湿度过高报警指示灯
  19. sbit Buzzer_P  = P1^1;     // 蜂鸣器
  20. sbit KeySet_P  = P1^5;         // “设置”按键的管脚
  21. sbit KeyDown_P = P1^6;       // “减”按键的管脚
  22. sbit KeyUp_P   = P1^7;       //“加”按键的管脚
  23. uchar temp;                             // 保存温度
  24. uchar humi;                             // 保存湿度
  25. uchar AlarmTL;                       // 温度下限报警值
  26. uchar AlarmTH;                      // 温度上限报警值
  27. uchar AlarmHL;                     // 湿度下限报警值
  28. uchar AlarmHH;                      // 湿度上限报警值
  29. /*********************************************************/
  30. // 单片机内部EEPROM不使能
  31. /*********************************************************/
  32. void ISP_Disable()
  33. {
  34.         ISP_CONTR= 0;
  35.         ISP_ADDRH= 0;
  36.         ISP_ADDRL= 0;
  37. }
  38. /*********************************************************/
  39. // 从单片机内部EEPROM读一个字节,从0x2000地址开始
  40. /*********************************************************/
  41. unsigned char EEPROM_Read(unsigned int add)
  42. {
  43.         ISP_DATA  = 0x00;
  44.         ISP_CONTR= 0x83;
  45.         ISP_CMD   = 0x01;
  46.         ISP_ADDRH= (unsigned char)(add>>8);
  47.         ISP_ADDRL= (unsigned char)(add&0xff);
  48.         //对STC89C51系列来说,每次要写入0x46,再写入0xB9,ISP/IAP才会生效
  49.         ISP_TRIG  = 0x46;         
  50.         ISP_TRIG  = 0xB9;
  51.         _nop_();
  52.         ISP_Disable();
  53.         return(ISP_DATA);
  54. }
  55. /*********************************************************/
  56. // 往单片机内部EEPROM写一个字节,从0x2000地址开始
  57. /*********************************************************/
  58. void EEPROM_Write(unsigned int add,unsignedchar ch)
  59. {
  60.         ISP_CONTR= 0x83;
  61.         ISP_CMD   = 0x02;
  62.         ISP_ADDRH= (unsigned char)(add>>8);
  63.         ISP_ADDRL= (unsigned char)(add&0xff);
  64.         ISP_DATA  = ch;
  65.         ISP_TRIG  = 0x46;
  66.         ISP_TRIG  = 0xB9;
  67.         _nop_();
  68.         ISP_Disable();
  69. }
  70. /*********************************************************/
  71. // 擦除单片机内部EEPROM的一个扇区
  72. // 写8个扇区中随便一个的地址,便擦除该扇区,写入前要先擦除
  73. /*********************************************************/
  74. void Sector_Erase(unsigned int add)      
  75. {
  76.         ISP_CONTR= 0x83;
  77.         ISP_CMD   = 0x03;
  78.         ISP_ADDRH= (unsigned char)(add>>8);
  79.         ISP_ADDRL= (unsigned char)(add&0xff);
  80.         ISP_TRIG  = 0x46;
  81.         ISP_TRIG  = 0xB9;
  82.         _nop_();
  83.         ISP_Disable();
  84. }
  85. /*********************************************************/
  86. // 毫秒级的延时函数,time是要延时的毫秒数
  87. /*********************************************************/
  88. void DelayMs(uint time)
  89. {
  90.         uinti,j;
  91.         for(i=0;i<time;i++)
  92.                 for(j=0;j<112;j++);
  93. }
  94. /*********************************************************/
  95. // 1602液晶写命令函数,cmd就是要写入的命令
  96. /*********************************************************/
  97. void LcdWriteCmd(uchar cmd)
  98. {
  99.    LcdRs_P = 0;
  100.    LcdRw_P = 0;
  101.    LcdEn_P = 0;
  102.    P0=cmd;
  103.         DelayMs(2);
  104.    LcdEn_P = 1;   
  105.         DelayMs(2);
  106.    LcdEn_P = 0;  
  107. }
  108. /*********************************************************/
  109. // 1602液晶写数据函数,dat就是要写入的命令
  110. /*********************************************************/
  111. void LcdWriteData(uchar dat)
  112. {
  113.    LcdRs_P = 1;
  114.    LcdRw_P = 0;
  115.    LcdEn_P = 0;
  116.      P0=dat;
  117.         DelayMs(2);
  118.    LcdEn_P = 1;   
  119.         DelayMs(2);
  120.    LcdEn_P = 0;
  121. }
  122. /*********************************************************/
  123. // 1602液晶初始化函数
  124. /*********************************************************/
  125. void LcdInit()
  126. {
  127.    LcdWriteCmd(0x38);        // 16*2显示,5*7点阵,8位数据口
  128.    LcdWriteCmd(0x0C);        // 开显示,不显示光标
  129.    LcdWriteCmd(0x06);        // 地址加1,当写入数据后光标右移
  130.    LcdWriteCmd(0x01);        // 清屏
  131. }
  132. /*********************************************************/
  133. // 液晶光标定位函数
  134. /*********************************************************/
  135. void LcdGotoXY(uchar line,uchar column)
  136. {
  137.         //第一行
  138.     if(line==0)        
  139.        LcdWriteCmd(0x80+column);
  140.         //第二行
  141.    if(line==1)        
  142.        LcdWriteCmd(0x80+0x40+column);
  143. }
  144. /*********************************************************/
  145. // 液晶输出字符串函数
  146. /*********************************************************/
  147. void LcdPrintStr(uchar *str)
  148. {
  149.    while(*str!='\0')                      //判断是否到字符串的尽头了
  150.        LcdWriteData(*str++);
  151. }
  152. /*********************************************************/
  153. // 液晶输出数字
  154. /*********************************************************/
  155. void LcdPrintNum(uchar num)
  156. {
  157.         LcdWriteData(num/10+48);   // 十位
  158.         LcdWriteData(num%10+48);       // 个位
  159. }
  160. /*********************************************************/
  161. // 液晶显示内容的初始化
  162. /*********************************************************/
  163. void LcdShowInit()
  164. {
  165.         LcdGotoXY(0,0);                                                   // 第0行的显示内容
  166.         LcdPrintStr("  DHT11 System ");
  167.         LcdGotoXY(1,0);                                                // 第1行的显示内容
  168.         LcdPrintStr("T:   C  H:  %RH");
  169.         LcdGotoXY(1,4);                                                   // 温度单位摄氏度上面的圆圈符号
  170.         LcdWriteData(0xdf);      
  171. }
  172. /*********************************************************/
  173. // 10us级延时程序
  174. /*********************************************************/
  175. void Delay10us()
  176. {
  177.         _nop_();  // 执行一条指令,延时1微秒
  178.         _nop_();
  179.         _nop_();
  180.         _nop_();
  181.         _nop_();
  182.         _nop_();
  183.         _nop_();
  184.         _nop_();
  185.         _nop_();
  186.         _nop_();
  187. }
  188. /*********************************************************/
  189. // 读取DHT11单总线上的一个字节
  190. /*********************************************************/
  191. uchar DhtReadByte(void)
  192. {   
  193.         bitbit_i;
  194.         ucharj;
  195.         uchardat=0;
  196.         for(j=0;j<8;j++)   
  197.         {
  198.                 while(!DHT11_P); // 等待低电平结束        
  199.                 Delay10us();           // 延时
  200.                 Delay10us();
  201.                 Delay10us();
  202.                 if(DHT11_P==1)            // 判断数据线是高电平还是低电平
  203.                 {
  204.                         bit_i=1;
  205.                         while(DHT11_P);
  206.                 }
  207.                 else
  208.                 {
  209.                         bit_i=0;
  210.                 }
  211.                 dat<<=1;            // 将该位移位保存到dat变量中
  212.                 dat|=bit_i;   
  213.         }
  214.    return(dat);  
  215. }
  216. /*********************************************************/
  217. // 读取DHT11的一帧数据,湿高、湿低(0)、温高、温低(0)、校验码
  218. /*********************************************************/
  219. void ReadDhtData()
  220. {            
  221.         ucharHumiHig;              // 湿度高检测值
  222.         ucharHumiLow;          // 湿度低检测值
  223.         ucharTemHig;                        // 温度高检测值
  224.         ucharTemLow;               // 温度低检测值
  225.    uchar check;                    //校验字节
  226.         
  227.         DHT11_P=0;                  // 主机拉低20ms
  228.         DelayMs(20);
  229.         DHT11_P=1;                  // DATA总线由上拉电阻拉高主机延时40us           
  230.         Delay10us();                  // 延时等待30us
  231.         Delay10us();
  232.         Delay10us();
  233.         while(!DHT11_P);         //等待DHT的低电平结束
  234.         while(DHT11_P);           //等待DHT的高电平结束
  235.         //进入数据接收状态
  236.         HumiHig= DhtReadByte();          // 湿度高8位
  237.         HumiLow= DhtReadByte();         // 湿度低8为,总为0
  238.         TemHig  = DhtReadByte();          // 温度高8位
  239.         TemLow  = DhtReadByte();         // 温度低8为,总为0
  240.         check   = DhtReadByte();    // 8位校验码,其值等于读出的四个字节相加之和的低8位
  241.         DHT11_P=1;                                  // 拉高总线
  242.         if(check==HumiHig+ HumiLow + TemHig + TemLow)             // 如果收到的数据无误
  243.         {
  244.                 temp=TemHig;                       // 将温度的检测结果赋值给全局变量temp
  245.                 humi=HumiHig;                     // 将湿度的检测结果赋值给全局变量humi
  246.         }
  247. }
  248. /*********************************************************/
  249. // 是否需要报警判断
  250. /*********************************************************/
  251. void AlarmJudge(void)
  252. {
  253.         uchari;
  254.         if(temp>AlarmTH)                 // 温度是否过高
  255.         {
  256.                 LedTH_P=0;
  257.                 LedTL_P=1;
  258.         }
  259.         elseif(temp<AlarmTL)           // 温度是否过低
  260.         {
  261.                 LedTL_P=0;
  262.                 LedTH_P=1;
  263.         }
  264.         else                                          //温度正常
  265.         {
  266.                 LedTH_P=1;
  267.                 LedTL_P=1;
  268.         }
  269.         if(humi>AlarmHH)              //湿度是否过高
  270.         {
  271.                 LedHH_P=0;
  272.               LedHL_P=1;
  273.         }
  274.         elseif(humi<AlarmHL)          // 湿度是否过低
  275.         {
  276.                 LedHL_P=0;
  277.                 LedHH_P=1;
  278.         }
  279.         else                                       // 湿度正常
  280.         {
  281.                 LedHH_P=1;
  282.                 LedHL_P=1;
  283.         }
  284.         if((LedHH_P==0)||(LedHL_P==0)||(LedTH_P==0)||(LedTL_P==0))         // 蜂鸣器判断,只要至少1个报警灯亮,蜂鸣器就报警
  285.         {
  286.                 for(i=0;i<3;i++)
  287.                 {
  288.                         Buzzer_P=0;
  289.                         DelayMs(100);
  290.                         Buzzer_P=1;
  291.                         DelayMs(100);
  292.                 }
  293.         }
  294. }
  295. /*********************************************************/
  296. // 按键扫描,用于设置温湿度报警范围
  297. /*********************************************************/
  298. void KeyScanf()
  299. {
  300.         if(KeySet_P==0)            //判断设置按键是否被按下
  301.         {
  302.                 /*将液晶显示改为设置页面的************************************/
  303.                 LcdWriteCmd(0x01);                                   // 设置界面的显示框架
  304.                 LcdGotoXY(0,0);
  305.                 LcdPrintStr("Temp:   -      ");
  306.                 LcdGotoXY(1,0);
  307.                 LcdPrintStr("Humi:   -      ");
  308.                
  309.                 LcdGotoXY(0,6);                                          //在液晶上填充温度的下限值        
  310.                 LcdPrintNum(AlarmTL);        
  311.                 LcdGotoXY(0,9);                                          //在液晶上填充温度的上限值
  312.                 LcdPrintNum(AlarmTH);
  313.                 LcdGotoXY(1,6);                                          //在液晶上填充湿度的下限值
  314.                 LcdPrintNum(AlarmHL);      
  315.                 LcdGotoXY(1,9);                                         // 在液晶上填充湿度的上限值
  316.                 LcdPrintNum(AlarmHH);
  317.                 LcdGotoXY(0,7);                                          //光标定位到第0行第7列
  318.                 LcdWriteCmd(0x0F);                                     // 光标闪烁
  319.                
  320.                 DelayMs(10);                                        // 去除按键按下的抖动
  321.                 while(!KeySet_P);                                 // 等待按键释放
  322.                 DelayMs(10);                                        // 去除按键松开的抖动
  323.                 /*设置温度的下限值************************************//
  324.                 while(KeySet_P)             // “设置键”没有被按下,则一直处于温度下限的设置
  325.                 {
  326.                         if(KeyDown_P==0)                                //判断 “减按键“是否被按下               
  327.                         {
  328.                                 if(AlarmTL>0)                                //只有当温度下限值大于0时,才能减1
  329.                                         AlarmTL--;
  330.                                 LcdGotoXY(0,6);                          //重新刷新显示更改后的温度下限值   
  331.                                 LcdPrintNum(AlarmTL);              
  332.                                 LcdGotoXY(0,7);                           //重新定位闪烁的光标位置
  333.                                 DelayMs(350);                                //延时
  334.                         }
  335.                         if(KeyUp_P==0)                                   //判断 “加按键“是否被按下
  336.                         {
  337.                                 if(AlarmTL<99)                         // 只有当温度下限值小于99时,才能加1
  338.                                         AlarmTL++;
  339.                                 LcdGotoXY(0,6);                         // 重新刷新显示更改后的温度下限值
  340.                                 LcdPrintNum(AlarmTL);
  341.                                 LcdGotoXY(0,7);                           //重新定位闪烁的光标位置
  342.                                 DelayMs(350);                                //延时
  343.                         }      
  344.                 }
  345.                 LcdGotoXY(0,10);
  346.                 DelayMs(10);                                        // 去除按键按下的抖动
  347.                 while(!KeySet_P);                                 // 等待按键释放
  348.                 DelayMs(10);                                        // 去除按键松开的抖动
  349.                 /*设置温度的上限值************************************//
  350.                                 
  351.                 while(KeySet_P)           // “设置键”没有被按下,则一直处于温度上限的设置
  352.                 {
  353.                         if(KeyDown_P==0)                                //判断 “减按键“是否被按下
  354.                         {
  355.                                 if(AlarmTH>0)                             // 只有当温度上限值大于0时,才能减1                 
  356.                                         AlarmTH--;
  357.                                 LcdGotoXY(0,9);                        // 重新刷新显示更改后的温度上限值
  358.                                 LcdPrintNum(AlarmTH);
  359.                                 LcdGotoXY(0,10);                 // 重新定位闪烁的光标位置
  360.                                 DelayMs(350);                                //延时
  361.                         }
  362.                         if(KeyUp_P==0)                                 //判断 “加按键“是否被按下
  363.                         {
  364.                                 if(AlarmTH<99)                          //只有当温度上限值小于99时,才能加1
  365.                                         AlarmTH++;
  366.                                 LcdGotoXY(0,9);                           //重新刷新显示更改后的温度上限值   
  367.                                 LcdPrintNum(AlarmTH);
  368.                                 LcdGotoXY(0,10);                 // 重新定位闪烁的光标位置
  369.                                 DelayMs(350);                                //延时
  370.                         }                                                              
  371.                 }
  372.                 LcdGotoXY(1,7);
  373.                 DelayMs(10);                                        // 去除按键按下的抖动
  374.                 while(!KeySet_P);                                 // 等待按键释放
  375.                 DelayMs(10);                                        // 去除按键松开的抖动
  376.                
  377.                 /*设置湿度的下限值************************************//
  378.                 while(KeySet_P)             // “设置键”没有被按下,则一直处于湿度下限的设置
  379.                 {
  380.                         if(KeyDown_P==0)                                //判断 “减按键“是否被按下
  381.                         {
  382.                                 if(AlarmHL>0)                               //只有当湿度下限值大于0时,才能减1
  383.                                         AlarmHL--;
  384.                                 LcdGotoXY(1,6);                           //重新刷新显示更改后的湿度下限值   
  385.                                 LcdPrintNum(AlarmHL);
  386.                                 LcdGotoXY(1,7);                           //重新定位闪烁的光标位置
  387.                                 DelayMs(350);
  388.                         }
  389.                         if(KeyUp_P==0)                                   //判断 “加按键“是否被按下
  390.                         {
  391.                                 if(AlarmHL<99)                         // 只有当湿度下限值小于99时,才能加1
  392.                                         AlarmHL++;
  393.                                 LcdGotoXY(1,6);                         // 重新刷新显示更改后的湿度下限值
  394.                                 LcdPrintNum(AlarmHL);
  395.                                 LcdGotoXY(1,7);                         // 重新定位闪烁的光标位置
  396.                                 DelayMs(350);                                //延时
  397.                         }      
  398.                 }
  399.                 LcdGotoXY(1,10);
  400.                 DelayMs(10);                                        // 去除按键按下的抖动
  401.                 while(!KeySet_P);                                 // 等待按键释放
  402.                 DelayMs(10);                                        // 去除按键松开的抖动
  403.                
  404.                 /*设置湿度的上限值************************************//
  405.                 while(KeySet_P)             // “设置键”没有被按下,则一直处于湿度上限的设置
  406.                 {
  407.                         if(KeyDown_P==0)                              //判断 “减按键“是否被按下
  408.                         {
  409.                                 if(AlarmHH>0)                             // 只有当湿度上限值大于0时,才能减1
  410.                                         AlarmHH--;
  411.                                 LcdGotoXY(1,9);                         // 重新刷新显示更改后的湿度上限值
  412.                                 LcdPrintNum(AlarmHH);
  413.                                 LcdGotoXY(1,10);              // 重新定位闪烁的光标位置
  414.                                 DelayMs(350);
  415.                         }
  416.                         if(KeyUp_P==0)                                   // 判断“加按键“ 是否被按下
  417.                         {
  418.                                 if(AlarmHH<99)                           //只有当湿度上限值小于99时,才能加1
  419.                                         AlarmHH++;
  420.                                 LcdGotoXY(1,9);                          //重新刷新显示更改后的湿度上限值   
  421.                                 LcdPrintNum(AlarmHH);
  422.                                 LcdGotoXY(1,10);                // 重新定位闪烁的光标位置
  423.                                 DelayMs(350);                                //延时
  424.                         }      
  425.                 }
  426.                 LcdWriteCmd(0x0C);                                   //取消光标闪烁
  427.                 LcdShowInit();                                               //液晶显示为检测界面的
  428.                 DelayMs(10);                                        // 去除按键按下的抖动
  429.                 while(!KeySet_P);                                 // 等待按键释放
  430.                 DelayMs(10);                                        // 去除按键松开的抖动
  431.                 Sector_Erase(0x2000);                          //存储之前必须先擦除
  432.                 EEPROM_Write(0x2000,AlarmTL);             //把温度下限存入到EEPROM的0x2000这个地址
  433.                 EEPROM_Write(0x2001,AlarmTH);            //把温度上限存入到EEPROM的0x2001这个地址
  434.                 EEPROM_Write(0x2002,AlarmHL);            //把湿度下限存入到EEPROM的0x2002这个地址
  435.                 EEPROM_Write(0x2003,AlarmHH);            //把湿度上限存入到EEPROM的0x2003这个地址
  436.         }      
  437. }
  438. /*********************************************************/
  439. // 主函数
  440. /*********************************************************/
  441. void main()
  442. {
  443.         uchari;
  444.         LcdInit();                                         //液晶功能的初始化                    
  445.         LcdShowInit();                                     // 液晶显示的初始化
  446.         AlarmTL=EEPROM_Read(0x2000);    // 从EEPROM的0x2000这个地址读取温度的报警下限
  447.         AlarmTH=EEPROM_Read(0x2001);   // 从EEPROM的0x2001这个地址读取温度的报警上限
  448.         AlarmHL=EEPROM_Read(0x2002);    // 从EEPROM的0x2002这个地址读取湿度的报警下限   
  449.         AlarmHH=EEPROM_Read(0x2003);   // 从EEPROM的0x2003这个地址读取湿度的报警上限
  450.         while(1)
  451.         {
  452.                 ReadDhtData();                              //检测温湿度数据
  453.                 LcdGotoXY(1,2);                          //定位到要显示温度的地方
  454.                 LcdPrintNum(temp);                    // 显示温度值
  455.                 LcdGotoXY(1,11);                 // 定位到要显示湿度的地方
  456.                 LcdPrintNum(humi);                      // 显示湿度值
  457.                
  458.                 AlarmJudge();                         // 判断并根据需要报警
  459.                 for(i=0;i<25;i++)
  460.                 {
  461.                         KeyScanf();                                     // 按键扫描
  462.                         DelayMs(20);                          //延时   
  463.                 }
  464.         }
  465. }
复制代码


评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏2 分享淘帖 顶 踩
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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