1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > 超详细!基于树莓派Python编程使用dht11温湿度模块

超详细!基于树莓派Python编程使用dht11温湿度模块

时间:2022-03-19 17:48:00

相关推荐

超详细!基于树莓派Python编程使用dht11温湿度模块

超详细!基于树莓派Python编程使用dht11温湿度模块

前言:

本人树莓派小白(电路知识也很有限),在树莓派上使用dht11模块时没有在网络上找到 很详细的教程,因此经历两天的摸索才得以正确使用该模块,所以我萌生了写一篇较为详细的教程的想法。如果同为小白,仔细研究dht11的使用会为其他的模块使用打下坚实的基础(例如:超声波模块、寻路模块等),如果你没有耐心看完本文可去文章末尾拿代码。

一、材料

1.树莓派

2.dht11温度模块

3.杜邦线(买模块一般都会送)

二、连线

dht11模块包含三个引脚:VCC(正极3.3v)、DATA(数据传输口)、GND(负极或0电位)树莓派GPIO参考图(本文使用BOARD编码即下图的编码模式)

其中VCC接树莓派任意3.3v接口

DATA接树莓派任意GPIO(本文接12)

GND接树莓派任意GND

VCC与GND勿接反(据说接反必烧)

三、dht11通信原理及对应Python编程

1.首先,对进行准备工作,引入一些库(官网系统自带,无需安装)和定义一下引脚。

import RPi.GPIO as GPIO #引入RPi.GPIO模块,并实例化为GPIO,简化后面的模块调用import time#引入time模块GPIO.setmode(GPIO.BOARD) #定义GPIO编码方式time.sleep(2)#由于dht11的采样周期间隔为2s,此处防止dht无方响应Pin=12 #定义引脚,使用哪个就定义哪个

2.DATA 用于树莓派与 DHT11之间的通讯和同步,采用单总线数据格式,一次通讯时间4ms左右,数据分整数部分和小数部分,一次完整的数据传输为40bit(40个二进制数),高位先出(代码在第5点处一并说明)(dht11与树莓派的通信过程见下图)。

3.dht11默认处于高电平状态 ,当树莓派发送开始信号(1段大于18μs的低电平),dht11接收到树莓派的开始信号后会转为工作模式,此时应将树莓派转的GPIO转为高电平状态然后将GPIO转为输入模式用于接收dht11的信号。

GPIO.setup(Pin,GPIO.OUT) #将GPIO设置为输出模式GPIO.output(Pin,0)#向dht11发送低电平(开始信号)(其中0可以用Flase、GPIO.low代替,下文的1同理)time.sleep(0.02) #低电平持续时间0.02s大于dht11要求的0.018sGPIO.output(Pin,1)#向dht11发送高电平(理论上可以取消,但是实际使用中不发送高概率出错)GPIO.setup(Pin,GPIO.IN)#将GPIO转为输入模式,用以接收dht11的信号

4.接收到开始信号后dht11首先会发送一段持续80μs的低电平信号和80μs的高电平信号以回复树莓派的开始信号,然后将会发送40bit(40个二进制数)的湿度温度数据,每个bit都将以一段持续50μs的低电平信号开始(信号的开头是一样的,因此无法判断是0还是1),然后续以一段时间不等的高电平信号,其中如果发送二进制"0"将持续26-28μs,二进制"1"将持70μs。因此后续编程将根据高电平信号持续的时间来判断dht11发送的信号是0还是1。(前三行赋值代码放到这里是便于理解,实际运行过程高概率因为数据接收不全卡死,在后面会介绍一下)

Bit=[] #定义列表,用以存储接收到的数据Time=[]#存储数字0和数字1的高电位持续时间K=0#定义循环初始值while GPIO.input(Pin)==0: #采用轮训检测dht的响应信号,如果输入高电平将跳出此循环(不懂可以查阅python的while continue用法)continuewhile GPIO.input(Pin)==1: #采用轮训检测dht的响应信号continuewhile K<40: #循环40次用以接收dht11的40bit数据while GPIO.input(Pin)==0:#因为每bit数据以低电平开始,故此。continuebegin=time.time() #低电平循环结束故此时是高电平信号,因此开始计时while GPIO.input(Pin)==1:#轮训高电平continueend=time.time() #获取高电平信号的结束时间#Time.append(end-begin)#此处为了确定0和1的高电平持续时间if (end-begin)<0.00003: #检测高电平的持续时间判断输入是0还是1(0.00003可以自测一下,取一个适合你的时间)Bit.append(0) #高电平小于0.00003s证明是0else:Bit.append(1) #高电平大于0.00003s证明是1K=K+1 #记录循环次数#print(Time)#观察时间特点以确定上文0.00003的取值

5.将得到40bit数据进行拆分、校验并转换为10进制数输出。

humidity1bit=Bit[0:8] #根据dht11的信号原理获取所需的值(下同理)humidity2bit=Bit[8:16]temperature1bit=Bit[16:24]temperature2bit=Bit[24:32]checkbit = Bit[32:40]humidity1=0humidity2=0temperature1=0temperature2=0check=0for i in range(0,8): #循环8次,将二进制数转换为十进制数humidity1+=humidity1bit[i]*(2**(7-i))humidity2+=humidity2bit[i]*(2**(7-1))temperature1+=temperature1bit[i]*(2**(7-i))temperature2+=temperature2bit[i]*(2**(7-i))check+=checkbit[i]*(2**(7-i))temperature=temperature1+temperature2*0.1 #获取温度值(注意dht11的使用说明中明文写到整数位后是小数位故应乘0.1)humidity=humidity1+humidity2*0.1 #(网上大部分都没乘0.1,他们的运行结果是整数,足可见网上的帖子都是复制粘着的水文)checknum=temperature1+humidity1+temperature2+humidity2 #计算前32位数的值if checknum==check:#检查前32位的值是否与校验位相等print("temp:%s,hum:%s"%(temperature,humidity)) #相等输出温度和湿度else:print("dht11 check was wrong. checknum:%s check:%s"%(

四、本人实际运行时遇到的一些错误

1.在准备阶段,由于dht11使用说明显示发送低电平开始信号后,可直接将GPIO调到输入模式。但是在实际操作过程中,将GPIO直接调到输入状态,后续接受到的数据高概率出现校验码不符的情况,如果在发送开始信号后加上发送高电平信号代码会减少此类错误。

2.本人第一次采用模块化编程,但是这种编程手段运行速度缓慢,会发生接收数据不全的情况,然后会卡到while循环的高电平状态,无法退出。

3.切记采用我这种检测高电平信号持续时间的方法,不要在whlie k <40:的循环内加入print等函数,不然会导致类似问题二循环不能退出的问题。

4.赋值语句要放到开头不然影响代码运行进度,而造成数据接收不全卡死在while循环内.(具体原因是dht11输出信号后会转入高电平状态,而赋值语句的加入影响代码运行进度使接收到的数据小于40bit而无法跳出while循环)

``

while K<40:while GPIO.input(Pin)==0:continuebegin=time.time()while GPIO.input(Pin)==1:#我断点测试卡到这里,符合推测continueend=time.time()if (end-begin)<0.00003:Bit.append(0)else:Bit.append(1)K=K+1

五、完整代码及注释

import RPi.GPIO as GPIO #引入RPi.GPIO模块,并实例化为GPIO,简化后面的模块调用import time#引入time模块Bit=[] #定义列表,用以存储接收到的数据Time=[]#存储数字0和数字1的高电位持续时间K=0#定义循环初始值GPIO.setmode(GPIO.BOARD) #定义GPIO编码方式time.sleep(2)#由于dht11的采样周期间隔为2s,此处防止dht无方响应Pin=12 #定义引脚,使用哪个就定义哪个GPIO.setup(Pin,GPIO.OUT) #将GPIO设置为输出模式GPIO.output(Pin,0)#向dht11发送低电平(开始信号)(其中0可以用Flase、GPIO.low代替,下文的1同理)time.sleep(0.02) #低电平持续时间0.02s大于dht11要求的0.018sGPIO.output(Pin,1)#向dht11发送高电平(理论上可以取消,但是实际使用中不发送高概率出错)GPIO.setup(Pin,GPIO.IN)#将GPIO转为输入模式,用以接收dht11的信号while GPIO.input(Pin)==0: #采用轮训检测dht的响应信号,如果输入高电平将跳出此循环(不懂可以查阅python的while continue用法)continuewhile GPIO.input(Pin)==1: #采用轮训检测dht的响应信号continuewhile K<40: #循环40次用以接收dht11的40bit数据while GPIO.input(Pin)==0:#因为每bit数据以低电平开始,故此。continuebegin=time.time() #低电平循环结束故此时是高电平信号,因此开始计时while GPIO.input(Pin)==1:#轮训高电平continueend=time.time() #获取高电平信号的结束时间#Time.append(end-begin)#此处为了确定0和1的高电平持续时间if (end-begin)<0.00003: #检测高电平的持续时间判断输入是0还是1(0.00003可以自测一下,取一个适合你的时间)Bit.append(0) #高电平小于0.00003s证明是0else:Bit.append(1) #高电平大于0.00003s证明是1K=K+1 #记录循环次数#print(Time)#观察时间特点以确定上文0.00003的取值humidity1bit=Bit[0:8] #根据dht11的信号原理获取所需的值(下同理)humidity2bit=Bit[8:16]temperature1bit=Bit[16:24]temperature2bit=Bit[24:32]checkbit = Bit[32:40]humidity1=0humidity2=0temperature1=0temperature2=0check=0for i in range(0,8): #循环8次,将二进制数转换为十进制数humidity1+=humidity1bit[i]*(2**(7-i))humidity2+=humidity2bit[i]*(2**(7-1))temperature1+=temperature1bit[i]*(2**(7-i))temperature2+=temperature2bit[i]*(2**(7-i))check+=checkbit[i]*(2**(7-i))temperature=temperature1+temperature2*0.1 #获取温度值(注意dht11的使用说明中明文写到整数位后是小数位故应乘0.1)humidity=humidity1+humidity2*0.1 #(网上大部分都没乘,他们的运行结果是整数,足可见网上的帖子都是复制粘着的水文)checknum=temperature1+humidity1+temperature2+humidity2 #计算前32位数的值if checknum==check:#检查前32位的值是否与校验位相等print("temp:%s,hum:%s"%(temperature,humidity)) #相等输出温度和湿度else:print("dht11 check was wrong. checknum:%s check:%s"%(checknum,check))#不等输出前32位值和校验位值

六、附录

1.dht11原理:

链接:/s/1bdQ0y9RWzJmOeZz986PJDg

提取码:tqzh

2.Python代码下载:

链接:/s/1F4qF0RY_xuFe5OJhgowPUg

提取码:qgxz

3.本人亲测使用树莓派IDE运行出错概率远高于使用命令行:sudo python dht11.py

4.对与0和1的判断网上有与我不同的想法,他的想法很巧妙(通过检测在高电平持续时间内能进行多少次赋值运算,进而通过检测k值来判断高电平持续时间),但有点难以理解(不如我的来的直接)可作为参考(我的代码和他的代码均有一定概率出错)

while j < 40:k = 0while GPIO.input(channel) == GPIO.LOW:continuewhile GPIO.input(channel) == GPIO.HIGH:k += 1if k > 100:breakif k < 8:data.append(0)else:data.append(1)j += 1

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。