天域至尊 发表于 2019-4-12 13:43

树莓派第四课之DHT11湿温度传感器

第一课,温度传感器https://www.52pojie.cn/thread-902898-1-1.html
第二课,继电器https://www.52pojie.cn/thread-903925-1-1.html
第三课,舵机https://www.52pojie.cn/thread-911228-1-1.html

第四课,DHT11湿温度传感器终于来了

懒了这么久,今天把欠的账还还。第四课,DHT11温湿度传感器,话说有了这玩意可以做自动煮蛋器啊,呀呸,自动孵蛋器,孵蛋器。肉比蛋好吃嘛,呀呸,小动物那么可爱,怎么可以吃小动物,多放孜然,谢谢。


这一期呢,我试了几种不同的方式,最后发现还是网上流传的方式准确率比较高,但是数据读取错误率依旧有30%-50%左右,暂时没找到更好的解决方案,所以说,这期主要讲怎么使用树莓派进行高低电平通信的问题,实际使用中建议采用C语言。

放心,数据读取错误程序是会发现的,不会回传错误数据

解决高低电平通信问题,无非就是两点,发消息和收消息。
发消息上次讲了,GPIO.output(端口号, GPIO.HIGH/ GPIO.LOW)就可以设置引脚的高低电平了,上一节课已经学习过了。

GPIO.HIGH是高电平, GPIO.LOW是低电平。再用time.sleep(秒数)设置下暂停的时间,就能控制波形、频率等等。
如下例程:# -*- coding: utf-8 -*-
import RPi.GPIO as GPIO #引入GPIO模块,重命名为GPIO
import time #引入time模块
GPIO.setmode(GPIO.BCM) #设置gpio引脚编号模式,有两种编号模式可供选择,自己随意设置就好
GPIO.setup(13, GPIO.OUT) #设置13号口为输出模式
while True: #进入死循环
    GPIO.output(13, GPIO.HIGH) #13号口输出高电平
    time.sleep(0.02) #程序暂停0.02秒
    GPIO.output(13, GPIO.LOW) #13号口输出高电平
    time.sleep(0.02) #程序暂停0.02秒
GPIO.cleanup() #关闭所有端口

这样,程序在死循环里,每隔0.02秒就将电平翻转,那不就是周期为0.04秒的方波了吗。

这就是发送信号,很简单吗,但是怎么接收信号呢?

这时候同学们肯定发现,上面有一句这个GPIO.setup(13, GPIO.OUT) #设置13号口为输出模式

那我把GPIO.OUT改为GPIO.IN不就行了。

似乎Python会帮我们处理一切心意,但是可以吗?我们先做测试。

我们初步设想是这样1.   将一个端口设置为接收模式。2.   编写一个程序,输出这个模式接收到的信息。3.   我们手动将该端口接到高低电平上,观看效果。

好的,那我们就来试试吧。# -*- coding: utf-8 -*-
import RPi.GPIO as GPIO #引入GPIO模块,重命名为GPIO
import time
GPIO.setmode(GPIO.BCM) #设置gpio引脚编号模式,有两种编号模式可供选择,自己随意设置就好
GPIO.setup(6, GPIO.IN) #设置6号口为输入模式
print(GPIO.input(6)) #输出6号口的状态

启动!
我们发现,我们将6号口置于高电平,则显示是1,置于低电平则显示是0.那么,我们成功了吗?
我们修改下程序,让他不断去侦测,显示。# -*- coding: utf-8 -*-
import RPi.GPIO as GPIO #引入GPIO模块,重命名为GPIO
import time
GPIO.setmode(GPIO.BCM) #设置gpio引脚编号模式,有两种编号模式可供选择,自己随意设置就好
GPIO.setup(6, GPIO.IN) #设置13号口为输出模式
while True:
    print(GPIO.input(6))

运行后我们发现,程序会非常快速的输出,即使你的电平没有变化,他依然是快速输出。比如你置为高电平,则一直输出1,以最快速的方式。

其中将6号口悬空,会发生误判断,则随机显示0或1。

好了,我们继续修改测试程序,让他无变化则不显示。# -*- coding: utf-8 -*-
import RPi.GPIO as GPIO #引入GPIO模块,重命名为GPIO
import time
GPIO.setmode(GPIO.BCM) #设置gpio引脚编号模式,有两种编号模式可供选择,自己随意设置就好
GPIO.setup(6, GPIO.IN) #设置13号口为输出模式
while True:
    i=GPIO.input(6)
    if i != GPIO.input(6):
      print(GPIO.input(6))
      i=GPIO.input(6)
这样的话,只有在端口发生变化的时候才显示,果然不错。

好了,基础学会了,我们去了解下DHT11传感器的通信方式吧。

啥是DHT11传感器?


估价的话5-6元
它能够测量环境里的温度,湿度数据

DHT11建议每次查询数据的间隔时间要大于2秒钟,否则可能会出现数据不准确的情况。


首先由主机发送起始信号,起始信号为低电平,时间大于18ms

然后传感器开始应答,先输出80μs的低电平,然后输出80μs的高电平,提醒主机准备接收信号。

随后传感器开始传输数据,共发射四十位数据,前八位为温度数据整数位,再往后八位为温度数据小数位,再往后八位是湿度数据整数位,再往后八位是湿度数据小数位,再往后八位是校验位
数据0的表示方式为:50μs的低电平和 26-28μs的高电平。
数据1的表示方式为:50μs的低电平加 70μs的高电平。


校验方式为:
数据传送正确时校验和数据等于“ 8bit 湿度整数数据 +8bit 湿度小数数据+8bi 温度整数数据 +8bit 温度小数数据 ”所得结果的末8位。



说吧,现在多少人去厕所哭了。

网上有人给了一个点子,检测到低电平变为高电平后,开始进入循环,每循环一次就计数加一,如果输入是0,计数会少些,如果输入是1,计数会多些。
经过测试,输入是0时,计数往往低于8次,计数是1时,计数往往多于8次,如此就可以断别。

哦,对了,1秒=1,000,000微秒。

所以,1微秒等于0.000001秒。

对了,上面的参数哪里去挖?后山去挖,可以去网上百度该模块的技术手册,也可以去找淘宝卖家要。

这一次的流程比较复杂,大家注意看流程图

哇,夭寿了,因为用户组限制,这次流程图太大了,传不上去啊,压缩了还看个毛啊,全模糊了怎么看。

流程图和代码一起传了百度网盘,大家去那看吧。

好了,流程图看好了以后,大家心里大概已经清楚了,代码基本上每一步都有注释,大家可以看下。
# -*- coding: utf-8 -*-
import RPi.GPIO as GPIO #引入GPIO模块,重命名为GPIO
import time#引入时间模块
channel=6#设置端口号
j=0#初始化计数器为0
data=[]#初始化数据存储数组

GPIO.setmode(GPIO.BCM) #设置gpio引脚编号模式,有两种编号模式可供选择,自己随意设置就好
time.sleep(1)#程序暂停一秒钟
GPIO.setup(channel, GPIO.OUT) #设置6号口为输出模式
GPIO.output(channel, GPIO.LOW)#6号口输出低电平,即发送触发信号
time.sleep(0.02)#低电平维持0.02秒
GPIO.output(channel, GPIO.HIGH)#输出高电平,标志低电平结束
GPIO.setup(channel, GPIO.IN)#设置端口模式为输入
while GPIO.input(channel)==GPIO.LOW:#跳过初始状态的低电平
    pass
while GPIO.input(channel)==GPIO.HIGH:#跳过初始状态的高电平
    pass

#进入循环
while j < 40:#仅仅存储40个数据
        k = 0
        while GPIO.input(channel) == GPIO.LOW:#跳过低电平
                continue
       
        while GPIO.input(channel) == GPIO.HIGH:#如果是高电平,则进入循环,高电平结束时停止
                k += 1#计数器自增
                if k > 100:#如果高电平计数器大于100,则跳出循环,数据错误
                        break
       
        if k < 8:#如果计数器数值小于8次,则认为值为0
                data.append(0)
        else:#否则认为值为1
                data.append(1)

        j += 1#数据位数计数器加一

#按位切割数据
humidity_bit = data
humidity_point_bit = data
temperature_bit = data
temperature_point_bit = data
check_bit = data

humidity = 0
humidity_point = 0
temperature = 0
temperature_point = 0
check = 0

#计算各个数据结果和校验值
for i in range(8):
        humidity += humidity_bit * 2 ** (7 - i)
        humidity_point += humidity_point_bit * 2 ** (7 - i)
        temperature += temperature_bit * 2 ** (7 - i)
        temperature_point += temperature_point_bit * 2 ** (7 - i)
        check += check_bit * 2 ** (7 - i)
#计算检查值
tmp = humidity + humidity_point + temperature + temperature_point


if check == tmp:
    print('数据正确')
    print("温度: "+str(temperature)+", 湿度: "+str(humidity))
else:
        print('数据错误')
        print("温度: "+str(temperature)+",湿度: "+str(humidity)+"校验值: "+str(check)+" 检查值: "+str(tmp))

GPIO.cleanup()


这时候可能有人已经要跳出来喊,你是抄袭的。事实上,我并不是抄袭,我引用了网上主流的代码,对其加以修改和注释,其原版仅仅能够在python2.X版本下运行,我将其升级到了python3,同时完善了注释和流程解释。可以说,当前互联网上针对于这个代码最详细,最准确的教程就在我这了。相信意义党也应该觉得这次教程编写的有意义吧。

因为网上对该代码抄袭严重,质量参差不齐,实在难以找到原作者是谁,故无法声明原作者的原著链接,但在此对原作者表示感谢。本次教程本人不声明版权,大家可以引用转载。

流程图和代码都在这里:链接:https://pan.baidu.com/s/13hHWYNpaxhjUlDN1DnKlUw 提取码:jkk8

这里只有代码,流程图放压缩包就超过用户组限制了……

愤怒,愤怒,图片传不上去好痛苦,严重影响教程质量,希望吾爱的文件大小限制放宽些,太痛苦了这样。

ptkid 发表于 2019-4-19 09:41

这个其实用esp8266刷ESP EASY做很方便的,固件刷进去,然后把线接好,登录到固件页面,选好针脚开启获取信息,比在树莓派上做方便,树莓派可以通过python来获取esp easy 上JSON的数据,这样就可以和设备脱离了,不然树莓派必须放在检测环境的附近,由于线缆连接的原因。

DEFwa 发表于 2019-4-12 14:27

好东西,学习一下

by、怒神 发表于 2019-4-12 16:12

感谢大佬分享

jjijj 发表于 2019-4-12 20:50

虽然看不懂,但是仍然要支持你。

hfg123 发表于 2019-4-14 10:53

学习一下

grufield 发表于 2019-4-20 15:08

家里的树莓派吃灰了,来学习一下

Darusyu 发表于 2019-4-20 18:28

可以当毕设用了,可以

矛盾迷茫 发表于 2019-9-17 21:25

感谢,感谢:loveliness:

beyond0518 发表于 2021-1-7 20:45

学习了。最近在研究树莓派
页: [1] 2
查看完整版本: 树莓派第四课之DHT11湿温度传感器