第二次培训任务:对dht11的基本了解

(撰写时间2020-07-29)

一、介绍

DHT11是温度湿度测量二合一传感器。非常适用于对精度和实时性要求不高的温湿度测量场合。

 

外形如下图:

无
图1 外形
无
图2 规格

DHT11温湿度传感器的测量范围,以及精度、分辨率如下图。如果超出了这个范围,那么DHT11就不能够使用了。

无
图3 参数特性

二、硬件认识

  1. 单总线结构
  2. 引脚说明:GND、VCC、空脚、数据引脚DATA(其中数据引脚既可以接收数据,又可以发送数据)。电源引脚(VDD,GND)之间可增加一个100nF的电容,用以去耦滤波,即减少电子器件辐射噪音。
  3. 时序主要分为三部分:1:触发DHT11采集数数据;2:读取数字0;3:读取数字1
无
图4 数据时序图

dth11的介绍文章中,硬件原理图显示:物品接在1号、2号引脚之间,数据总线DATA(即为2号引脚)使用上拉电阻拉高,因此总线空闲时为高电平。硬件原理图如下:

无
图5 硬件原理图

我很疑惑上拉电阻的作用,在另一篇介绍dth11的文章中,有以下讲解:上拉电阻的作用是在单片机不进行输出以及传感器待机时,使得DATA口为高电平。电平就是电压,这里只是叫法不一样。

三、工作过程与原理

1.参考dht11官方手册

单片机将驱动总线的IO配置为输出模式。准备向DHT11发送数据。单片机将驱动总线的IO配置为输入模式,准备接收DHT11回传的数据。数据格式:8bit 湿度整数数据 + 8bit 湿度小数数据 + 8bit 温度整数数据 + 8bit 温度小数数据 + 8bit 校验位。因为湿度小数数据和温度小数数据都被设定为0(8个0),所以有用的只有湿度整数数据,温度整数数据和校验位。

用户MCU发送一次开始信号后,DHT11从低功耗模式转换到高速模式,等待主机开始信号结束后,DHT11发送响应信号,送出40bit的数据(DHT11用的是单总线协议,一次传送40位的数据,并触发一次信号采集,用户可选择读取部分数据。该模式下,DHT11接收到开始信号触发一次温湿度采集,如果没有接收到主机发送开始信号,DHT11不会主动进行温湿度采集。采集数据后转换到低速模式。

无
通讯过程

 

我的理解是主机先把总线拉低,等待dht11检测到起始信号,在起始信号结束后的20-40us之间,dht11发送80us低电平来响应起始信号,之后由主机读取dht11的响应信号,并发送开始信号,由此主机切换到输入模式,或者输出高电平。而开始被主机拉低的总线,就由上拉电阻拉高。

开始时候的互动过程

总线为低电平,说明DHT11发送了响应信号。DHT11发送响应信号后,再把总线拉高80us,准备发送数据,每一bit数据都以50us低电平开始,高电平的时间长短定了数据位是0还是150 微秒的低电平和 26-28 微秒的高电平表示“0”, 50 微秒的低电平加 70 微秒的高电平表示“1”。

数字0信号表示方式
数字1信号表示方式

如果读取响应信号为高电平,则DHT11没有响应,请检查线路是否连接正常.当最后一bit数据传送完毕后,DHT11拉低总线 50us,随后总线由上拉电阻拉高进入空闲状态。

2.参考相关文章:DHT11温湿度传感器编程思路以及代码的实现

一. 单片机上点后1s内不读取(不重要)

二. 主机(单片机)发送起始信号:1.主机先拉高data。2.拉低data延迟18ms。3.拉高data(单片机引脚设置为输入)。
三. 从机(DHT11)收到起始信号后进行应答:从机拉低data,主机读取到data线被拉低持续80us后从机拉高data线, 持续80us,直到高电平结束,意味着主机可以开始接受数据。
四. 主机开始接收数据:
        1.主机先把data线拉高(io设置为输入)。
        2.从机把data线拉低,主机读取data线电平,直到低电平结束(大约50us)从机拉高data线后,延迟40us左右(28~70us之间)主机再次读取data线电平,如果为低电平,则为“0”,如果为高电平,则为“1”。
        3.继续重复上述1,2步骤累计40次。

五. data线拉低50us代表读取结束

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

四、运行

DHT11.ino

#include <Arduino.h>
#include <SoftwareSerial.h>
#include "DHT11.h"

#define fan 9                     
#define beep 10                   
DHT11 myDHT11(11);
SoftwareSerial mySerial(12, 13); // RX, TX

char ssid[] = "FENG";                        //这里填写自己的Wifi账号
char password[] = "12345678";             //这里填写自己的Wifi密码

#define DevicesID 516128482
char APIkey[] = "wsZg=kanSndl6XnjadWqwbgDi=E=";  

int temp=1;
int humi=1;

void set_ESP8266(void)
{
    Serial.begin(115200);                  //设置esp8266波特率为115200
    delay(1000);
    Serial.println("AT");                  //判断模块是否正常
    delay(1000);
    Serial.println("AT+CWMODE=3");         //设置WIFI应用模式
    delay(1000);
    Serial.println("AT+RST");              //重置WIFI模块
    delay(3000);
    Serial.print("AT+CWJAP=\"");          //连接无线路由器
    Serial.print(ssid);
    Serial.print("\",\"");
    Serial.print(password);
    Serial.println("\"");
    delay(8000);
    Serial.println("AT+CIPSTART=\"TCP\",\"183.230.40.33\",80");   //和服务器建立TCP连接
    delay(1000);
    Serial.println("AT+CIPMODE=1");       //进入透明传输模式
    delay(3000);
    Serial.println("AT+CIPSEND");         //开始传输
    delay(2000);
}

void setup()      //Arduino程序初始化程序放在这里,只在开机时候运行一次
{             
    mySerial.begin(9600);          //设置sim900a波特率为9600
    pinMode(fan,OUTPUT);           //确定引脚的功能, OUTPUT 数字输出
    pinMode(beep,OUTPUT);
    digitalWrite(fan,HIGH);       //设定风扇引脚为高电平
    digitalWrite(beep,HIGH);
    set_ESP8266();               //连网,与onenet建立连接,开启透传
}


void loop()     //Arduino程序的主程序部分,循环运行内部程序
{
    myDHT11.DHT11_Read();               //读取温湿度值
    ESP8266_SendMessage();
     
    if(myDHT11.TEM_Buffer_Int>30 || myDHT11.HUMI_Buffer_Int>50)
    {
        digitalWrite(beep,LOW);          //输出LOW电平,发声
        digitalWrite(fan,LOW);
        SIM900A_SendMessage();
    }
    else                          
    {
        digitalWrite(beep,HIGH);          //输出HIGH电平, 停止发声
        digitalWrite(fan,HIGH);
    }
    //delay(1000);        //延时1s
}

void ESP8266_SendMessage(void)           //合成post请求
{
    Serial.print("POST /devices/");
    Serial.print(DevicesID);
    Serial.println("/datapoints HTTP/1.1"); 
    Serial.print("api-key:");
    Serial.println(APIkey);  
    Serial.println("Host:api.heclouds.com");
    Serial.println("Content-Length: 59");
    Serial.println("");
    Serial.print("{\"datastreams\":[{\"id\":\"Temp\",\"datapoints\":[{\"value\":");
    Serial.print(myDHT11.TEM_Buffer_Int);
    Serial.println("}]}]}");
    delay(1000); 
  
    Serial.print("POST /devices/");
    Serial.print(DevicesID);
    Serial.println("/datapoints HTTP/1.1"); 
    Serial.print("api-key:");
    Serial.println(APIkey);  
    Serial.println("Host:api.heclouds.com");
    Serial.println("Content-Length: 59");
    Serial.println("");
    Serial.print("{\"datastreams\":[{\"id\":\"Humi\",\"datapoints\":[{\"value\":");
    Serial.print(myDHT11.HUMI_Buffer_Int);
    Serial.println("}]}]}");
    delay(1000); 
}

void SIM900A_SendMessage()
{
  mySerial.print("AT+CSCS=\"GSM\"\r\n");              //设置GSM字符集
  delay(1000);
  mySerial.print("AT+CMGF=1\r\n");                   //设置为文本模式
  delay(1000);      
  mySerial.print("AT+CMGS=\"18888888888\"\r\n");    //设置手机号
  delay(1000);
  mySerial.print("HUMI = ");
  mySerial.print(myDHT11.HUMI_Buffer_Int);
  mySerial.println(" %RH");
  mySerial.print("TMEP = ");
  mySerial.print(myDHT11.TEM_Buffer_Int);
  mySerial.println(" ℃");
  delay(1000);
  mySerial.write(0x1A);     //“CTRL+Z”的键值,即用于告诉SIM900A,要执行发送操作   (HEX)格式单独发送
  delay(1000);
}

库文件:DHT11.h

#ifndef __DHT11_H__
#define __DHT11_H__
#include <Arduino.h>
class DHT11
{
public:
	DHT11(int pin);
	void DHT11_Init();
	unsigned char DHT11_Read_Byte();
	void DHT11_Read();

	unsigned char HUMI_Buffer_Int;
	unsigned char TEM_Buffer_Int;
private:
	int DHT11_DQ;
};
#endif

库文件:DHT11.cpp

#include "DHT11.h"
//定义变量
unsigned char HUMI_Buffer_Int = 0;
unsigned char TEM_Buffer_Int = 0;

DHT11::DHT11(int pin)
{
	DHT11_DQ = pin;
}
//****************************************************
//初始化DHT11
//****************************************************

void DHT11::DHT11_Init()
{
	pinMode(DHT11_DQ,OUTPUT);
	digitalWrite(DHT11_DQ,LOW);  //拉低总线,发开始信号;
	delay(30);  //延时要大于 18ms,以便 DHT11 能检测到开始信号;
	digitalWrite(DHT11_DQ,HIGH);
	delayMicroseconds(40);  //等待 DHT11 响应;
	pinMode(DHT11_DQ,INPUT_PULLUP);
	while(digitalRead(DHT11_DQ) == HIGH);
	delayMicroseconds(80);   //DHT11 发出响应,拉低总线 80us;
	if(digitalRead(DHT11_DQ) == LOW);
	delayMicroseconds(80);   //DHT11 拉高总线 80us 后开始发送数据;
}

//****************************************************
//读一个字节DHT11数据
//****************************************************
unsigned char DHT11::DHT11_Read_Byte()
{
	unsigned char i,dat = 0;
	unsigned int j;

	pinMode(DHT11_DQ,INPUT_PULLUP);
        delayMicroseconds(2);
	for( i=0; i<8; i++)
	{
			while(digitalRead(DHT11_DQ) == LOW);   //等待 50us;
			delayMicroseconds(40);   //判断高电平的持续时间,以判定数据是‘0’还是‘1’;
			if(digitalRead(DHT11_DQ) == HIGH)
				dat |= (1<<(7-i));   //高位在前,低位在后;
			while(digitalRead(DHT11_DQ) == HIGH);   //数据‘1’,等待下一位的接收;

	}
	return dat;
}
//****************************************************
//读取温湿度值,存放在TEM_Buffer和HUMI_Buffer
//****************************************************
void DHT11::DHT11_Read()
{
	DHT11_Init();
	HUMI_Buffer_Int = DHT11_Read_Byte();   		//读取湿度的整数值
	DHT11_Read_Byte();							//读取湿度的小数值
	TEM_Buffer_Int = DHT11_Read_Byte();			//读取温度的整数值
	DHT11_Read_Byte();							//读取温度的小数值
	DHT11_Read_Byte();							//读取校验和
	delayMicroseconds(50);						//DHT11拉低总线50us
	pinMode(DHT11_DQ,OUTPUT);
	digitalWrite(DHT11_DQ,HIGH);				//释放总线	
}

源代码来自:基于Arduino的温湿度上传OneNET,同时SIM900A短信报警(2)(源码)

五、注意事项

 

©️2020 CSDN 皮肤主题: 游动-白 设计师:上身试试 返回首页