DHT11是一款有已校准数字信号输出的温湿度传感器。 精度湿度+-5%RH, 温度+-2℃,量程湿度20-90%RH, 温度0~50℃。

我买的封装好的模块,上边自带了上拉电阻,直接查到树莓派上即可灰、紫、蓝分别代表数据、3.3V、0V,接到树莓派的3,1,10脚,分别对应PIN8,3.3V,0V。

DHT11与单片机通讯协议为单线协议(1-wire),其实单线协议蛮厉害的,一个GPIO就能实现数据的读取,但是这个协议没有同步脉冲,所以对时序要求比较高,比如DHT11对高低电平定义如下:

低电平50us,然后一个26-28us的高电平,代表0

低电平50us,然后一个70us的高电平,代表1

也就是说,需要能分辨出40us以下的时间才能准确的测出,下边看看具体的时序:

总线空闲状态为高电平,主机把总线拉低等待DHT11响应,主机把总线拉低必须大于18毫秒,保证DHT11能检测到起始信号。DHT11接收到主机的开始信号后,等待主机开始信号结束,然后发送80us低电平响应信号.主机发送开始信号结束后,延时等待20-40us后, 读取DHT11的响应信号,主机发送开始信号后,可以切换到输入模式,或者输出高电平均可, 总线由上拉电阻拉高。

数字0表示如下图:

数字1表示如下图:

可以看出,每一位包括一开始的响应信号,都是由一个低电平跟一个高电平组成,其中响应信号为80us+80us=160us

数字0为50+26=76us

数字1为50+70=120us

为读到DHT11的状态,我编写了以下的程序:

import wiringpi2 as gpio
owpin=8 #第8脚为1-wire脚
tl=[] #存放每个数据位的时间
gpio.wiringPiSetup() #初始化wiringpi库
gpio.pinMode(owpin,1) #设置针脚为输出状态
gpio.digitalWrite(owpin,1) #输出高电平
gpio.delay(1)
###发开始指令,要求DHT11传输数据
gpio.digitalWrite(owpin,0) #拉低25ms开始指令
gpio.delay(25)
gpio.digitalWrite(owpin,1) #输出高电平,开始指令结束
gpio.pinMode(owpin,0) #设针脚为输入状态
###开始指令发送完毕,把管脚设置为高电平,并等待DHT11拉低管脚。传输数据
while(gpio.digitalRead(owpin)==1): pass #如果管脚一直是1,则一直等待。
###若被拉低,说明传输开始,应答信号+40位数据+结束标志共42位
###下边共循环45次,故意多循环几次看结果。
for i in range(45): #测试每个数据周期的时间(包括40bit数据加一个发送开始标志
tc=gpio.micros() #记下当前us数(从初始化开始算起,必要时重新初始化)
'''
一个数据周期,包括一个低电平,一个高电平,从DHT11第一次拉低信号线开始
到DHT11发送最后一个50us的低电平结束(然后被拉高,一直维持高电平,所以
最后的完成标志是一直为高,超过500ms)
'''
while(gpio.digitalRead(owpin)==0):pass #一位数据由一个低电平
while(gpio.digitalRead(owpin)==1): #加一个高电平组成
if gpio.micros()-tc>500: #如果超过500us就结束了本次循环,传输结束后
break #会被上拉电阻拉成高电平,防止进入死循环
tl.append(gpio.micros()-tc) #记录每个周期时间的us数,存到tl这个列表 print(tl) #打印结果

程序里有详细的解释,我就不再赘述,这里贴出我这里的执行结果:

[116, 68, 74, 67, 124, 64, 120, 120, 76, 71, 73, 73, 73, 73, 73, 73, 74, 67, 73, 73, 123, 120, 70, 72, 73, 79, 71, 73, 73, 74, 73, 74, 73, 70, 73, 122, 74, 117, 120, 119, 70, 508, 506, 512, 512]

现在分析一下结果:

第一个116us是应答信号,按照说明应该是160us估计是我手里这个DHT11做的不是很标准后边40个(从68us开始到最后一个70us)为40位数据,后边因为没有收到任何数据,所以都超过了500us(时间超过500us就跳出循环防止死循环)

第一个116us不管,60-80us的为0,120左右的为1,则收到的数据为:

湿度整数     湿度小数     温度整数     温度小数     校验
0001 0110  0000 0000  0001 1000  0000 0000  0010 1110
16+4+2=22  0          16+8=24    0          32+8+4+2=46

故读到的结果是湿度22%,温度24度,校验和为22+24=46,读取成功。

我又加了一些数据处理,以及读取失败重新读取的附加代码,最终代码如下:

import wiringpi2 as gpio
owpin=8 #第8脚为1-wire脚
def getval(owpin):
tl=[] #存放每个数据位的时间
tb=[] #存放数据位
gpio.wiringPiSetup() #初始化wiringpi库
gpio.pinMode(owpin,1) #设置针脚为输出状态
gpio.digitalWrite(owpin,1) #输出高电平
gpio.delay(1)
gpio.digitalWrite(owpin,0) #拉低20ms开始指令
gpio.delay(25)
gpio.digitalWrite(owpin,1) #抬高20-40us
gpio.delayMicroseconds(20)
gpio.pinMode(owpin,0) #设针脚为输入状态
while(gpio.digitalRead(owpin)==1): pass #等待DHT11拉低管脚 for i in range(45): #测试每个数据周期的时间(包括40bit数据加一个发送开始标志
tc=gpio.micros() #记下当前us数(从初始化开始算起,必要时重新初始化)
'''
一个数据周期,包括一个低电平,一个高电平,从DHT11第一次拉低信号线开始
到DHT11发送最后一个50us的低电平结束(然后被拉高,一直维持高电平,所以
最后的完成标志是一直为高,超过500ms)
'''
while(gpio.digitalRead(owpin)==0):pass
while(gpio.digitalRead(owpin)==1):
if gpio.micros()-tc>500: #如果超过500ms就结束了
break
if gpio.micros()-tc>500: #跳出整个循环
break
tl.append(gpio.micros()-tc) #记录每个周期时间的us数,存到tl这个列表 # print(tl) #反注释后可打印时间列表
tl=tl[1:] #去掉第一项,剩下40个数据位
for i in tl:
if i>100: #若数据位为1,时间为50us低电平+70us高电平=120us
tb.append(1)
else:
tb.append(0) #若数据位为0,时间为50us低电平+25us高电平=75us
#这里取大于100us就为1
# print(tb) #反注释可查看每一位状态
return tb def GetResult(owpin):
for i in range(10):
SH=0;SL=0;TH=0;TL=0;C=0
result=getval(owpin)
# print(len(result))
if len(result)==40:
for i in range(8):
#计算每一位的状态,每个字8位,以此为湿度整数,湿度小数,温度整数,温度小数,校验和
SH*=2;SH+=result[i]
SL*=2;SL+=result[i+8]
TH*=2;TH+=result[i+16]
TL*=2;TL+=result[i+24]
C*=2;C+=result[i+32]
if ((SH+SL+TH+TL)%256)==C and C!=0:
break
else:
print("Read Sucess,But checksum error! retrying")
else:
print("Read failer! Retrying")
gpio.delay(200)
return SH,SL,TH,TL SH,SL,TH,TL=GetResult(owpin)
print("湿度:",SH,SL,"温度:",TH,TL)

运行结果如下:

湿度: 20 0 温度: 24 0

树莓派高级GPIO库,wiringpi2 for python使用笔记(四)实战DHT11解码的更多相关文章

  1. 树莓派高级GPIO库,wiringpi2 for python使用笔记(一)安装

    网上的教程,一般Python用RPi.GPIO来控制树莓派的GPIO,而C/C++一般用wringpi库来操作GPIO,RPi.GPIO过于简单,很多高级功能不支持,比如i2c/SPI库等,也缺乏高精 ...

  2. 树莓派高级GPIO库,wiringpi2 for python使用笔记(三)GPIO操作

    GPIO库的核心功能,当然就是操作GPIO了,GPIO就是"通用输入/输出"接口,比如点亮一个LED.继电器等,或者通过iic spi 1-wire等协议,读取.写入数据,这都是G ...

  3. 树莓派高级GPIO库,wiringpi2 for python使用笔记(五)i2c读取测试

    wiringpi2显然也把i2c驱动带给了Python,手头上正巧有一个DS3231的模块,上边带了一个DS3231 RTC(实时时钟),与一片24C32,两个芯片均为iic总线设备,与树莓派接线如下 ...

  4. 树莓派高级GPIO库,wiringpi2 for python使用笔记(二)高精度计时、延时函数

    学过单片机的同学应该清楚,我们在编写传感器驱动时,需要用到高精度的定时器.延时等功能,wiringpi提供了一组函数来实现这些功能,这些函数分别是: micros() #返回当前的微秒数,这个数在调用 ...

  5. python学习笔记(四)

    模块与包 python模块,一个.py文件 导入模块的语法: import importable  importable#可以是包或包中的模块 import importable1,....,impo ...

  6. PYTHON 爬虫笔记四:正则表达式基础用法

    知识点一:正则表达式详解及其基本使用方法 什么是正则表达式 正则表达式对子符串操作的一种逻辑公式,就是事先定义好的一些特定字符.及这些特定字符的组合,组成一个‘规则字符串’,这个‘规则字符串’用来表达 ...

  7. python学习笔记四 迭代器,生成器,装饰器(基础篇)

    迭代器 __iter__方法返回一个迭代器,它是具有__next__方法的对象.在调用__next__方法时,迭代器会返回它的下一个值,若__next__方法调用迭代器 没有值返回,就会引发一个Sto ...

  8. Python学习笔记四--字典与集合

    字典是Python中唯一的映射类型.所谓映射即指该数据类型包含哈希值(key)和与之对应的值(value)的序列.字典是可变类型.字典中的数据是无序排列的. 4.1.1字典的创建及赋值 dict1={ ...

  9. Python学习笔记(四)Python函数的参数

    Python的函数除了正常使用的必选参数外,还可以使用默认参数.可变参数和关键字参数. 默认参数 基本使用 默认参数就是可以给特定的参数设置一个默认值,调用函数时,有默认值得参数可以不进行赋值,如: ...

随机推荐

  1. linux下不重启加硬盘

    linux下热加载磁盘 临时给虚拟机加了一块硬盘,增加后懒得重启,于是看了看热加载 [root@centos5 ~]# cat /proc/scsi/scsi Attached devices: Ho ...

  2. 第9课_3_db库安装

    四 安装listener监听 使用oracle用户,在rac1和rac2上都可以起netca 1.打开网络配置界面,选择"Cluster configuration"集群配置方案, ...

  3. C++_转换转子(4种)

    static_cast const_cast dynamic_cast

  4. echo向文件中写入

    echo命令向一个文件写入内容的方法详解,感兴趣的朋友可以参考下. 覆盖型写法 (文件里原来的内容被覆盖)echo "aaa" > a.txtecho aaa > a. ...

  5. 判断浏览器及设备的打开方式,自动跳转app中

    如果安装了APP则自动条状app,如果没安装则自动跳转下载页面 <head> 放在head中加载 <script> function redirect() { var appU ...

  6. 解析:用 CSS3 和 JavaScript 制作径向动画菜单

    原作者的解析(英文):http://creative-punch.net/2014/02/making-animated-radial-menu-css3-javascript/ 原作者的解析(译文) ...

  7. 【Howie玩docker】-windows下玩docker

    Windows下安装toolbox一直没成功,于是投机取巧,用虚拟机手工打造玩docker的方法. 步骤: 安装虚拟机,安装centos 在win下建立共享文件夹,假如是 f:/share 在cent ...

  8. Lucky Sum

    Description Lucky Sum time limit per test: 2 seconds memory limit per test: 256 megabytes input: sta ...

  9. SQL Server 向堆表中插入数据的过程

    堆表中  IAM 记录着的数据页,表的各个数据页之间没有联系.也就是说一个页面它不会知道自己的前一页是谁,也不知道自己的后一页是谁. 插入数据时先找到IAM页,再由pfs(page free spac ...

  10. 12.java.lang.NoSuchMethodException

    java.lang.NoSuchMethodException 方法不存在异常 当程序试图通过反射来创建对象,访问(修改或读取)某个方法,但是该方法不存在就会引发异常