绪:
树莓派买了有一段时间了,也折腾了几次,总想着做些分享,却又多次耽搁,今日立下Flag:两周更新一次折腾日志。
简介:
树莓派最初发布于2012年,当前已经发布了8个版本,如下图,详情参见官网链接:https://www.raspberrypi.org/products/。引用树莓派实验室的一句话来介绍树莓派:树莓派虽小,五脏俱全,它给爱折腾的极客们提供了一种新的玩具。本次将分享树莓派基于DHT11温湿度传感器的实践。
DHT11温湿度传感器原理
DHT11是一款有已校准数字信号输出的温湿度传感器。 其精度湿度+-5%RH, 温度+-2℃,量程湿度20-90%RH, 温度0~50℃,参考百度百科。它的工作原理为:主机给DHT11传感器发送一个启动信号,进行一系列交互后,传感器发送40位二进制数字,其中前8位表示湿度整数部分humidity_int,9-16位表示湿度小数部分humidity_decimal,17-24表示温度整数部分temperature_int,25-32位表示温度小数部分temperature_decimal;最后8位为检验数字check_num,当check_num=(humidity_int+humidity_decimal+temperature_int+temperature_decimal)时,本次数据传输有效,否则无效。
DHT11传感器初始化
- 树莓派通过GPIO针脚输出一个低电平,持续至少18ms,然后输出一个高电平,此为触发DHT11传感器工作的信号;
- DHT11被成功初始化后,会通过GPIO针脚输出80us的低电平,然后拉高80us,此信号表示告诉树莓派:我已被成功初始化,即将开始传送数据;
- 随后,DHT11开始向树莓派发送40位二进制数字,其中"0"对应50us的低电平加上26~28us的高电平,"1"对应50us的低电平加上70us的高电平。
上述过程用数据时序图表示如下:

树莓派与DHT11的交互
树莓派与DHT11交互就是基于DHT11传感器原理模拟上述过程来获取数据,首先通过树莓派的针脚与DHT11联接。我的设备为树莓派B+,为40针脚,其排列及不同编码下的映射如下面两张图,左图来源于树莓派实验室http://shumeipai.nxez.com/,右图可在树莓派终端通过gpio readall命令获取,在下面程序中我将演示基于BCM编码获取温湿度数据:
而DHT11有三个引脚,分分别为:VCC(供电5V),GND(接地引脚)及DATA(数据引脚),根据树莓派的针脚设定,一种连接方式为:
DHT11针脚 | 树莓派针脚 |
VCC | 2 |
DATA | 12 (BCM编码下,GPIO18号) |
GND | 6 |
实际连接图如下:
编程实现从DHT11获取温湿度
import RPi.GPIO as GPIO
import time
class RaspiTemperature(object):
def __init__(self):
self.channel = 18
self.mode = GPIO.BCM
def initial_dht11(self):
"""
初始化dht11传感器,请参考dht11工作原理:
1. 将18(BCM编码下,原始为12号)GPIO针脚置为输出模式,拉低电平,并保持18ms,然后拉高,初始化dht11;
2. 然后将18号GPIO针脚置为输入模式,接受dht11传感器的反馈;
:return:
"""
GPIO.setmode(self.mode)
time.sleep(1)
GPIO.setup(self.channel, GPIO.OUT)
GPIO.output(self.channel, GPIO.LOW)
time.sleep(0.018)
GPIO.output(self.channel, GPIO.HIGH)
GPIO.setup(self.channel, GPIO.IN)
def get_data(self):
"""
数据获取,请参考dht11工作原理:
1. dht11会先拉低电平80us,然后拉高80us,告诉树莓派,我已初始化完毕,即将开始传输数据,因此这部分在python
代码中利用while...continue处理即可
2. 获取数据:这部分为最易混淆的地方,实际这也是核心代码部分
# 数据0或1前面都有50us的低电平
while GPIO.input(self.channel) == GPIO.LOW:
continue
# 由于程序无法精确控制us级别的sleep,因此采用如下方式计算高电平的计数,这里和CPU时钟及处理速度有关系,我不懂内部原理,期待大佬分享
while GPIO.input(self.channel) == GPIO.HIGH:
k += 1
if k > 100:
break
# 如果高电平计数小于8,则为0,否则为1
if k < 8:
data.append(0)
else:
data.append(1)
:return:
"""
data = []
count = 0
# dht11拉低电平80us
while GPIO.input(self.channel) == GPIO.LOW:
continue
# dht11拉高电平80us
while GPIO.input(self.channel) == GPIO.HIGH:
continue
# 获取数据
while count < 40:
k = 0
while GPIO.input(self.channel) == GPIO.LOW:
continue
while GPIO.input(self.channel) == GPIO.HIGH:
k += 1
if k > 100:
break
if k < 8:
data.append(0)
else:
data.append(1)
count += 1
return data
def normalize_data(self, data):
"""
数据规整,这里的知识点就一个:二进制数据转为十进制数,参见方法transform_binary
:param data:
:return:
"""
humidity_int = self.transform_binary(data[0:8])
humidity_decimal = self.transform_binary(data[8:16])
temperature_int = self.transform_binary(data[16:24])
temperature_decimal = self.transform_binary(data[24:32])
check_int = self.transform_binary(data[32:40])
tmp = humidity + humidity_point + temperature + temperature_point
if check_int == tmp:
print "temperature: {}.{}*c".format(temperature_int, temperature_decimal),\
"humidity: {}.{}%".format(humidity_int, humidity_decimal)
else:
print "failed to get data from dht11"
GPIO.cleanup()
@staticmethod
def transform_binary(self, num_binary):
num = 0
for i in range(8):
num += num[i] * 2 ** (7 - i)
return num
if __name__ == '__main__':
dht11 = RaspiTemperature()
dht11.initial_dht11()
data = dht11.get_data()
dht11.normalize_data(data)
则执行脚本python *.py即可获取读数,有了这个脚本,可以把DHT11用到更多有趣的地方,如自动监控室内温度等。
注:在连接树莓派和DHT11传感器时,一定要注意连接针脚,以免烧掉传感器,我只能说:这后面有个悲伤的故事!因此这里不能贴上获取温湿度的图了。