前言
为什么将DHTx放在第二篇来讨论?第一是DHT12,DHT22温湿度采用单总线方式传输数据,使用简单且广泛。第二是DHTx系列包含在Iot.Device.DHTxx命名空间下面,可以直接调用。
DHT22简介
AM2302湿敏电容数字温湿度模块是一款含有己校准数字信号输出的温湿度复合传感器。它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有极高的可靠性与卓越的长期稳定性。传感器包括一个电容式感湿元件和一个高精度测温元件,并与一个高性能8位单片机相连接。因此该产品具有品质卓越、超快响应、抗干扰能力强、性价比极高等优点。每个传感器都在极为精确的湿度校验室中进行校准。校准系数以程序的形式储存在单片机中,传感器内部在检测信号的处理过程中要调用这些校准系数。标准单总线接口,使系统集成变得简易快捷。超小的体积、极低的功耗,信号传输距离可达20米以上,使其成为各类应用甚至最为苛刻的应用场合的最佳选择。(来源于官方手册)
产品手册下载:
电路图
DHT22当中VCC接树莓派5V引脚,GND接树莓派GND,Data接树莓派GPIO26(物理引脚37)。
注意:需要在Data引脚和Vcc引脚之间并联一个10KΩ电阻作为上拉电阻。
编写代码
using System;
using System.Device.Gpio;
using System.Threading;
namespace _2.Dht22
{
class Program
{
static void Main(string[] args)
{
try
{
//使用GPIO 16
using (Iot.Device.DHTxx.Dht22 dht = new Iot.Device.DHTxx.Dht22(26, PinNumberingScheme.Logical))
{
while (true)
{
Console.WriteLine($"Temperature: {dht.Temperature.Celsius.ToString("0.0")} ℃, Humidity: { dht.Humidity.ToString("0.0")} %");
Thread.Sleep(1000);
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
}
同样。发布之后上传至树莓派运行,可以看到正常获取当前环境温度和湿度。
分析
接下来咋们来一步一步分析整个数据读取流程是怎么样的?首先更具DataSheet所给出的流程图
整个读取流程可以分为三个步骤:
(1)SDA处于上拉状态,等待外部信号
AM2302 上电后(AM2302 上电后要等待 2S 以越过不稳定状态,在此期间读取设备不能发送任何指令),测试环境温湿度数据,并记录数据,此后传感器自动转入休眠状态。AM2302 的 SDA 数据线由上拉电阻拉高一直保持高电平,此时 AM2302 的 SDA 引脚处于输入状态,时刻检测外部信号。
(2)主机发起读取信号,并应答
树莓派的 I/O 设置为输出,同时输出低电平,且低电平保持时间不能小于 800us,典型值是拉低 1MS,然后树莓派的 I/O 设置为输入状态,释放总线,由于上拉电阻, 树莓派的 I/O 即 AM2302的 SDA 数据线也随之变高,等主机释放总线后,AM2302 发送响应信号,即输出 80 微秒的低电平作为应答信号,紧接着输出 80 微秒的高电平通知外设准备接收数据,信号传输如图 所示:
(3)接收数据
AM2302 发送完响应后,随后由数据总线 SDA 连续串行输出 40 位数据,微处理器根据 I/O 电平的变化接收 40 位数据。
位数据“0”的格式为: 50 微秒的低电平加 26-28 微秒的高电平;
位数据“1”的格式为: 50 微秒的低电平加 70 微秒的高电平;
位数据“0”、位数据“1”格式信号如图所示:
AM2302 的数据总线 SDA 输出 40 位数据后,继续输出低电平 50 微秒后转为输入状态,由于上拉电阻随之变为高电平。同时 AM2302 内部重测环境温湿度数据,并记录数据,测试记录结束,传感器内部单片机自动进入休眠状态。传感器内部单片机只有收到主机的起始信号后,才重新唤醒传感器,进入工作状态。
整个流程用程序表示如下:
static byte[] Read(int pin)
{
uint loopCount = 10000;
Stopwatch stopwatch = new Stopwatch();
byte[] readBuff = new byte[5];
byte readVal = 0;
uint count;
try
{
using (GpioController controller = new GpioController())
{
//第一步 打开GPIO,准备读取
controller.OpenPin(pin);
if (!controller.IsPinOpen(pin))
{
throw new Exception($"Open pin {pin} failed.");
}
//第二步 主机发起读取,并接收应答
controller.SetPinMode(pin, PinMode.Output);
controller.Write(pin, PinValue.Low);
// wait at least 18 milliseconds
// here wait for 18 milliseconds will cause sensor initialization to fail
DelayMicroseconds(20000, true);
//拉高,然后等待30us,准备接收信号
controller.Write(pin, PinValue.High);
DelayMicroseconds(30, true);
controller.SetPinMode(pin, PinMode.InputPullUp);
//传感器拉低,作为应答信号
count = loopCount;
while (controller.Read(pin) == PinValue.Low)
{
if (count-- == 0)
{
return null;
}
}
//拉高,作为开始信号
count = loopCount;
while (controller.Read(pin) == PinValue.High)
{
if (count-- == 0)
{
return null;
}
}
//第三步 读取40bit的数据
for (int i = 0; i < 40; i++)
{
//每位数据的起始信号,50us的低电平信号
count = loopCount;
while (controller.Read(pin) == PinValue.Low)
{
if (count-- == 0)
{
return null;
}
}
// 26 - 28 microseconds represent 0
// 70 microseconds represent 1
stopwatch.Restart();
count = loopCount;
while (controller.Read(pin) == PinValue.High)
{
if (count-- == 0)
{
return null;
}
}
stopwatch.Stop();
//位数据“0”的格式为: 50 微秒的低电平加 26-28 微秒的高电平;
//位数据“1”的格式为: 50 微秒的低电平加 70 微秒的高电平;
//这里取30us
readVal <<= 1;
if (!(stopwatch.ElapsedTicks * 1000000F / Stopwatch.Frequency <= 30))
{
readVal |= 1;
}
if (((i + 1) % 8) == 0)
{
readBuff[i / 8] = readVal;
}
}
//数据总线 SDA 输出 40 位数据后,继续输出低电平 50 微秒后转为输入状态
//一次读取结束,拉高总线,有上拉电阻的话,会自动拉高
DelayMicroseconds(50, true);
controller.SetPinMode(pin, PinMode.Output);
controller.Write(pin, PinValue.High);
}
//校验
if ((readBuff[4] == ((readBuff[0] + readBuff[1] + readBuff[2] + readBuff[3]) & 0xFF)))
{
return readBuff;
}
else
{
return null;
}
}
catch (Exception ex)
{
throw ex;
}
}
参考资料
1、DHTxx - Digital-Output Relative Humidity & Temperature Sensor Module
2、Demo下载
文章评论