温湿度传感器 DHT11

DHT11简介

特点:相对温湿度测量;全校准;数字输出;长期稳定;20米超长信号传输距离;超低能耗;完全互换直接出结果(比如超声波测距模块就需要代码转化一下结果,这个就不用)

接口:VCC,GND和DATA。

DATA 用于微处理器与 DHT11之间的通讯和同步,采用单总线数据格式,一次
通讯时间4ms左右,数据分小数部分和整数部分,具体格式在下面说明,当前小数
部分用于以后扩展,现读出为零.操作流程如下:
一次完整的数据传输为40bit,高位先出。
数据格式8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据+8bit校验和
数据传送正确时校验和数据等于“ 8bit湿度整数数据+8bit湿度小数数据
+8bi温度整数数据+8bit温度小数数据” 所得结果的末8位。

 DHT11的通讯过程时序

总体过程:

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

激活过程:(使得DHT11由低功耗转到高速模式并开始测量)

  • 总线空闲状态为高电平,主机把总线拉低等待DHT11响应,主机把总线拉低必须大于18毫秒,保证DHT11能检测到起始信号。
  • DHT11接收到主机的开始信号后, 等待主机开始信号结束,然后发送80us低电平响应信号.
  • 主机发送开始信号结束后,延时等待20-40us后, 读取DHT11的响应信号,
  • 主机发送开始信号后,可以切换到输入模式,或者输出高电平均可, 总线由上拉电阻拉高。
void Start_DHT()
{

	dht = 1;
	dht = 0;
	
	Delay30ms();
	
	dht =  1;
	while(dht == 1);//不断读取直到DHT再次变低,跳出循环,说明模块响应
	while(dht == 0);//不断读取直到DHT再次拉高,80us之后,再经过50us后DHT变成低电平,就代表要开始变高并开始传输数据了
	while(dht == 1);//等待数据传输,不断读取直到DHT再次变低,如退出循环说明数据传输前的50us低电平开始了
    
	
}
总线为低电平,说明DHT11发送响应信号,DHT11发送响应信号后,再把总线拉高80us,准备发送数据,每一bit数据都以50us低电平时隙开始,高电平的长短定了数据位是0还是1.格式见下面图示.如果读取响应信号为高电平,则DHT11没有响应,请检查线路是否连接正常.当最后一bit数据传送完毕后,DHT11拉低总线50us,随后总线由上拉电阻拉高进入空闲状态。

数字‘0’信号表示:

数字 ‘1’信号表示:

数字1/0的区别就是高电平的时间不同,所以设一个延时40us,如果还是高电平就是‘1’,低电平就是‘0’:

数字01检测实现:

void check_01()
{
	
	while(dht == 0); //不断读取上拉的一瞬间,也可以写成while(!dht);
 
	Delay40us();//高电平持续26-28us是‘0’,高电平持续70us是'1',所以delay40us之后观察还是否是高电平
 
	if(dht == 1){//'1'
	    //
		
		while(dht == 1); // 不断读取下拉的一瞬间,因为在开始传输数据之前要延迟80us,如果提前结束,下一次开始传输数据就会出错,因为“开始传输数据”是从判断上拉开始的
		
	}else(dht == 0){ //'0'
		//
		
	}
	
}

完整的代码实现

实验一:读取温湿度数据

#include "reg52.h"
#include <intrins.h>

sbit led1 = P3^7;//根据原理图(电路图),设备变量led1指向P3组IO口的第7口
sbit dht = P3^3;

char datas[];

void Delay1000ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	_nop_();
	i = 8;
	j = 1;
	k = 243;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}


void Delay30ms()		//@11.0592MHz
{
	unsigned char i, j;

	i = 54;
	j = 199;
	do
	{
		while (--j);
	} while (--i);
}

void Delay60us()		//@11.0592MHz
{
	unsigned char i;

	i = 25;
	while (--i);
}

void Delay40us()		//@11.0592MHz
{
	unsigned char i;

	_nop_();
	i = 15;
	while (--i);
}


void Start_DHT()
{

	dht = 1;
	dht = 0;
	
	Delay30ms();
	
	dht =  1;
	while(dht == 1);//不断读取直到DHT再次变低,跳出循环,说明模块响应
	while(dht == 0);//不断读取直到DHT再次拉高,80us之后,再经过50us后DHT变成低电平,就代表要开始变高并开始传输数据了
	while(dht == 1);//等待数据传输,不断读取直到DHT再次变低,如退出循环说明数据传输前的50us低电平开始了
    
	
}

void Read_data_From_DHT()
{
	int i;//轮
	int j;//每一轮读多少次
	char temp;
	char flag;
	Start_DHT();
	
	for(i = 0;i < 5;  i++)
	{//5组数据
		for(j =0;j<8;j++)
		{//每组数据8位
			while(!dht);//等待上拉  dht = 1 退出循环
			Delay40us();//高电平持续26-28us是‘0’,高电平持续70us是'1',所以delay40us之后观察还是否是高电平
			if(dht == 1)
			{
				flag = 1;
				while(dht);//不断读取下拉的一瞬间,因为在开始传输数据之前要延迟80us,如果提前结束,下一次开始传输数据就会出错,因为“开始传输数据”是从判断上拉开始的

			}
			else
			{
				flag = 0;
			}
			temp =  temp << 1;//temp左移一位,例如temp= 10101011  左移之后变成-》01010110(第一个数移出去,最后一位补零)
			temp |= flag;//假如flag=1,temp=01010111
		}
		datas[i] = temp;
	}
	
}



void main()
{
	Delay1000ms();//传感器上电后,要等待 1s 以越过不稳定状态在此期间无需发送任何指令
	
	led1 = 1;
	Start_DHT(); 
	while(1)
	{
		Delay1000ms();
		Read_data_From_DHT();
	}
	
}

 实现二:将温度和湿度的数据在串口助手中显示

#include "reg52.h"
#include <intrins.h> 
#include <string.h>

sbit led1 = P3^7;//根据原理图(电路图),设备变量led1指向P3组IO口的第7口
sbit dht = P3^3;
char datas[5];

sfr AUXR = 0x8E;

void UartInit()		//9600bps@11.0592MHz
{
	AUXR = 0x01;
	SCON = 0x40;  //配置串口工作方式1,REN不使能接收
	
	//配置定时器1,工作方式为8位自动重载
	TMOD &= 0x0f;//
	TMOD |= 0x20;
	
	TH1 = 0xFD; 
	TL1 = 0xFD; //9600波特率的初值
	
	TR1 = 1;//启动定时器
	
	
}

void Send_byte(char data_msg)
{
	SBUF = data_msg;
	while(!TI);//在请求中断时,TI= 1,既!TI=0,等待数据的发送完成;响应中断结束后TI = 0,既!TI = 1,将TI清零
	TI = 0;

}

void Send_string(char* str)
{
	while(*str != '\0')
	{
		Send_byte(*str);
		str++;
	}
}

void Delay1000ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	_nop_();
	i = 8;
	j = 1;
	k = 243;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}


void Delay30ms()		//@11.0592MHz
{
	unsigned char i, j;

	i = 54;
	j = 199;
	do
	{
		while (--j);
	} while (--i);
}



void Delay40us()		//@11.0592MHz
{
	unsigned char i;

	_nop_();
	i = 15;
	while (--i);
}


void Start_DHT()
{

	dht = 1;
	dht = 0;
	
	Delay30ms();
	
	dht =  1;
	while(dht == 1);//不断读取直到DHT再次变低,跳出循环,说明模块响应
	while(dht == 0);//不断读取直到DHT再次拉高,80us之后,再经过50us后DHT变成低电平,就代表要开始变高并开始传输数据了
	while(dht == 1);//等待数据传输,不断读取直到DHT再次变低,如退出循环说明数据传输前的50us低电平开始了
    
	
}

void Read_data_From_DHT()
{
	int i;//轮
	int j;//每一轮读多少次
	char temp;
	char flag;
	Start_DHT();
	
	for(i = 0;i < 5;  i++)
	{//5组数据
		for(j =0;j<8;j++)
		{//每组数据8位
			while(!dht);//等待上拉  dht = 1 退出循环
			Delay40us();//高电平持续26-28us是‘0’,高电平持续70us是'1',所以delay40us之后观察还是否是高电平
			if(dht == 1)
			{
				flag = 1;
				while(dht);//不断读取下拉的一瞬间,因为在开始传输数据之前要延迟80us,如果提前结束,下一次开始传输数据就会出错,因为“开始传输数据”是从判断上拉开始的

			}
			else
			{
				flag = 0;
			}
			temp =  temp << 1;//temp左移一位,例如temp= 10101011  左移之后变成-》01010110(第一个数移出去,最后一位补零)
			temp |= flag;//假如flag=1,temp=01010111
		}
		datas[i] = temp;
	}
	
}



void main()
{
	Delay1000ms();//传感器上电后,要等待 1s 以越过不稳定状态在此期间无需发送任何指令
	
	led1 = 1;
	UartInit();
	Start_DHT(); 
	while(1)
	{
		Delay1000ms();
		Read_data_From_DHT();
		Send_string("H;");
		Send_byte(datas[0]/10 + 0x30);
		Send_byte(datas[0]%10 + 0x30);
		
		Send_string(".");
		Send_byte(datas[1]/10 + 0x30);
		Send_byte(datas[1]%10 + 0x30);
		Send_string("\r\n");
		Send_string("T;");
		Send_byte(datas[2]/10 + 0x30);
		Send_byte(datas[2]%10 + 0x30);
		Send_string(".");
		Send_byte(datas[3]/10 + 0x30);
		Send_byte(datas[3]%10 + 0x30);
		Send_string("\r\n");
	}
	
}

其中温度和湿度进行数据的转化变成更易读的方式

void Build_datas()
{
	humidity[0] = 'H';
	humidity[1] = datas[0]/10 + 0x30;
	humidity[2] = datas[0]%10 + 0x30;
	humidity[3] = '.';
	humidity[4] = datas[1]/10 + 0x30;
	humidity[5] = datas[1]%10 + 0x30;
	humidity[6] = '%';
	humidity[7] = '\0';
	
	temperature[0] = 'T';
	temperature[1] = datas[2]/10 + 0x30;
	temperature[2] = datas[2]%10 + 0x30;
	temperature[3] = '.';
	temperature[4] = datas[3]/10 + 0x30;
	temperature[5] = datas[3]%10 + 0x30;
	temperature[6] = 'C';
	temperature[7] = '\0';

}

实验结果:

实验三:LCD显示温湿度的同时,通过usb串口接收温湿度信息 

#include "reg52.h"
#include <intrins.h> 
#include <string.h>

#define databuffer P0 //定义8位数据线,Po端口组

sbit led1 = P3^7;//根据原理图(电路图),设备变量led1指向P3组IO口的第7口
sbit dht  = P3^3;
sbit RS   = P1^0;
sbit RW   = P1^1;
sbit EN   = P1^4;
sfr AUXR = 0x8E;

char datas[5];
char temperature[8];
char humidity[8];

 
void Check_Busy()//(4)以后每次写指令,读/写数据操作均需要检测忙信号
{
	char temp = 0x80;
	databuffer = 0x80;//先将databuffer置为忙
	while(temp &= 0x80 ){//1000 0000//BF(D7)位为高电平,代表忙
	//然后如果temp不变化的话,就一直检查是否busy
	RS = 0;
	RW = 1;
	EN = 0;
	
	_nop_();
	
	EN = 1;
	temp = databuffer;//根据时序图,E为1时开始读
	_nop_();
	_nop_();
	EN = 0;
	_nop_();
	}
}
 
 
 
void Delay15ms()		//@11.0592MHz
{
	unsigned char i, j;
 
	i = 27;
	j = 226;
	do
	{
		while (--j);
	} while (--i);
}
 
void Delay5ms()		//@11.0592MHz
{
	unsigned char i, j;
 
	i = 9;
	j = 244;
	do
	{
		while (--j);
	} while (--i);
}
 
 
 
 
 
void Write_cmd_Func(char cmd)//写入指令的函数
{
	Check_Busy();//(4)以后每次写指令,读/写数据操作均需要检测忙信号
	RS = 0;//写指令
	RW = 0;
	
	EN = 0;
	_nop_();
	databuffer = cmd;
	EN = 1;
	_nop_();
	_nop_();
	EN = 0;
}
 
void Write_data_Func(char dataShow)//写入数据的函数
{
	Check_Busy();//(4)以后每次写指令,读/写数据操作均需要检测忙信号
	RS = 1;//写内容
	RW = 0;
	
	EN = 0;
	_nop_();
	databuffer = dataShow;
	_nop_();
	EN = 1;
	_nop_();
	_nop_();
	EN = 0;
}


void UartInit()		//9600bps@11.0592MHz
{
	AUXR = 0x01;
	SCON = 0x40;  //配置串口工作方式1,REN不使能接收
	
	//配置定时器1,工作方式为8位自动重载
	TMOD &= 0x0f;//
	TMOD |= 0x20;
	
	TH1 = 0xFD; 
	TL1 = 0xFD; //9600波特率的初值
	
	TR1 = 1;//启动定时器
	
	
}

void Send_byte(char data_msg)
{
	SBUF = data_msg;
	while(!TI);//在请求中断时,TI= 1,既!TI=0,等待数据的发送完成;响应中断结束后TI = 0,既!TI = 1,将TI清零
	TI = 0;

}

void Send_string(char* str)
{
	while(*str != '\0')
	{
		Send_byte(*str);
		str++;
	}
}

void Delay1000ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	_nop_();
	i = 8;
	j = 1;
	k = 243;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}


void Delay30ms()		//@11.0592MHz
{
	unsigned char i, j;

	i = 54;
	j = 199;
	do
	{
		while (--j);
	} while (--i);
}



void Delay40us()		//@11.0592MHz
{
	unsigned char i;

	_nop_();
	i = 15;
	while (--i);
}


void Start_DHT()
{

	dht = 1;
	dht = 0;
	
	Delay30ms();
	
	dht =  1;
	while(dht == 1);//不断读取直到DHT再次变低,跳出循环,说明模块响应
	while(dht == 0);//不断读取直到DHT再次拉高,80us之后,再经过50us后DHT变成低电平,就代表要开始变高并开始传输数据了
	while(dht == 1);//等待数据传输,不断读取直到DHT再次变低,如退出循环说明数据传输前的50us低电平开始了
    
	
}

void Read_data_From_DHT()
{
	int i;//轮
	int j;//每一轮读多少次
	char temp;
	char flag;
	Start_DHT();
	
	for(i = 0;i < 5;  i++)
	{//5组数据
		for(j =0;j<8;j++)
		{//每组数据8位
			while(!dht);//等待上拉  dht = 1 退出循环
			Delay40us();//高电平持续26-28us是‘0’,高电平持续70us是'1',所以delay40us之后观察还是否是高电平
			if(dht == 1)
			{
				flag = 1;
				while(dht);//不断读取下拉的一瞬间,因为在开始传输数据之前要延迟80us,如果提前结束,下一次开始传输数据就会出错,因为“开始传输数据”是从判断上拉开始的

			}
			else
			{
				flag = 0;
			}
			temp =  temp << 1;//temp左移一位,例如temp= 10101011  左移之后变成-》01010110(第一个数移出去,最后一位补零)
			temp |= flag;//假如flag=1,temp=01010111
		}
		datas[i] = temp;
	}
	
}


void LCD1602_Init()
{
	//(1)延时 15ms
	Delay15ms();
	//(2)写指令 38H(不检测忙信号)
	Write_cmd_Func(0x38);
	//(3)延时 5ms
	Delay5ms();
	//(4)以后每次写指令,读/写数据操作均需要检测忙信号
	
	//(5)写指令 38H:显示模式设置
	Write_cmd_Func(0x38);
	//(6)写指令 08H:显示关闭
	Write_cmd_Func(0x08);
	//(7)写指令 01H:显示清屏
	Write_cmd_Func(0x01);
	//(8)写指令 06H:显示光标移动设置
	Write_cmd_Func(0x06);
	//(9)写指令 0CH:显示开及光标设置
	Write_cmd_Func(0x0C);
	
}


void LCD1602_ShowLine(char row,char col,char *string)
{
	switch(row){
		case 1:
			Write_cmd_Func(0x80+col);//只要定下开始的位置,之后光标会自行移动
			while(*string){
				Write_data_Func(*string);
				string++;
			}
			break;
		
		
		case 2:
			Write_cmd_Func(0x80+0x40+col);//只要定下开始的位置,之后光标会自行移动
			while(*string){
				Write_data_Func(*string);
				string++;
			}
			break;	
		}
	/*
		char pos;
	
	if(hang == 0){//如果第一行
			pos = 0x80 + 0x00 + lie; 
		}else if(hang == 1){//如果第二行
			pos = 0x80 + 0x40 + lie;
		}
		Check_Busy();
		Write_data_Func(*string);
	
	while(*string != '\0'){
		Check_Busy();
		Write_data_Func(*string);
		string++;
	}
		*/
}

void Build_datas()
{
	humidity[0] = 'H';
	humidity[1] = datas[0]/10 + 0x30;
	humidity[2] = datas[0]%10 + 0x30;
	humidity[3] = '.';
	humidity[4] = datas[1]/10 + 0x30;
	humidity[5] = datas[1]%10 + 0x30;
	humidity[6] = '%';
	humidity[7] = '\0';
	
	temperature[0] = 'T';
	temperature[1] = datas[2]/10 + 0x30;
	temperature[2] = datas[2]%10 + 0x30;
	temperature[3] = '.';
	temperature[4] = datas[3]/10 + 0x30;
	temperature[5] = datas[3]%10 + 0x30;
	temperature[6] = 'C';
	temperature[7] = '\0';

}

void main()
{
	Delay1000ms();//传感器上电后,要等待 1s 以越过不稳定状态在此期间无需发送任何指令
	
	UartInit();
	LCD1602_Init();
	Start_DHT(); 
	
	led1 = 1;
	while(1)
	{
		Delay1000ms();
		Read_data_From_DHT();
	
		Build_datas();
		
		Send_string(humidity);
		Send_string("\r\n");
		Send_string(temperature);
		Send_string("\r\n");
		LCD1602_ShowLine(1,2,humidity);
		LCD1602_ShowLine(2,2,temperature);
	}
	
}

实验结果:

以上就完成了DHT11的基本功能,又结合了 LCD1602和串口。所以代码显得比较冗长。

  • 16
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值