玩转树莓派入门系列——4.传感器系列之温湿度模块DHT11
一、DHT11介绍
1、DHT11和DHT22
一般的温湿度传感器有DHT11和DHT22,两者的差别在与价格与精确度。DHT11便宜但精度范围大,DHT22贵但精度范围小。
2、引脚说明
a) VDD 供电3.3-5.5V DC
b) DATA串行数据,单设备
c) NC 空脚
d) GND 接地,电源负极
3、参数
4、通信原理
DHT11器件只有一根数据线,即单总线通信,所以对于时序要求比较大。由于DHT11是主从结构,所以只有当主机发起通信请求时,从机才会开始应答。
数据格式:
8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据+8bit校验位
a、起始信号:
主机把SDA(数据总线)拉低18ms<x<30ms
b、响应信号:
从机把SDA拉低83us,再拉高87us响应起始信号
c、数据信号:
“0”的格式为:54微秒的低电平+23到27微秒的高电平
“1”的格式为:54微秒的低电平+68到74微秒的高电平
d、结束信号:
从机的DATA引脚输出40位数据后,继续输出54微秒的低电平后转换为输入状态。
e、数据格式:
收到主机信号后,从机一次性从SDA串出40bit,高位先出
f、温度:
高位为温度整数部分,低位为温度小数部分
g、湿度:
高位为温度整数部分,低位为湿度小数部分
低位第8位1表示负温度,否则位正温度
h、校验位:
校验位=湿度高位+湿度低位+温度高位+温度低位
5、时序图
a、步骤一:
DHT11上电后,要等待超过1s时间等待电平稳定,同时DHT11的SDA处于高电平,DATA引脚处于输入状态,时刻监测外部信号。
b、步骤二:
主机发送低电平,拉低SDA电平,至少超过18ms(最大不超过30ms),然后主机拉高电平,等待从机做出应答信号。
c、步骤三:
DHT11的DATA引脚监测到起始信号后,等待起始信号结束,再输出83微秒的低电平作为应答信号,然后输出87微秒的高电平通知外设准备接收数据,然后主机的IO口就处于输入状态等待数据接收。
d、步骤四:
主机开始接收40位的数据,
“0”的格式为:54微秒的低电平+23到27微秒的高电平
“1”的格式为:54微秒的低电平+68到74微秒的高电平
e、步骤五:
结束信号,DHT11的DATA引脚输出40位数据后,继续输出54微秒的低电平后转换为输入状态。
二、DHT11接入树莓派4B
刚买回来的DHT11模块集成在一块板子上,提供三个引脚:VCC、DATA和GND。很明显,VCC接3.3V电源,GND接地,DATA引脚接入GPIO口,从树莓派4b的GPIO引脚图。我们把VCC接1脚,DATA接7脚,GND接9脚,其中DATA脚对应GPIO.7(BCM为4,WiringPi为7)。
三、DHT11读取数据
1、通过系统功能读取
树莓派有一个Device Tree(DT)功能,即在/boot/overlays发现外设,并加载到系统上去,其操作只要在/boot/config.txt进行对应的外设配置,重启后,就可以在/sys/devices下找对对应的外设。
修改/boot/config.txt
dtparam=i2c_arm=on
dtparam=spi=on
dtoverlay=dht11
重启
reboot
采集数据
DHT11Path="/sys/devices/platform/dht11@4/iio:device0"
HumidityRelative=$(awk '{print $1 / 1000 }' ${DHT11Path}/in_humidityrelative_input)
RoomTemp=$(awk '{print $1 / 1000 }' ${DHT11Path}/in_temp_input)
这个方法经常因为1-write协议本身的缘故,1bit数据丢失,就会导致数据无法读出。
解决方法只能通过多次读值,取正常值。
2、通过Adafruit库读取
更新源软件包
apt update
apt upgrade
apt install build-essential python-dev python3-dev python-pip python3-pip
获取Adafruit库
apt install git
sudo git clone https://github.com/adafruit/Adafruit_Python_DHT.git
修改Adafruit对树莓派4B的支持
vi Adafruit_Python_DHT/Adafruit_DHT/platform_detect.py
#在elif match.group(1) == 'BCM2837': > #Pi 3b+ >return 3后面加入新的分支
elif match.group(1) == 'BCM2711':
#Pi 4B
return 3
安装Adafurit库
python setup.py install
python3 setup.py install
执行demo获取温湿度
#11代表DHT11,4代表gpio4
python AdafruitDHT.py 11 4
#或
python3 AdafruitDHT.py 11 4
3、通过C编程读取
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <wiringPi.h>
typedef unsigned char uint8;
typedef unsigned int uint16;
typedef unsigned long uint32;
uint32 databuf;
/*
//初始化引脚
//上电1s内不操作,维持电平稳定
*/
void GPIO_init(int gpio_pin)
{
pinMode(gpio_pin, OUTPUT); // set mode to output
digitalWrite(gpio_pin, 1); // output a high level
sleep(1);
return;
}
/*
//起始信号
1.主机初状态是高电平,要超过1s稳定电平
2.主机再拉低延时18ms-30ms
3.主机末状态是高电平,等待
*/
void DHT11_start(int gpio_pin)
{
pinMode(gpio_pin, OUTPUT);
digitalWrite(gpio_pin, 0);
delay(25);
digitalWrite(gpio_pin, 1);
pinMode(gpio_pin, INPUT);
pullUpDnControl(gpio_pin, PUD_UP); //当引脚被配置为输入(INPUT)模式,使用函数pullUpDnControl来激活其内部的上拉电阻或下拉电阻
delayMicroseconds(27);
return;
}
/*
//主机接受数据
1.主机接受到从机回复的响应信号
2.格式0——54us的低电平+23到27us的高电平
格式1——54us的低电平+68到74us的高电平
3.思路:从识别到低电平开始,然后去除掉掉前面54秒的低电平还有
*/
uint8 DHT11_read(int gpio_pin)
{
uint8 crc, i;
if (0 == digitalRead(gpio_pin)) //主机接收到从机发送的响应信号(低电平)
{
while(!digitalRead(gpio_pin)); //主机接收到从机发送的响应信号(高电平)
for (i = 0; i < 32; i++)
{
while(digitalRead(gpio_pin)); //数据位开始的54us低电平
while(!digitalRead(gpio_pin)); //数据位开始的高电平就开始
delayMicroseconds(32); //跳过位数据,32us已经是数据0和数据1的差距点
databuf *= 2;
if (digitalRead(gpio_pin) == 1)
{
databuf++;
}
}
for (i = 0; i < 8; i++)
{
while (digitalRead(gpio_pin));
while (!digitalRead(gpio_pin));
delayMicroseconds(32);
crc *= 2;
if (digitalRead(gpio_pin) == 1)
{
crc++;
}
}
return 1;
}
else
{
return 0;
}
}
int main(int argc, char *argv[])
{
if (2 != argc)
{
printf("Usge: %s <gpio_pin>\n", argv[0]);
return 0;
}
if (-1 == wiringPiSetup())
{
printf("Setup WiringPi failed!\n");
return 1;
}
while(1)
{
GPIO_init(atoi(argv[1]));
DHT11_start(atoi(argv[1]));
if (DHT11_read(atoi(argv[1])))
{
printf("RH:%d.%d\n", (databuf >> 24) & 0xff, (databuf >> 16) & 0xff);
printf("TMP:%d.%d\n", (databuf >> 8) & 0xff, databuf & 0xff);
databuf = 0;
}
else
{
printf("Sensor dosent ans!\n");
databuf = 0;
}
sleep(3);
}
return 0;
}
编译执行
这里要用sudo权限,并且引脚值要对应好,GPIO-7的Wiring值对应7
gcc -o DHT DHT11.c -lwiringPi
sudo ./DHT 7
4、通过Python编程读取
对Python不熟,暂时无输出。