找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 26373|回复: 44
收起左侧

[原创]自己编的DHT11驱动程序~

  [复制链接]
ID:84652 发表于 2015-8-4 17:29 | 显示全部楼层 |阅读模式
本帖最后由 王朗的诱惑 于 2015-8-4 21:05 编辑

前几天在某宝上看到DHT11,感觉蓝色的外壳做的很漂亮,然后就买了1个。结果发现网上的程序都是给旧12T单片机用的,注释也没几句,用着很不顺手。所以就自己按照数据手册编了驱动程序。还是自己的程序用着顺手~~~~拿来和大家分享~~~~
  1. /*********************************************************************************************
  2. 程序名:    DHT11驱动程序
  3. 编写人:    王朗的诱惑
  4. 编写时间:  2015年8月4日
  5. 硬件支持:  STC12C5A60S2  DHT11
  6. 接口说明:  DHT11:VCC GND DATA
  7. *********************************************************************************************
  8. 说明:1、单片机是STC12C5A60S2,晶振频率12MHz,实验成功。换用12T单片机或别的晶振的时候要修改
  9.           延时函数和JUDGE。程序里判断超时的变量t的阀值也要改。
  10.           2、好东西要共享,大家随意折腾~~
  11. *********************************************************************************************/
  12. #include <STC12C5A60S2.H>

  13. typedef unsigned char        uchar;
  14. typedef unsigned int        uint;

  15. #define JUDGE        30                //用于判断通信的0和1,与单片机速度和晶振频率有关

  16. sbit DATA = P1^0;                //定义数据引脚

  17. uchar dat_r[5];                        //用于存放从DHT11读取到的数值

  18. /*********************************************************************************************
  19. 函数名:延时函数
  20. 调  用:Delay30us();/Delay20ms();/Delay1s();
  21. 参  数:无
  22. 返回值:无
  23. 结  果:延时相应时间
  24. 备  注:振荡晶体为12MHz(所有延时函数Copy自STC-ISP(v6.85).exe)
  25. **********************************************************************************************/
  26. void Delay30us()                //@12.000MHz
  27. {
  28.         unsigned char i;

  29.         i = 87;
  30.         while (--i);
  31. }


  32. void Delay20ms()                //@12.000MHz
  33. {
  34.         unsigned char i, j, k;

  35.         i = 1;
  36.         j = 234;
  37.         k = 113;
  38.         do
  39.         {
  40.                 do
  41.                 {
  42.                         while (--k);
  43.                 } while (--j);
  44.         } while (--i);
  45. }

  46. void Delay1s()                //@12.000MHz
  47. {
  48.         unsigned char i, j, k;

  49.         i = 46;
  50.         j = 153;
  51.         k = 245;
  52.         do
  53.         {
  54.                 do
  55.                 {
  56.                         while (--k);
  57.                 } while (--j);
  58.         } while (--i);
  59. }

  60. /*********************************************************************************************
  61. 函数名:UART串口初始化函数
  62. 调  用:UART_Init();
  63. 参  数:无
  64. 返回值:无
  65. 结  果:启动UART串口接收中断,允许串口接收,启动T/C1产生波特率(占用)
  66. 备  注:振荡晶体为12MHz,PC串口端设置 [ 4800,8,无,1,无 ]
  67. **********************************************************************************************/
  68. void UART_Init (void){
  69.         EA = 1; //允许总中断(如不使用中断,可用//屏蔽)
  70.         ES = 1; //允许UART串口的中断

  71.         TMOD = 0x20;        //定时器T/C1工作方式2
  72.         SCON = 0x50;        //串口工作方式1,允许串口接收(SCON = 0x40 时禁止串口接收)
  73.         TH1 = 0xF3;        //定时器初值高8位设置
  74.         TL1 = 0xF3;        //定时器初值低8位设置
  75.         PCON = 0x80;        //波特率倍频(屏蔽本句波特率为2400)
  76.         TR1 = 1;        //定时器启动   
  77. }

  78. /*********************************************************************************************
  79. 函数名:UART串口发送函数
  80. 调  用:UART_T (?);
  81. 参  数:需要UART串口发送的数据(8位/1字节)
  82. 返回值:无
  83. 结  果:将参数中的数据发送给UART串口,确认发送完成后退出
  84. 备  注:
  85. **********************************************************************************************/
  86. void UART_T (uchar UART_data){ //定义串口发送数据变量
  87.         SBUF = UART_data;        //将接收的数据发送回去
  88.         while(TI == 0);                //检查发送中断标志位
  89.         TI = 0;                        //令发送中断标志位为0(软件清零)
  90. }

  91. /*********************************************************************************************
  92. 函数名:DHT11读数据函数
  93. 调  用:? = GetData();
  94. 参  数:无
  95. 返回值:失败->-1,-2,-3,-4;成功->0
  96. 结  果:读DHT11数据并保存到数组dat_r[]
  97. 备  注:
  98. **********************************************************************************************/
  99. char GetData (void)
  100. {
  101.         uchar i,j;                                //for循环变量
  102.         uchar t;                                //超时判断
  103.         uchar dat8=0;                        //一次读取的8位数据,需要读5次

  104.         DATA = 0;                                //主机发起始信号
  105.         Delay20ms();                        //主机拉低总线至少18ms
  106.         DATA = 1;                                //主机拉高总线20~40us
  107.         Delay30us();

  108.         t = 80;                                        //设置超时等待时间
  109.         while(DATA && t--);                //等待DHT11拉低总线
  110.         if(t == 0)                                //超时
  111.         {
  112.                 DATA = 1;
  113.                 return -1;                        //通信错误退出,返回错误信号:-1
  114.         }

  115.         //等80us响应信号
  116.         t = 250;                                //设置超时等待时间
  117.         while(!DATA && t--);        //等待DHT11拉高总线
  118.         if(t == 0)                                //超时
  119.         {
  120.                 DATA = 1;
  121.                 return -2;                        //通信错误退出,返回错误信号:-2
  122.         }

  123.         //等80us响应信号
  124.         t = 250;                                //设置超时等待时间
  125.         while(DATA && t--);                //等待DHT11拉低总线
  126.         if(t == 0)                                //超时
  127.         {
  128.                 DATA = 1;
  129.                 return -3;                        //通信错误退出,返回错误信号:-3
  130.         }

  131.         for(j=0; j<5; j++)                //5次读取
  132.         {
  133.                 for(i=0; i<8; i++)                        //1次8个位
  134.                 {
  135.                         //等待50us开始时隙
  136.                         t = 150;                                //设置超时等待时间
  137.                         while(!DATA && t--);        //等待DHT11拉高总线
  138.                         if(t == 0)                                //超时
  139.                         {
  140.                                 DATA = 1;
  141.                                 return -4;                        //通信错误退出,返回错误信号:-4
  142.                         }
  143.                         t = 0;                                        //记录时间清零
  144.                         while(DATA && ++t);                //等待并记录高电平持续时间
  145.                         dat8 <<= 1;
  146.                         if(t > JUDGE)                        //高电平持续时间较长(70us)
  147.                                 dat8 += 1;                        //传输值为1
  148.                         //else dat8 += 0;
  149.                 }
  150.                 dat_r[j] = dat8;
  151.         }

  152.         Delay30us();                //等待DHT11拉低50us
  153.         Delay30us();
  154.         DATA = 1;                        //结束,拉高总线
  155.         return 0;                        //返回成功信号
  156. }

  157. /*********************************************************************************************
  158. 函数名:数据校验函数
  159. 调  用:? = Check();
  160. 参  数:无
  161. 返回值:成功->0;失败->-1;
  162. 结  果:数据校验
  163. 备  注:数据传送正确时校验和数据等于“8bit湿度整数数据+8bit湿度小数数据+8bi温度整数数据+8bit温度小数数据”所得结果的末8位。
  164. **********************************************************************************************/
  165. char Check (void)
  166. {
  167.         uchar i;                        //for循环变量
  168.         uint chk=0;                        //校验和
  169.         for(i=0; i<4; i++)
  170.                 chk += dat_r[i];                //累加
  171.         if((uchar)chk != dat_r[4])        //比对
  172.                 return -1;                                //返回错误信号:-1
  173.         else
  174.                 return 0;                                //返回正确信号:0
  175. }

  176. /*********************************************************************************************
  177. 函数名:主函数
  178. 调  用:无
  179. 参  数:无
  180. 返回值:无
  181. 结  果:读DHT11数据并送到串口显示
  182. 备  注:
  183. **********************************************************************************************/
  184. void main (void)
  185. {
  186.         char i;
  187.         UART_Init();                //串口初始化
  188.         Delay1s();                        //等待DHT11稳定
  189.         do
  190.         {
  191.                 i = GetData();        //读数据
  192.                 if(i != 0)                //有错误
  193.                 {
  194.                         UART_T(-i);        //返回错误值
  195.                         break;                //重新开始
  196.                 }

  197.                 i = Check();        //数据校验
  198.                 if(i != 0)                //有错误
  199.                 {
  200.                         UART_T(-i);        //返回错误值
  201.                         break;                //重新开始
  202.                 }

  203.                 UART_T(dat_r[0]);                //湿度整数
  204.                 //UART_T(dat_r[1]);                //湿度小数(根据数据手册,DHT11小数部分一直是0没用)
  205.                 UART_T(dat_r[2]);                //温度整数
  206.                 //UART_T(dat_r[3]);                //温度小数(根据数据手册,DHT11小数部分一直是0没用)
  207.                 UART_T(dat_r[4]);                //校验值

  208.                 Delay1s();                                //经测试,两次连读要至少延时80ms        
  209.         }while(1);
  210. }//main
复制代码



评分

参与人数 1黑币 +35 收起 理由
davg1 + 35 赞一个!程序写的很工整

查看全部评分

回复

使用道具 举报

ID:84652 发表于 2018-9-16 11:16 | 显示全部楼层
把主函数里的break都改成continue
回复

使用道具 举报

ID:84652 发表于 2019-3-1 21:22 | 显示全部楼层
修改一处bug:请把程序里所有的t--改成--t,否则错误值返回不了。原来的程序一次成功了,所以直到现在才发现这个bug……向大家道歉……

评分

参与人数 1黑币 +50 收起 理由
admin + 50 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

ID:123712 发表于 2016-12-28 22:03 | 显示全部楼层
谢谢楼主分享资料,学习中
回复

使用道具 举报

ID:158563 发表于 2016-12-29 10:43 | 显示全部楼层
感觉好难……
回复

使用道具 举报

ID:146045 发表于 2017-3-18 11:45 | 显示全部楼层
程序很好
回复

使用道具 举报

ID:186776 发表于 2017-5-17 21:02 | 显示全部楼层
学习了
回复

使用道具 举报

ID:186776 发表于 2017-5-17 21:26 来自手机 | 显示全部楼层
学习了
回复

使用道具 举报

ID:145935 发表于 2017-5-18 10:41 | 显示全部楼层
感谢分享,学习了。
回复

使用道具 举报

ID:141361 发表于 2017-5-25 13:13 | 显示全部楼层
这两天一直在研究,开始初始化都失败,然后呢却却读出来数据,真是闹心,借鉴一下程序看有没有效果
回复

使用道具 举报

ID:202299 发表于 2017-5-26 11:06 | 显示全部楼层
请问大神,有没有DHT11加1602显示的综合程序?
回复

使用道具 举报

ID:202299 发表于 2017-5-26 11:06 | 显示全部楼层
请问大神,要用1602显示的话,还要用到串口吗?
回复

使用道具 举报

ID:84652 发表于 2017-8-21 14:43 | 显示全部楼层
smallriver 发表于 2017-5-25 13:13
这两天一直在研究,开始初始化都失败,然后呢却却读出来数据,真是闹心,借鉴一下程序看有没有效果

单总线一般都是时序问题,最好是能有台示波器看看。
回复

使用道具 举报

ID:84652 发表于 2017-8-21 14:44 | 显示全部楼层
aiait 发表于 2017-5-26 11:06
请问大神,要用1602显示的话,还要用到串口吗?

把数据送到1602屏幕上就行了吧?只是这样的话不用串口。串口可以用来调试,看看有没有数据读出来。
回复

使用道具 举报

ID:229113 发表于 2017-8-24 13:41 | 显示全部楼层
我在stc15上用的,仿真软件上串口输出时十六进制,怎么才能输出的是十进制呢?
回复

使用道具 举报

ID:84652 发表于 2017-8-25 11:02 | 显示全部楼层
cp66 发表于 2017-8-24 13:41
我在stc15上用的,仿真软件上串口输出时十六进制,怎么才能输出的是十进制呢?

写个发送字符串函数,把数据的十位和个位分开发,串口助手用文本模式接收。
回复

使用道具 举报

ID:215834 发表于 2017-11-18 09:55 | 显示全部楼层
楼主好,感谢分享。请问为什么要检测那么多次错误呢。另外 &nbsp;while(DATA && ++t);&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 语句检测时间t自加一次需要多久时间,谢谢楼主
回复

使用道具 举报

ID:84652 发表于 2017-11-18 10:40 | 显示全部楼层
本帖最后由 王朗的诱惑 于 2017-11-18 11:03 编辑
njzyg 发表于 2017-11-18 09:55
楼主好,感谢分享。请问为什么要检测那么多次错误呢。另外  while(DATA && ++t);      ...

DHT11是单总线器件,驱动的时候时序容易出问题,但是环节太多不知道问题出在哪,调试的时候就费劲。不断检测错误就是想知道问题出在哪个环节,然后有针对性地解决。那个自加的具体时间不知道,和单片机速度有关系,先把前面调试好了,然后记录下来0和1对应的t值通过串口发上来,取平均值就可以了。
回复

使用道具 举报

ID:326995 发表于 2018-5-10 20:55 | 显示全部楼层
代码很有用
回复

使用道具 举报

ID:95072 发表于 2018-11-10 16:49 | 显示全部楼层
值得学习!!!
回复

使用道具 举报

ID:458168 发表于 2019-1-8 23:12 | 显示全部楼层
谢谢楼主
回复

使用道具 举报

ID:445069 发表于 2019-3-1 17:29 | 显示全部楼层
楼主,有没有在STC89C52上测试过DHT11?
找了很多网上的代码,根本就读不出来。
回复

使用道具 举报

ID:84652 发表于 2019-3-1 19:39 | 显示全部楼层
ontheroad 发表于 2019-3-1 17:29
楼主,有没有在STC89C52上测试过DHT11?
找了很多网上的代码,根本就读不出来。

没有诶,不过我手上有元件,我可以帮你试试~
回复

使用道具 举报

ID:84652 发表于 2019-3-1 21:18 | 显示全部楼层
ontheroad 发表于 2019-3-1 17:29
楼主,有没有在STC89C52上测试过DHT11?
找了很多网上的代码,根本就读不出来。

这是STC89C52RC的程序,晶振频率11.0592MHz,接口还是P1.0,刚刚测试成功了。

DHT11-STC89.zip

35.33 KB, 下载次数: 80, 下载积分: 黑币 -5

11.0592MHz

回复

使用道具 举报

ID:434090 发表于 2019-3-16 11:34 | 显示全部楼层
最近在研究dht11,多谢分享
回复

使用道具 举报

ID:448233 发表于 2019-11-12 09:11 | 显示全部楼层

楼主,有没有在STC15F408AD测试过DHT11?
找了很多网上的代码,根本就读不出来。
回复

使用道具 举报

ID:84652 发表于 2019-11-19 00:20 | 显示全部楼层
zeki520kiki 发表于 2019-11-12 09:11
楼主,有没有在STC15F408AD测试过DHT11?
找了很多网上的代码,根本就读不出来。

我没试过……如果实在调不出来,强烈建议用示波器或者逻辑分析仪看看波形。
回复

使用道具 举报

ID:627950 发表于 2019-12-15 20:16 | 显示全部楼层
楼主,有没有在IAP15W4K58S4测试过DHT11?
求分享~
回复

使用道具 举报

ID:666819 发表于 2019-12-17 23:32 | 显示全部楼层
我测试成功了,谢谢楼主的帮助
回复

使用道具 举报

ID:84652 发表于 2020-1-7 22:09 | 显示全部楼层
梦在夏天 发表于 2019-12-15 20:16
楼主,有没有在IAP15W4K58S4测试过DHT11?
求分享~

没有……盲调主要看人品,最好想办法搞个示波器或者逻辑分析仪。
回复

使用道具 举报

ID:259035 发表于 2020-1-31 17:23 | 显示全部楼层

楼主,有没有在STC15f2k60s上测试过DHT11?
找了很多网上的代码,根本就读不出来。
回复

使用道具 举报

ID:84652 发表于 2020-2-7 19:30 | 显示全部楼层
yechuan220 发表于 2020-1-31 17:23
楼主,有没有在STC15f2k60s上测试过DHT11?
找了很多网上的代码,根本就读不出来。

没……现在我大概明白,提出这些问题的老哥们是没有示波器什么的,那就串口调试吧。DHT11这东西不是把信号全发过去才返回的,通信的过程就是反馈的过程,比如主机发一个开始信号,然后DHT11就会响应一个低电平信号,检测这个信号,就知道之前的开始信号正不正常。类似于打电话,得听到对方的声音,才知道信号没问题,对吧。
回复

使用道具 举报

ID:626079 发表于 2020-3-18 23:14 | 显示全部楼层
感谢楼主的程序,麻烦咨询下楼主,你的STC52程序中
#define JUDGE        4                //用于判断通信的0和1,与单片机速度和晶振频率有关
这是起啥作用。 我看在程序里调用时:
if(t >JUDGE)                        //高电平持续时间较长(70us)
dat8 += 1;                        //传输值为1

能解答一下为什么t>JDGE是与70us进行比较呢?新手不太明白,谢谢了。
还有dat8 += 1;是不是就是把dat8最后一位给“1”的意思哈?
回复

使用道具 举报

ID:710428 发表于 2020-3-19 20:34 | 显示全部楼层
谢谢分享
回复

使用道具 举报

ID:282869 发表于 2020-3-20 13:32 | 显示全部楼层
值得參考學習,謝謝分享.
回复

使用道具 举报

ID:84652 发表于 2020-3-20 14:51 | 显示全部楼层
本帖最后由 王朗的诱惑 于 2020-3-20 19:46 编辑
xmfjfhcel 发表于 2020-3-18 23:14
感谢楼主的程序,麻烦咨询下楼主,你的STC52程序中
#define JUDGE        4                //用于判断通 ...

问题1:
截图_20200320064436.png

看下数据手册里的图5,DHT11数据高电平持续时间规定为70us,所以比较这个时间判断数据是1还是0。JUDGE是手动试出来的,这个值理论上最好能让单片机计时在DHT11数据高电平的时间中间,就是(70+28)/2 = 49 us。
好好研究下数据手册是解决问题的最好办法。已附上数据手册。

问题2:
是。相当于 dat8 |= 1;

DHT11说明书081206.pdf

677.52 KB, 下载次数: 7, 下载积分: 黑币 -5

DHT11数据手册

回复

使用道具 举报

ID:626079 发表于 2020-3-20 16:43 | 显示全部楼层


谢谢大侠, 高手。已经用你的程序做出来通过……
http://www.51hei.com/bbs/dpj-182291-1.html
回复

使用道具 举报

ID:246783 发表于 2020-3-21 19:56 | 显示全部楼层
你这个思路比较好   相当于软件示波器了       借鉴你这个思路调了408AS 的dht11   数据出来了 !!

另外问个问题  :  串口接收时      开文本接收时 数据一直是字符乱码  怎么解决 ?

                  SendString("\r\n湿度:");
                        SendData(dat_r[0]);                //湿度整数        
             
                SendString("\r\n温度:");
                SendData(dat_r[2]);                //温度整数                


/////////////////////////////////////////
我的串口函数  :  
/******************************************************************************

****************************************************************Author:Liming**/
void SendData(unsigned char dat)
{
    while (B_TX1_Busy);               //等待前面的数据发送完成
    B_TX1_Busy = 1;
    SBUF = dat;                 //写数据到UART数据寄存器
}

/*******************************************************************************
  * @brief  None
  * @param  None
  * @retval None
****************************************************************Author:Liming**/
void SendString(char *s)
{
    while (*s)                  //检测字符串结束标志
    {
        SendData(*s++);         //发送当前字符
    }
}
回复

使用道具 举报

ID:84652 发表于 2020-3-22 13:13 | 显示全部楼层
sasafair 发表于 2020-3-21 19:56
你这个思路比较好   相当于软件示波器了       借鉴你这个思路调了408AS 的dht11   数据出来了 !!

另外 ...

文本接收时发送的数字需要进行ASCII编码,比如发送0,实际发送的字节是0x30;发送1,实际发送的字节是0x31,依次类推。
实现的方法有很多,可以自己写转换函数,转换要发送的数据的每个十进制位;也可以用sprintf函数把数据转换成字符串然后发送字符串;还可以重定向printf然后直接用printf。
你这个情况的话,推荐使用sprintf。如果为了学习ASCII编码,建议自己写个转换函数。
祝好运~
回复

使用道具 举报

ID:733775 发表于 2020-4-20 23:25 | 显示全部楼层
用LCD显示的数据特别不准咋办。。是这东西本来就误差大,还是时间没取好导致数据有误差啊?或者算法?不能直接高位/10,%10?太离谱了家里温度显示27摄氏度,天气预报也就15摄氏度
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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