找回密码
 立即注册

QQ登录

只需一步,快速开始

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

dht11和ds18b20温湿度控制 单片机程序

[复制链接]
跳转到指定楼层
楼主
基于51单片机,传感器使用dht11和ds18b20,dht11测温度精度有限,18b20可以弥补。第一行显示dht11采集到的湿度和温度,以及继电器状态。第二行显示18b20采集到温度和THI。THi是畜牧业衡量动物热应激指数的标准,不需要的删除掉。继电器是通过THI指数高低控制的。


单片机源程序如下:
  1. /*********************************************************************************************
  2. 程序名:    DHT11-1602
  3. 编写人:    fby
  4. 编写时间:  2019年3月21日
  5. 硬件支持:  STC89C52RC  DHT11  LCD1602
  6. 接口说明:  DHT11:VCC DATA NC GND
  7. *********************************************************************************************
  8. 说明:1、单片机是STC89C52RC,晶振频率11.0592MHz,实验成功。
  9.           2、好东西要共享,大家随意折腾~~
  10. *********************************************************************************************/
  11. #include "reg52.h"
  12. #include<intrins.h>  //此文件中定义了单片机的一些特殊功能寄存器
  13. #include<stdio.h>
  14. #include"temp.h"       

  15.                          


  16. #define uchar unsigned char        //无符号字符型类型数据
  17. #define uint unsigned int //无符号整型数据
  18.         #define ulong unsigned long //无符号整型数据
  19.         #define xiao float //xiaoshu
  20. #define IODATA  P0
  21.        

  22. uchar dat_r[10];          //用于存放从DHT11读取到的数值
  23.           uchar sData[10];

  24. sbit DATA=P2^0;   //定义数据线
  25. sbit RS=P2^6; //定义rs端口
  26. sbit RW=P2^5; //定义rw端口
  27. sbit E=P2^7;
  28.           sbit jidian=P3^7;  //定义继电器
  29.        
  30.         static uint i;
  31.         extern uint zheng;

  32.        
  33.        
  34.        


  35.              
  36. void delay200ms(void)   //误差 0us
  37. {
  38.     unsigned char a,b,c;
  39.     for(c=4;c>0;c--)
  40.         for(b=116;b>0;b--)
  41.             for(a=214;a>0;a--);
  42.     _nop_();  //if Keil,require use intrins.h
  43. }

  44.         /*******************************************************************************
  45. * 函 数 名         : datapros()
  46. * 函数功能                   : 温度读取处理转换函数
  47. * 输    入         : temp
  48. * 输    出         : 无
  49. *******************************************************************************/

  50. void datapros(int temp)          
  51. {
  52.            float tp;  
  53.         if(temp< 0)                                //当温度值为负数
  54.           {
  55.       sData[0]=0;
  56.                 //因为读取的温度是实际温度的补码,所以减1,再取反求出原码
  57.                 temp=temp-1;
  58.                 temp=~temp;
  59.                 tp=temp;
  60.                 temp=tp*0.0625*100+0.5;       
  61.                 //留两个小数点就*100,+0.5是四舍五入,因为C语言浮点数转换为整型的时候把小数点
  62.                 //后面的数自动去掉,不管是否大于0.5,而+0.5之后大于0.5的就是进1了,小于0.5的就
  63.                 //算加上0.5,还是在小数点后面。

  64.           }
  65.         else
  66.           {                       
  67.                 sData[0]=1;
  68.                 tp=temp;//因为数据处理有小数点所以将温度赋给一个浮点型变量
  69.                 //如果温度是正的那么,那么正数的原码就是补码它本身
  70.                 temp=tp*0.0625*100+0.5;       
  71.                 //留两个小数点就*100,+0.5是四舍五入,因为C语言浮点数转换为整型的时候把小数点
  72.                 //后面的数自动去掉,不管是否大于0.5,而+0.5之后大于0.5的就是进1了,小于0.5的就
  73.                 //算加上0.5,还是在小数点后面。
  74.         }
  75.         //显示数据处理
  76.         sData[1] = '0'+(temp / 10000);
  77.         sData[2] = '0'+(temp % 10000 / 1000);
  78.         sData[3] = '0'+(temp % 1000 / 100) ;
  79.         sData[4] = '0'+(temp % 100 / 10);
  80.         sData[5] = '0'+(temp % 10);
  81.           //真实数据
  82.         sData[7] = temp / 10000;
  83.         sData[8] = temp % 10000 / 1000;
  84.         sData[9] = temp % 1000 / 100 ;
  85.         sData[10] =temp % 100 / 10;
  86. }

  87.         /*******************************************************************************
  88. * 函 数 名         : Timer1Init
  89. * 函数功能                   : 定时器1初始化
  90. * 输    入         : 无
  91. * 输    出         : 无
  92. *******************************************************************************/
  93.         void Timer1Init()
  94. {
  95.         TMOD|=0X10;//选择为定时器1模式,工作方式1,仅用TR1打开启动。

  96.         TH1=0XFC;        //给定时器赋初值,定时1ms
  97.         TL1=0X18;       
  98.         ET1=1;//打开定时器1中断允许
  99.         EA=1;//打开总中断
  100.         TR1=1;//打开定时器                       
  101. }



  102. /*********************************************************************************************
  103. 函数名:延时函数
  104. 调  用:Delay30us();/Delay20ms();/Delay1s();
  105. 参  数:无
  106. 返回值:无
  107. 结  果:延时相应时间
  108. 备  注:振荡晶体为11.0592MHz(所有延时函数Copy自STC-ISP(v6.85).exe)
  109. **********************************************************************************************/
  110. void Delay30us()                //@11.0592MHz-40
  111. {
  112.         unsigned char i;

  113.         i = 11;
  114.         while (--i);
  115. }


  116. void Delay20ms()                //@11.0592MHz
  117. {
  118.         unsigned char i, j;

  119.         i = 36;
  120.         j = 217;
  121.         do
  122.         {
  123.                 while (--j);
  124.         } while (--i);
  125. }


  126. void Delay1s()                //@11.0592MHz
  127. {
  128.         unsigned char i, j, k;

  129.         _nop_();
  130.         i = 8;
  131.         j = 1;
  132.         k = 243;
  133.         do
  134.         {
  135.                 do
  136.                 {
  137.                         while (--k);
  138.                 } while (--j);
  139.         } while (--i);
  140. }


  141. /*********************************************************************************************
  142. 函数名:DHT11启动函数
  143. 调  用:无
  144. 参  数:无
  145. 返回值:无
  146. 结  果:DHT11开始工作
  147. 备  注:
  148. **********************************************************************************************/
  149. void DHT11_start()                 // 主机控制DHT11开始工作
  150. {
  151.    DATA=1;                                 // 主线空闲状态
  152.    _nop_();
  153.    _nop_();
  154.    DATA=0;                                 // 主机发送开始工作信号
  155.    Delay20ms();   //延时18ms以上
  156.    DATA=1;                                 // 拉高并延时等待DHT11响应
  157.    Delay30us();
  158. }
  159. /*********************************************************************************************
  160. 函数名:DHT11读数据函数
  161. 调  用:? = DHT11_rec_byte();
  162. 参  数:无
  163. 返回值:
  164. 结  果:读DHT11数据并保存到dat
  165. 备  注:
  166. **********************************************************************************************/

  167. uchar DHT11_rec_byte()      //接收一个字节
  168. {
  169.    uchar i,dat=0;
  170.   for(i=0;i<8;i++)    //从高到低依次接收8位数据
  171.    {         
  172.       while(!DATA);   ////等待50us低电平过去
  173.       Delay30us();
  174.           Delay30us();     //延时60us,如果还为高则数据为1,否则为0
  175.       dat<<=1;           //左移位使正确接收8位数据,数据为0时直接移位
  176.       if(DATA==1)    //数据为1时,使dat加1来接收数据1
  177.          dat+=1;
  178.       while(DATA);  //等待数据线拉低   
  179.     }  
  180.     return dat;
  181. }

  182. /*********************************************************************************************
  183. 函数名:接收DHT11的40位的数据并校验
  184. 调  用:? = DHT11_receive();
  185. 参  数:无
  186. 返回值:无
  187. 结  果:结果保存到dat_r[i]中
  188. 备  注:
  189. **********************************************************************************************/
  190. void DHT11_receive()      //接收40位的数据
  191. {
  192.     uchar R_H,R_L,T_H,T_L,RH,RL,TH,TL,revise;

  193.         //xiao thi;
  194. //uint zheng;
  195.     DHT11_start();                 // 主机控制DHT11开始工作
  196.     if(DATA==0)
  197.     {
  198.         while(DATA==0);   //等待拉高     
  199.         Delay30us();
  200.                 Delay30us();
  201.                 Delay30us();  //拉高后延时80us
  202.         R_H=DHT11_rec_byte();    //接收湿度高八位  
  203.         R_L=DHT11_rec_byte();    //接收湿度低八位  
  204.         T_H=DHT11_rec_byte();    //接收温度高八位  
  205.         T_L=DHT11_rec_byte();    //接收温度低八位
  206.         revise=DHT11_rec_byte(); //接收校正位

  207.         Delay30us();    //结束

  208.         if((R_H+R_L+T_H+T_L)==revise)      //校正
  209.         {
  210.             RH=R_H;
  211.             RL=R_L;
  212.             TH=T_H;
  213.             TL=T_L;

  214.                                
  215.         }
  216.         /*数据处理,方便显示*/
  217.         dat_r[0]='0'+(RH/10);
  218.         dat_r[1]='0'+(RH%10);
  219.         dat_r[2]='0'+(TH/10);
  220.         dat_r[3]='0'+(TH%10);
  221.                                
  222.                                 dat_r[4]=RH;
  223.       
  224.         
  225.                                 //dat_r[4]='0'+(zheng/100);
  226.                           //dat_r[5]='0'+(zheng%100/10);
  227.                                 //dat_r[6]='0'+(zheng%10);
  228.                                 //dat_r[7]='0'+(zheng/10);
  229.                                 //dat_r[8]=Thi;
  230.                                 //dat_r[7]='0'+(h);
  231.                                 //dat_r[7]='0'+(zheng);


  232.        
  233.     }
  234. }

  235. /********************************************************************
  236. * 名称 : bit Busy(void)
  237. * 功能 : 这个是一个读状态函数,读出函数是否处在忙状态
  238. * 输入 : 输入的命令值
  239. * 输出 : 无
  240. ***********************************************************************/
  241. void Busy(void)
  242. {
  243. bit busy_flag = 1;
  244. IODATA  = 0xff;
  245. RS = 0;          //指令关
  246. Delay30us();
  247. RW = 1;          //读状态
  248. Delay30us();
  249. E = 1;        //使能高电平
  250. while(1)
  251. {
  252. busy_flag = (bit)(IODATA  & 0x80); //强制取最高位
  253. if(busy_flag == 0)
  254. {
  255. break;
  256. }
  257. }
  258. E = 0;           //E 1->0,rs=0,rw=1,
  259.            //将数据寄存器内的数据读到DB0~DB7,分别将状态标志BF和地址计数器(AC)内容读到DB7和DB6~DB0。

  260. }

  261. /********************************************************************
  262. * 名称 : lcd1602_write_cmd(uchar del)
  263. * 功能 : 1602命令函数
  264. * 输入 : 输入的命令值
  265. * 输出 : 无
  266. ***********************************************************************/
  267. void lcd1602_write_cmd(uchar del)
  268. {
  269. RS = 0;
  270. Delay30us();
  271. RW = 0;
  272. Delay30us();
  273. E = 0;
  274. Delay30us();
  275. IODATA  = del;
  276. Delay30us();
  277. E = 1;
  278. Delay30us();
  279. E = 0;                        //E 1->0,rs=0,rw=0, 将指令代码写入指令寄存器中
  280. }

  281. /********************************************************************
  282. * 名称 : lcd1602_write_data(uchar del)
  283. * 功能 : 1602写数据函数
  284. * 输入 : 需要写入1602的数据
  285. * 输出 : 无
  286. ***********************************************************************/

  287. void lcd1602_write_data(uchar del)
  288. {
  289. Busy();      
  290. Delay30us();
  291. RS = 1;
  292. Delay30us();
  293. RW = 0;
  294. Delay30us();
  295. E = 0;
  296. Delay30us();
  297. IODATA  = del;
  298. Delay30us();
  299. E = 1;
  300. Delay30us();
  301. E = 0;                          //E 1->0,rs=1,rw=0, 数据写入数据寄存器中
  302. }

  303. /********************************************************************
  304. * 名称 : lcd1602_init()
  305. * 功能 : 1602初始化,请参考1602的资料
  306. * 输入 : 无
  307. * 输出 : 无
  308. ***********************************************************************/
  309. void lcd1602_init(void)
  310. {
  311. Delay20ms();
  312. lcd1602_write_cmd(0x38);         //8位数据,双列,5*7字形
  313. Delay20ms();
  314. lcd1602_write_cmd(0x38);
  315. Delay20ms();
  316. lcd1602_write_cmd(0x38);
  317. Busy();
  318. lcd1602_write_cmd(0x08);// 只开显示
  319. Busy();   
  320. lcd1602_write_cmd(0x01);        //清屏
  321. Busy();
  322. lcd1602_write_cmd(0x06);//显示地址递增,即写一个数据后,显示位置右移一位
  323. Busy();
  324. lcd1602_write_cmd(0x0c);        //开启显示屏,关光标,光标不闪烁
  325. }

  326. /********************************************************************
  327. * 名称 : lcd1602_char(uchar hang,uchar lie,char sign)
  328. * 功能 : 改变液晶中某位的值,如果要让第一行,第五个字符显示"b" ,调用该函数如下
  329. L1602_char(1,5,'b')
  330. * 输入 : 行,列,需要输入1602的数据
  331. * 输出 : 无
  332. ***********************************************************************/
  333. void lcd1602_char(uchar hang,uchar lie,char sign)
  334. {
  335. uchar a;
  336. if(hang == 1)
  337. {
  338. a = 0x80;
  339. }
  340. if(hang == 2)
  341. {
  342. a = 0xc0;
  343. }
  344. a = a + lie - 1;
  345. Busy();
  346. lcd1602_write_cmd(a);  //置数据存贮器地址
  347. Busy();
  348. lcd1602_write_data(sign);
  349. }




  350. /********************************************************************
  351. * 名称 : lcd1602_string(uchar hang,uchar lie,uchar *p)
  352. * 功能 : 改变液晶中某位的值,如果要让第一行,第五个字符开始显示"ab cd ef" ,调用该函数如下
  353. L1602_string(1,5,"ab cd ef;")
  354. * 输入 : 行,列,需要输入1602的数据
  355. * 输出 : 无
  356. ***********************************************************************/

  357. void lcd1602_string(uchar hang,uchar lie,uchar *p)
  358. {
  359. uchar a;
  360. if(hang == 1)
  361. {
  362. a = 0x80;
  363. }
  364. if(hang == 2)
  365. {
  366. a = 0xc0;
  367. }
  368. a = a + lie - 1;
  369. while(1)
  370. {
  371. Busy();
  372. lcd1602_write_cmd(a);
  373. Busy();
  374. lcd1602_write_data(*p);
  375. a++;
  376. p++;   
  377. if((*p == '\0')||(a==0x90)||(a==0xd0)) //字符结束或每行最后一个字符
  378. {
  379. break;
  380. }
  381. }
  382. }

  383. void kongzhi()    //控制函数
  384.    {
  385.    if(dat_r[8]>78) {jidian=0;lcd1602_string(1,16,"K");}     // 上限74
  386.       else if(dat_r[8]<77) {jidian=1;lcd1602_string(1,16,"G");}    // 下限72
  387.        else {lcd1602_string(1,16,"L");}  
  388.       }


  389.             //thi计算函数
  390.            void thisuan()
  391.            {
  392.            xiao th;
  393.            uint thi,shi,wen;
  394.              shi=dat_r[4]        ;
  395.                  wen=sData[7]*100+sData[8]*10+sData[9]+sData[10]/10 ;
  396.                     th=wen*0.81+(0.99*wen-14.3)*shi/100+46.3+0.5;
  397.                          thi=th*10;
  398.                           dat_r[5]='0'+(thi/100);
  399.                           dat_r[6]='0'+(thi%100/10);
  400.                                 dat_r[7]='0'+(thi%10);
  401.                         dat_r[8]=th;
  402.            }   

  403. /*********************************************************************************************
  404. 函数名:主函数
  405. 调  用:无
  406. 参  数:无
  407. 返回值:无
  408. 结  果:读DHT11数据并送到1602显示
  409. 备  注:
  410. **********************************************************************************************/
  411. void main (void)
  412. {

  413.        
  414.        Delay20ms();
  415.         lcd1602_init();         //LCD初始化

  416.         while(1)
  417.         {
  418.                                         datapros(Ds18b20ReadTemp());
  419.                 delay200ms;              //经测试,两次连读要至少延时80ms        
  420.                 DHT11_receive();//接受数据
  421.                                                 thisuan();
  422.                                        
  423.                                        
  424.                                
  425.       
  426.                 lcd1602_string(1,1,"S:");
  427.                                               lcd1602_char(1,3,dat_r[0]);
  428.                 lcd1602_char(1,4,dat_r[1]);
  429.                                               lcd1602_string(1,5,"%");
  430.                                        
  431.                 lcd1602_string(1,7,"W:");
  432.                 lcd1602_char(1,8,dat_r[2]);
  433.                 lcd1602_char(1,9,dat_r[3]);
  434.                 lcd1602_char(1,10,0XDF);
  435.                 lcd1602_string(1,11,"C");
  436.                                        
  437.                                         lcd1602_string(2,1,"T:");
  438.                                         lcd1602_char(2,3,dat_r[5]);
  439.                                         lcd1602_char(2,4,dat_r[6]);
  440.                                         lcd1602_string(2,5,".");
  441.                                         lcd1602_char(2,6,dat_r[7]);
  442.                                        
  443.                                        
  444.                                         if(sData[0]==0)
  445.                                         {
  446.                                         lcd1602_string(2,8,"-");
  447.                                         }
  448.                                        
  449.                                                 if(sData[7]>0)
  450.                                                 {
  451.                                                         lcd1602_char(2,9,sData[1]);
  452.                                                 }
  453.                                        
  454.                                                 lcd1602_char(2,10,sData[2]);
  455.                                                         lcd1602_char(2,11,sData[3]);
  456.                                         lcd1602_string(2,12,".");
  457.                                                                 lcd1602_char(2,13,sData[4]);
  458.                                                                 //lcd1602_char(2,14,sData[5]);
  459.                                        
  460.                                        
  461.                                         lcd1602_string(1,13,"ji:");

  462.                                
  463.                                         kongzhi();
  464.                                
  465.                
  466.                                

  467. }}  

  468.                                
  469.                                
  470. //void Timer0() interrupt 3  //定时器中断
  471. //{
  472.        
  473.        
  474.         //TH0=0XFC;        //给定时器赋初值,定时1ms
  475.         //TL0=0X18;
  476. //i++;
  477.        
  478. //}
复制代码

所有资料51hei提供下载:
THI dht11 18b20.zip (78.98 KB, 下载次数: 90)

评分

参与人数 2黑币 +55 收起 理由
Eli_ + 5 赞一个!
admin + 50 共享资料的黑币奖励!

查看全部评分

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

使用道具 举报

沙发
ID:16087 发表于 2019-11-2 15:29 | 只看该作者
楼主你太辛苦了,谢谢啊
回复

使用道具 举报

板凳
ID:332895 发表于 2019-11-6 23:19 | 只看该作者
stc89c52rc,11.0592MHz,实测可以运行!
回复

使用道具 举报

地板
ID:691459 发表于 2020-3-2 17:25 | 只看该作者
你好,我想问一下,DHT11怎么接入51开发板,接哪个引脚,小白一个。不是很懂
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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