DHT11 这款温湿度传感器 几乎是所有 MCU 入门第一个传感器, 现在看来有些不合时宜, 毕竟过于廉价,数据不太靠谱,远不如 AHT10 好用。早年买了两个,按例程读出数据后就吃灰了。某日看到有人说自己按datasheet去读,得不到需要的数据回应。于是仔细看了下DHT11的数据传输,觉得蛮有意思的,想着自己算是入门好几年的老鸟,硬核一点,不用别人的库,自己写几句代码来读一下这个传感器看看?

DHT11 数据传输详解https://blog.csdn.net/Alex_68/article/details/108730534

上文是要啃一下的,时序图并不算复杂,大概原理就是:

1.均由 MCU 发起读数据操作。没有传输时, 数据脚持续高电平。2.MCU 发起读数据操作时,把数据脚拉低再拉高一次。3.DHT11 收到上述电平变化后, 也把数据脚拉低再拉高一次作为响应,表示我要开始发送数据了。4.接下来 DHT11 把数据脚拉低再拉高40次, 即为40位数据的发送。数据是 0 还是 1 由高电平持续时间决定,和低电平时间无关。 大概可以理解和 摩斯电码 一样一样的。5.结束再次把数据脚拉低再拉高一次,高电平就一直保持了,直到 MCU 发起下一次读数据操作。

第一步,先采集下数据脚的电平情况看看:

实践出真知,下图为一帧数据的实测波形。按图右边设置示波器,点点左上角的运行按钮就能捕获到完美的波形。

如没有示波器,最简单就是 循环 “读数据脚、串口打印”,也能获得数据脚电平变化情况。

Serial.print(digitalRead(data_pin));

实际测试发现可能是因为串口太慢,上面的语句可以捕获到电平变化,但是不足以用来分析数据。

嗯,办法总是有的,按存储示波器的玩法,间隔20微秒,连续采样200次存入数组(总时间4ms左右,上面示波器的截图也能大概看出来)。采样完成后再集中打印出来。( 间隔越小越精准,需要的采样次数越多,一行显示不全了,嗯,超宽带鱼显示器在这里就比较方便了。上面20微秒200次是经过一些测试总结的,不要轻易改变)

实测,如下代码可以在串口监视器看到一些010111这样的输出,这里的01并不是是需要的数据,而是反映的数据脚电平高低变化。

#define DHT11_PIN 11
boolean data[200];void setup(){pinMode(12, OUTPUT);digitalWrite(12, HIGH);  // DHT11 VccpinMode(9, OUTPUT);digitalWrite(9, LOW);     // DHT11 Gnd  Serial.begin(115200);
}void loop(){/*HDT11空闲时为高电平。需要读数时,MCU先拉低30ms,再拉高30μs,注意两者时间单位 */pinMode(DHT11_PIN, OUTPUT);  digitalWrite(DHT11_PIN, LOW); delayMicroseconds(30000);digitalWrite(DHT11_PIN, HIGH);delayMicroseconds(30);  /*开始检测DHT的数据返回*/ pinMode(DHT11_PIN, INPUT); for(int i=0;i<200;i++){data[i]=digitalRead(DHT11_PIN);delayMicroseconds(20);}for(int i=0;i<200;i++)Serial.print(data[i]);    Serial.println();delay(5000);
}

从下图可以看出,1有单个的,和多个(3个或4个),分别对应长短电平,那么接下来需要做的就是“解码”

如果上面看起来有些别扭,修改下代码,把01用上下线段表示就比较像逻辑分析仪了:

第二步, 上面证实数据传输无误,继续判断高电平时间,就获得40位数据了:

MCU 需要干其他事的可能需要用到中断比较好,这里仅仅是验证数据传输,就用 while 语句傻等了。

#define DHT11_PIN 11
boolean data[40];
long time_stamp;void setup(){pinMode(12, OUTPUT);digitalWrite(12, HIGH);  // DHT11 VccpinMode(9, OUTPUT);digitalWrite(9, LOW);     // DHT11 Gnd  Serial.begin(115200);
}void loop(){/*HDT11空闲时为高电平。需要读数时,MCU先拉低30ms,再拉高30μs,注意两者时间单位 */pinMode(DHT11_PIN, OUTPUT);  digitalWrite(DHT11_PIN, LOW); delayMicroseconds(30000);digitalWrite(DHT11_PIN, HIGH);delayMicroseconds(30);  /*开始检测DHT的数据返回*/ pinMode(DHT11_PIN, INPUT); while (!digitalRead(DHT11_PIN)) {}            //刚开始应该是低电平,等待高电平出现后继续 , 括号不能省略!while ( digitalRead(DHT11_PIN)) {}            //高电平期间继续等待,出现低电平则为数据开始传输for(int i=0;i<40;i++){ data[i]=0;while (!digitalRead(DHT11_PIN)){}           //等待出现高电平time_stamp = micros();                      //开始计时while ( digitalRead(DHT11_PIN)){}           //等待出现低电平,即高电平结束了if (( micros()- time_stamp) > 50)  data[i]=1;}for(int i=0;i<40;i++)Serial.print(data[i]); Serial.println(); delay(5000);
}

上面代码可以在串口监视器上看到如下输出,40位不多不少,比较理想:

第三步,40位数据拆分转换。

第二步里的程序通用,能读出 DHT11 DHT22 两种传感器的数据,毕竟同一个公司的产品,格式都是连续5个8位共计40位数据:

湿度高8位、湿度低8位、温度高8位、温度低8位、校验8位

DHT11 只需要处理  湿度高8位  温度高8位 , 获得的整数即为需要的读数,没有小数的。

湿度高8位、湿度低8位、温度高8位、温度低8位、校验8位

DHT22 需要把16位全部读出来的整数除以10,数据含有1位小数的。

湿度高8位、湿度低8位、温度高8位、温度低8位、校验8位

第二步里的程序把数据都存在data[ i ] 里面了。

以DHT11 湿度值为例, 按位读出 data[0 ] ~ data[7 ] 并乘以该位的二进制值即可。

这里可以用 POW函数按位循环相加,但实测与预期有些出入,暂时用笨点的办法:

dht11_humidity = 128*data[0] + 64*data[1] + 32*data[2] + 16*data[3] + 8*data[4] + 4*data[5] + 2*data[6] + data[7]; 

比如上图标黄的 00100110 就是 0+0+32+0+0+6+2+0 = 40, 看到这里,二进制 基本功还是需要一些的,理解不了需要补些课。

需要注意的是:

实验性质,校验位未作处理,实际使用中数值偶有跳动,影响不大。

温度可能会产生负数值,这里暂不做处理,具体看手册,并不难。

新 Nano(五)自己写个库,读 DHT11 / DHT22相关推荐

  1. SpringBatch读文件(FlatFileItemReader)写据库(MyBatisBatchItemWriter)(四)

    文章目录 一.抽取顺序读取数据库公共Writer 二.mapper配置文件 三.写数据库的job 四.继承公共CommonProcesor 五.执行job 前言:我们在日常开发中可能会遇到写数据库,S ...

  2. 程序人生 | (7) “新一五计划”(博客导航)

    NLP顶会截稿时间 去年9月底,我大四的时候,曾写了一篇题为"一五计划"的博文,这也是我正式写博客以来的第一篇,其中粗浅的表达了我对入门深度学习和自然语言处理的一些看法和学习路线. ...

  3. 建立新工作簿就是建立新的计算机磁盘文件,新大学计算机基础选择题题库19.xls...

    新大学计算机基础选择题题库19.xls 知识点说明 知识块说明 选择题库 choice degree every_test gen_control item_type know_block know_ ...

  4. delphi usb 读写_写作论语 | 崔嵘:写我所读——国外整本书阅读中读写结合的理论与实践(上)...

    崔嵘简介 崔嵘,博士,首都师范大学初等教育学院副教授.硕士研究生导师, 澳大利亚弗林德斯大学教育学院客座副教授,美国明尼苏达大学访问学者,北京市语文现代化研究会秘书长.全国名师工作室联盟学术委员会学术 ...

  5. 当Github上下载的代码需要安装作者写的库时

    在GitHub上下载的代码包中有原作者写的库,需要安装. 例如下载 smote_variants 这个代码包后,运行时提示需要安装 smote_variants库.发现文件夹中有个setup.py文件 ...

  6. Ubuntu 下安装新世纪五笔输入法

    http://pinyin.sogou.com/linux/help.php 1.在此页面下 添加软件源:ppa:fcitx-team/nightly 2.之后在软件中心安装 fctix 这样就可以安 ...

  7. Linux下安装新世纪五笔输入法(附表)(for 小白)

    2018.1.31 本人刚入Linux不久,奈何自己习惯用的输入法是新世纪五笔,Linux下提供可安装的五笔并不是新世纪版本的,于是开始了漫长的百度之旅... 网上各种教程.经验,基本上关于86或98 ...

  8. 两个进程共享内存,一个写,一个读

    要求是:生产者进程生成Catalan序列,并将其写入到内存共享对象.消费者进程从共享内存中读取并输出序列.生产者进程要在命令行指定生成Catalan数的数目.例如,命令行指定5,说明生产者进程会生成5 ...

  9. c开发 易语言支持库,易写易库-用易语言开发易语言支持库.pdf

    易写易库-用易语言开发易语言支持库 易写易库(EXEK)用户手册 版本:0.2 作者:liigo,/liigo 时间:2008.10 概述 EXEK EXEK "易写易库(EEXXEEKK) ...

最新文章

  1. 构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(12)-系统日志和异常的处理②...
  2. pycharm安装numpy
  3. 【LeetCode】0938. 二叉搜索树的范围和(二叉树的遍历)
  4. 基于DirectUI搭建Windows窗体程序
  5. 打印系统里所有不包含任何错误的order list
  6. python中print怎么用_python的print怎么用
  7. 脱裤子放屁,多此一举
  8. 《大道至简》阅读笔记
  9. 2D图像生成3D点云补充材料chamfer distance和EMD
  10. 如何表达清楚一个程序:模块化设计
  11. PYPL 1 月 IDE 榜单:Visual Studio Code 猛追 IntelliJ
  12. 【Lua指南】lua脚本世界--快速入门
  13. 金士顿U盘修复工具Kingston Format Utility
  14. 工程项目进度控制的主要措施有哪些?
  15. 信息安全毕设论文选题推荐
  16. 知乎上100条简短深刻的回答
  17. 深度卷积网络:第三课
  18. Unity3d之设计模式(二)工厂模式
  19. 电脑一键装机下载重装系统详细教程
  20. Android友盟第三方登录

热门文章

  1. WebView实现改变选中区域颜色以及添加下划线
  2. OpenGL-GLSL语言入门教程(1)
  3. 打算自学一些编程,想兼职程序员打零工,想问问现在哪个程序员兼职平台单子简单,不考察接单人学历?
  4. 自动化交易系统(Auto Trading System)的一些资料
  5. Java小白入门200例81之Java接口
  6. strcmp函数实现(c语言)
  7. oa服务器优化,如何优化OA以提高访问速度
  8. Tcp通讯错误代码10061
  9. Java如何获取IP属地 ip2region failed to create searcher with x:java.io.FileNotFoundException:( 系统找不到指定的路径)
  10. Unity 性能优化基础