arduino学习系列——DHT11温湿度传感器的使用

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wgj99991111/article/details/53749144

一、器材
arduino UNO、面包板、DHT11温湿度传感器、连接线
这里说一下DHT11的基本情况:
(1)引脚说明:
1、VDD 供电 3.5V-5.5V DC
2、DATA 串行数据,单总线
3、GND 接地,电源负极。
(2)DHT11data数据格式:
一次传输40位数据=8bit湿度整数数据 + 8bit湿度小数数据 + 8bint温度整数数据 + 8bit温度小数数据 + 8bit校验位
3、时序图
这里写图片描述
二、连接图
这里写图片描述
如图所示,将DHT11的正极与5V电源接口相连,负极与GND相连,中间的数据接口与2号引脚相连。
三、代码

#include <dht11.h>
dht11 DHT11;
#define DHT11PIN 2
void setup(){
  Serial.begin(9600);
}

void loop(){
  Serial.println("/n");
  int chk = DHT11.read(DHT11PIN);
   Serial.print("Read sensor: ");
  switch (chk)
  {
    case DHTLIB_OK: 
                Serial.println("OK"); 
                break;
    case DHTLIB_ERROR_CHECKSUM: 
                Serial.println("Checksum error"); 
                break;
    case DHTLIB_ERROR_TIMEOUT: 
                Serial.println("Time out error"); 
                break;
    default: 
                Serial.println("Unknown error"); 
                break;
  }

  Serial.print("Humidity (%): ");
  Serial.println((float)DHT11.humidity, 2);

  Serial.print("Temperature (oC): ");
  Serial.println((float)DHT11.temperature, 2);
 delay(2000);
}

四、注意事项
1、代码中引用了#include <dht11.h>,这个是操作DHT11的库文件,有了它,就可以轻松操作我们这个温湿度传感器了。但是引用这个库文件的操作步骤是:
(1)在网上找到并下载该库文件,包括一个头文件和一个.cpp文件。
(2)在arduinoIDE中点击菜单:程序–导入库–add library,然后选择你存放库文件的那个文件夹。
(3)在代码中引用#include <dht11.h>,这样就可以使用了。
2、#define DHT11PIN 2,表示定义引脚2的名字为DHT11PIN ,注意这个定义语句后面没有分号。
五、原理分析
在硬件编程过程中,当你拿到一个器件,首先要了解他的引脚定义,这会告诉你这个东西应该怎么连接,在一个就是要看他的时序图,看了时序图你就知道主从设备之间进行数据采集过程中的代码应该怎么写,比如怎么启动,如何握手,怎么采集真正的数据等等。
在我们这个试验中,DHT11的时序图是这样的:
这里写图片描述
下面对照dht11.cpp源代码说说我们采集温湿度信息的原理(在代码中加了注释,说明相关内容。):

#include "dht11.h"


int dht11::read(int pin)
{
	// BUFFER TO RECEIVE
	uint8_t bits[5];//这里定义了5个八位的数组,也就是40位数据,用来存储数据采集的结果。
	uint8_t cnt = 7;//这个是用来给每一个数据的每一位输入值时计数用的。
	uint8_t idx = 0;//这个是给5个数组计数用的。

	// EMPTY BUFFER
	for (int i=0; i< 5; i++) bits[i] = 0;
	//首先在这里把这5个八位的数组全部填0,也就是初始值为0.
	// REQUEST SAMPLE
	pinMode(pin, OUTPUT);
	//将引脚定义为输出,也就是由arduino给DHT11写数据。从上面的时序图可以看出,要启动DHT11首先要给他发送18毫秒的低电平,再发送20~40微秒的高电平,DHT11只有看到了这样的信号,才会采集数据。
	digitalWrite(pin, LOW);
	delay(18);//这里就是发送18毫秒的低电平
	digitalWrite(pin, HIGH);
	delayMicroseconds(40);//这里就是发送40微秒的高电平
	pinMode(pin, INPUT);
	//发送完之后,这就等于把DHT11启动了,这时候我们就要从这个引脚上接受数据了,所以这时候要将这个引脚定义为输入引脚。
	// ACKNOWLEDGE or TIMEOUT
	unsigned int loopCnt = 10000;
	while(digitalRead(pin) == LOW)
		if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT;
	//从时序图中可以看出,接受数据一开始首先要读取80微秒的低电平,这里是一个等待,要把这80微秒等过去,但是有时候也有可能是传感器出现了故障,他一直发低电平,如果你持续等待不就相当于死机了,所以在这里要设置一个超时,也就是说要等待,但时间长了,就认为出问题了,返回一个异常信息。
	loopCnt = 10000;
	while(digitalRead(pin) == HIGH)
		if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT;
	//从时序图中可以看出,在80微秒的低电平之后是80微秒的高电平,这里仍然要等待,超时的原理与上面的低电平一样。
	// READ OUTPUT - 40 BITS => 5 BYTES or TIMEOUT
	//根据时序图,从下面开始就是40位的真正要读取的数据了,那么这里用了一个for循环来一位一位的读取这40bit的数据(注意是bite)。
	for (int i=0; i<40; i++)
	{
		//根据时序图,可以看出,对于每一个bite位数据,都是由一个低电平和一个高电平组成,区分这一位数据是1还是0取决于高电平的时常,如果高电平的时常为70微秒则表示1,如果高电平的时常为26~28微秒则表示0,因此读取每一位数据时,都是先等待把50微秒的低电平等过去,然后判断高电平的时常,根据这个时常来判断这bite的数据是1还是0.
		loopCnt = 10000;
		while(digitalRead(pin) == LOW)
			if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT;
		//这一句就是要把低电平等过去。
		unsigned long t = micros();
		//这里使用函数micros()获取了一个当前的时间,就是为了比较高电平的时常用的。
		loopCnt = 10000;
		while(digitalRead(pin) == HIGH)
			if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT;
		//这里就把高电平读出来了。
		if ((micros() - t) > 40) bits[idx] |= (1 << cnt);
		//然后再次使用micros()函数获取当前时间,减去读取高电平之前的时间点,也就是这个高电平的时常了,然后看这个时常是否大于40微秒,如果大于就认为是1,否则就认为这位是0.那么这里又是怎么运算的呢?分析下:bits[idx]表示一个8位的数组,假设他是0000 0000,运算符“|=”表示按位进行或运算,然后再把运算的结果赋给运算符左边的变量。而(1 << cnt)表示把数字1的二进制表示法向左移动cnt位,移动后的空位用0来填充。因此,对于一个八位的1可以表示为:0000 0001,刚才的初始化过程中我们知道cnt的值为7,所以,把这个0000 0001左移七位就变成了:1000 0000.然后将这个数与0000 0000进行|=运算,之后bits[idx]中的值就是1000 0000。可见这段代码实现的功能就是如果的到的这位数据是1,就将他存储到bits[idx]相应的位上去。
		//下面这段代码就是在循环的过程中修改cnt和idx的值,然后进行一位一位的读数而已。
		if (cnt == 0)   // next byte?
		//cnt为0表示一个8位的数组已经装满了,要换到下一个八位的数组上去,于是就把cnt复原为7,idx++让idx直到bits的下一个八位的数组上去。
		{
			cnt = 7;    // restart at MSB
			idx++;      // next byte!
		}
		else cnt--;
		//如果cnt不为0就表示这个八位的数据还没有读完,这时只需要让cnt-1,来填充下一位数据就可以了。
		//注意,在初始化的过程中我们把这40位的数据都初始化为0了,所以只有当有1出现时才需要进行改变。
	}

	// WRITE TO RIGHT VARS
        // as bits[1] and bits[3] are allways zero they are omitted in formulas.
        //从开始的时候的原理中我们知道这40位数据第1个8位是湿度的整数部分,第3个8位是温度的整数部分,下面这两句代码就是把数据分别放在这两个变量里了。
	humidity    = bits[0]; 
	temperature = bits[2]; 

	uint8_t sum = bits[0] + bits[2];  

	if (bits[4] != sum) return DHTLIB_ERROR_CHECKSUM;
	return DHTLIB_OK;
	//最后再用校验和验证一下数据是否正确。
}
//
// END OF FILE
//

六、运行结果
通电之后,在电脑上打开串口就可以看到采集到的温湿度信息。
这里写图片描述

猜你喜欢

转载自blog.csdn.net/wgj99991111/article/details/53749144