DHT11温湿度传感器初识

news2025/1/12 0:50:01

目录

一、产品概述

1、接线方式

2、特点

3、数据传送逻辑

二、发送时序检测模块是否存在

1、C51单片机(主机)时序分析

2、编写代码检测模块是否存在

3、读取DHT11数据的时序分析

三、温湿度通过串口传到PC显示

四、温湿度检测小系统——使数据显示在LCD1602液晶板上


一、产品概述

DHT11温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器,应用领域:暖通空调、汽车、消费品、气象站、温度调节器、除湿器、家电、医疗、自动控制等

1、接线方式

VCC:接供电的正极

GND:接地

DAT:接数据

2、特点

相对湿度和温度的测量

全部校准、数字输出

长期稳定性

超长的信号传输距离:20米

4引脚安装:可以买封装好的

完全互换:直接出结果,不用转化

3、数据传送逻辑

只有一根数据线DATA,上官一号发送序列指令给DHT11模块,模块一次完整的数据传输为40bit高位先出

40bit的数据格式

8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据+8bit校验合

二、发送时序检测模块是否存在

时序逻辑分析

对于主机来说:发送时序的开始在a点,结束在d点

1、C51单片机(主机)时序分析

a:dht=1;
b:dht=0;
b、c之间延时30ms;
c:dht=1;
开始读DHT模块有无信号,在40-100μs之间读,比如在60μs的时候读,如果在60μs的时候是低电平,说明模块存在

那怎么看模块是否有回应呢,请看上图中的de段,C51单片机发送完时序信号是处于高电平的状态,当DHT这边有信号过来时,会把信号从高电平状态拉到低电平状态,所以当de=0时,说明DHT模块有数据显示了

那对于单片机来说怎么获取到这个低电平状态呢,那就得去读取de段的数据了,读上面的引脚是否为低电平

从c点到e点共有两种情况:

第一种:cd之间的延时最短时间是20μs,de之间的延时时间是80μs,那么从c点到e点,所需要的延时时间就是20-100μs

第二种:cd之间的延时最长时间是40μs,de之间的延时时间是80μs,那么从c点到e点,所需要的延时时间就是40-120μs

综上述情况, 我们要读取它们重合的时间,才能把以上两点都包括在内,重合的时间是40-100μs

2、编写代码检测模块是否存在

#include "reg52.h"
#include "intrins.h"

sbit dht    = P3^3;
sbit ledOne = P3^7;

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 check_DHT(){

	//a:dht=1;
	dht = 1;
	//b:dht=0;
	dht = 0;
	//b、c之间延时30ms;
	Delay30ms();
	//c:dht=1;
	dht = 1;
	//开始读DHT模块有无信号,在40-100μs之间读,比如在60μs的时候读,如果在60μs的时候是低电平,说明模块存在
	Delay60us();
	if(dht == 0){
		ledOne = 0;     //亮灯,说明DHT模块存在
	}
}

void main()
{
	ledOne = 1;      //灭灯
	Delay1000ms();   //上电后稳定DHT11的供电
	Delay1000ms();
	check_DHT();     //看模块是否存在
	while(1);        //一直循环,不让main退出	
}

执行结果:

当单片机接温湿度传感器的时候,单片机的P3^7小灯就会亮,单片机不接温湿度传感器的时候,小灯就不亮

3、读取DHT11数据的时序分析

a:dht=1;
b:dht=0;
b、c之间延时30ms;
c:dht=1;

由于c点到d点之间有个20-40μs的延时时间,所以不太好找d点的位置,那么怎么找d点的位置呢

采用卡点的方法:

卡d点:while(dht);这时dht=1,当dht=1时,说明一直是高电平信号,当dht不等于1时,条件不满足时,说明信号从高电平下降到低电平了,也就是说找到d点了

卡e点:while(!dht); 这时dht=0,一直处于低电平状态,当dht不等于0时,条件不满足,说明信号从低电平上升到高电平了,也就是找到e点了

卡f点:while(dht);这时dht=1,当dht=1时,说明一直是高电平信号,当dht不等于1时,条件不满足时,说明信号从高电平下降到低电平了,也就是说找到f点了

卡g点:while(!dht); 这时dht=0,一直处于低电平状态,当dht不等于0时,条件不满足,说明信号从低电平上升到高电平了,也就是找到g点了

DHT11传输的有效数据都是高电平,只是持续的时间不一样

表示0时,高电平持续的时间是26-28μs

表示1时,高电平持续的时间是70μs

怎么读取DHT11传送的数据

从g点以后延时一段时间去读数据,比如延时50μs后,如果读到的信号是低电平,说明是数据是0,读到是信号是高电平,说明数据是1,然后读40bit,也是就是读40次,40次分5轮来读,每轮读8次(8bit=1个char)8次形成一个数据

数字0信号表示方法

 数字1信号表示方法

三、温湿度通过串口传到PC显示

1、环境准备:C51单片机连接DHT11温湿度传感器;VCC-5V、GND-GND、DAT-接/发数据引脚

2、编写代码

#include "reg52.h"
#include "intrins.h"

sbit dht    = P3^3;
sbit ledOne = P3^7;
sfr AUXR = 0x8E;
char datas[5];

void UartInit(void)		//9600bps@11.0592MHz
{
	AUXR = 0x01;   //降低时钟对外界的辐射
	SCON = 0x40;   //串行口寄存器工作模式选择方式1,RNE=0,为串行禁止接收状态
	
	TMOD &= 0x0F;  //定时器1工作方式位8位自动重装
	TMOD |= 0x20;
	
	TH1 = 0xFD; 
	TL1 = 0xFD;   //9600波特率的初值
	TR1 = 1;      //启动定时器
	
}

void sendByte(char data_msg){  //发送字节
	SBUF = data_msg;
	while(!TI);   //智能延时,靠硬件延时
	TI = 0;
}

void sendString(char* str){   //发送字符串

	while(*str != '\0'){
		sendByte(*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 DHT11_Start(){

	dht = 1;
	dht = 0;
	Delay30ms();
	dht = 1;
	while(dht);  //卡d点
	while(!dht); //卡e点
	while(dht);  //卡f点
	
}

void Delay40us()		//@11.0592MHz
{
	unsigned char i;
	_nop_();
	i = 15;
	while (--i);
}

void Read_Data_From_DHT(){

	int i;
	int j;
	char tmp;           //用来进行移位,用来获得最低位
	char flag;          //标志位
	DHT11_Start();
	for(i=0;i<5;i++){

		for(j=0;j<8;j++){
			while(!dht);  //卡g点
			Delay40us();  //延时40us
			if(dht == 1){
				flag = 1;
				while(dht);
			}else{    
				flag = 0;
			}
			tmp = tmp << 1;
			tmp |= flag;
		}
		datas[i] = tmp;
	}
}

void main()
{
	ledOne = 1;      //灭灯
	UartInit();      //初始化一个串口
	Delay1000ms();   //上电后稳定DHT11的供电
	Delay1000ms();
	
	while(1){
		Delay1000ms();
		Read_Data_From_DHT();          //获取DHT数据
		
		sendString("H:");              //发送字符串
		sendByte(datas[0]/10 + 0x30);  //发送第1个bit字节,获取湿度的整数位
		sendByte(datas[0]%10 + 0x30);
		sendByte('.');
		sendByte(datas[1]/10 + 0x30);  //发送第2个bit字节,获取湿度的小数位
		sendByte(datas[1]%10 + 0x30);
		sendString("\r\n");            //自动换行
		
		sendString("T:");
		sendByte(datas[2]/10 + 0x30);  //发送第3个bit字节,获取温度的整数位
		sendByte(datas[2]%10 + 0x30);
		sendByte('.');
		sendByte(datas[3]/10 + 0x30);  //发送第4个bit字节,获取温度的小数位
		sendByte(datas[3]%10 + 0x30);
		sendString("\r\n");            //自动换行
		
	}    	
}

3、执行结果:

四、温湿度检测小系统——使数据显示在LCD1602液晶板上

1、环境准备:C51单片机连接DHT11温湿度传感器和LCD1602液晶板

下面的链接里有C51单片机和LCD1602液晶板的连接方式

初识LCD1602及编程实现字符显示_Love小羽的博客-CSDN博客

2、编写代码

#include "reg52.h"
#include "intrins.h"
#define databuffer P0 //定义8位数据线,P0端口组

sbit dht    = P3^3;
sbit ledOne = P3^7;
sfr AUXR = 0x8E;
sbit RS = P1^0;
sbit RW = P1^1;
sbit EN = P1^4;
sbit fengshan = P1^6;  //继电器引脚

char datas[5];
char temp[8];   //定义一个温度类型
char huma[8];   //定义一个湿度类型


void check_busy(){
    
    char tmp = 0x80;
    databuffer = 0x80;
    
    while(tmp & 0x80){
        RS = 0;
        RW = 1;
        
        EN = 0;
        _nop_();
        EN = 1;
        _nop_();
        _nop_();
        tmp = databuffer;  //读取数据
        _nop_();
        EN = 0;
        _nop_();
    }
}

void Write_Cmd_Func(char cmd){
    
    check_busy();
    RS = 0;  //指令寄存器,接收地址
    RW = 0;
    EN = 0;
    _nop_();
    databuffer = cmd;   //发送指令
    _nop_();
    EN = 1;
    _nop_();
    _nop_();
    EN = 0;
    _nop_();
}

void Write_Data_Func(char dataShow){
    
    check_busy();
    RS = 1;  //数据寄存器,接收内容
    RW = 0;
    EN = 0;
    _nop_();
    databuffer = dataShow;   //发送数据
    _nop_();
    EN = 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 UartInit(void)		//9600bps@11.0592MHz
{
	AUXR = 0x01;   //降低时钟对外界的辐射
	SCON = 0x40;   //串行口寄存器工作模式选择方式1,RNE=0,为串行禁止接收状态
	
	TMOD &= 0x0F;  //定时器1工作方式位8位自动重装
	TMOD |= 0x20;
	
	TH1 = 0xFD; 
	TL1 = 0xFD;   //9600波特率的初值
	TR1 = 1;      //启动定时器
	
}

void sendByte(char data_msg){  //发送字节
	SBUF = data_msg;
	while(!TI);   //智能延时,靠硬件延时
	TI = 0;
}

void sendString(char* str){   //发送字符串

	while(*str != '\0'){
		sendByte(*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 DHT11_Start(){

	dht = 1;
	dht = 0;
	Delay30ms();
	dht = 1;
	while(dht);  //卡d点
	while(!dht); //卡e点
	while(dht);  //卡f点
	
}

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

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

void Read_Data_From_DHT(){

	int i;
	int j;
	char tmp;           //用来进行移位,用来获得最低位
	char flag;          //标志位
	DHT11_Start();
	for(i=0;i<5;i++){

		for(j=0;j<8;j++){
			while(!dht);  //卡g点
			Delay40us();  //延时40us
			if(dht == 1){
				flag = 1;
				while(dht);
			}else{    
				flag = 0;
			}
			tmp = tmp << 1;
			tmp |= flag;
		}
		datas[i] = tmp;
	}
}

void LCD1602_INIT(){

//(1)延时 15ms 
    Delay15ms();
//(2)写指令 38H(不检测忙信号) 
    Write_Cmd_Func(0x38);
//(3)延时 5ms 
    Delay5ms();
//(4)以后每次写指令,读/写数据操作均需要检测忙信号 
    check_busy();
//(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;
	}
}

void Build_Datas(){

	huma[0] = 'H';                 //温度
	huma[1] = datas[0]/10 + 0x30;
	huma[2] = datas[0]%10 + 0x30;
	huma[3] = '.';
	huma[4] = datas[1]/10 + 0x30;
	huma[5] = datas[1]%10 + 0x30;
	huma[6] = '%';
	huma[7] = '\0';
	
	temp[0] = 'T';                  //湿度
	temp[1] = datas[2]/10 + 0x30;
	temp[2] = datas[2]%10 + 0x30;
	temp[3] = '.';
	temp[4] = datas[3]/10 + 0x30;
	temp[5] = datas[3]%10 + 0x30;
	temp[6] = 'C';
	temp[7] = '\0';
	

}


void main()
{
	
	Delay1000ms();
	UartInit();      //初始化一个串口
	LCD1602_INIT();  //初始化LCD1602液晶显示
	Delay1000ms();   //上电后稳定DHT11的供电
	Delay1000ms();
	ledOne = 0;      
	
	while(1){
		Delay1000ms();
		Read_Data_From_DHT();           //获取DHT数据
		if(datas[2] > 29 ){
			fengshan = 0;
		}
		Build_Datas();
		sendString(huma);               //发送湿度字符串
		sendString("\r\n");
		sendString(temp);               //发送温度字符串
		sendString("\r\n");
		LCD1602_showLine(1,3,temp);		  //第一行显示湿度
		LCD1602_showLine(2,3,huma);		  //第二行显示温度
	}    
}

执行结果:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/153931.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Discrete Opinion Tree Induction for Aspect-based Sentiment Analysis 论文阅读笔记

一、作者 Chenhua Chen、Zhiyang Teng、Zhongqing Wang、Yue Zhang School of Engineering, Westlake University, China Institute of Advanced Technology, Westlake Institute for Advanced Study Soochow University 二、背景 如何为每一个方面词定位相应的意见上下文…

反补码运算之 “1 - 1 = - 1 ” ?

我们在研究数据的二进制表示时遇到这样一个问题&#xff1a; 由于计算中的CPU只有加法器&#xff0c;没有减法器&#xff0c;所以在计算机采用原码做减法时对于&#xff1a;1 - 1 0 相当于1 &#xff08;-1&#xff09;&#xff0c;用二进制表示为&#xff1a;000110011001。…

儿童感染新冠病毒后发高烧如何应对?专家来支招

儿童感染新冠病毒后发热较多&#xff0c;但肺炎发展较少儿童感染新冠病毒后发高烧&#xff0c;是重症吗&#xff1f;徐红梅&#xff1a;从目前的接待情况来看&#xff0c;儿童感染新冠病毒后比成人发烧。超过一半的儿童在感染后有发烧症状&#xff0c;伴有咳嗽、鼻塞、流鼻涕、…

JavaWeb的一些学习总结

Web系统就是&#xff1a;前端负责貌美如花&#xff0c;后端负责坚如磐石 企业在做Web系统时&#xff0c;成本与收益的对比是不可忽视的&#xff0c;企业做项目一定是要盈利的&#xff01; 企业做项目最求的不是技术的新和潮&#xff0c;追求的是低成本和稳还有好用度&#xff…

函数的设计

一、默认参数 C允许在函数定义或声明时&#xff0c;为形参指定默认值&#xff0c;即默认参数&#xff08;default argument&#xff09;。 &#xff08;1&#xff09;函数定义与函数声明只能设置一次默认参数。 &#xff08;2&#xff09;可以设置多个默认参数&#xff0c;设…

【精华】搞定JVM调优学习

JVM 介绍 1. 什么是 JVM JVM 是 Java Virtual Machine&#xff08;Java 虚拟机&#xff09;的缩写。一台执行 Java 程序的机器。 2 .JAVA 语言的执行原理 计算机语言&#xff1a; 计算机能够直接执行的指令。这种指令和系统及硬件有关。 计算机高级语言&#xff1a; 在遵循…

「数据」驱动行业拐点,毫末智行冲刺自动驾驶3.0时代

“毫末预计&#xff0c;到2025年中国高阶辅助驾驶搭载率将达到70%。而在汽车新消费领域&#xff0c;中国汽车市场增换购消费比例将达到60%&#xff0c;智能驾驶功能成为必选因素&#xff0c;并迎来商业化的加速发展。”1月5日&#xff0c;第七届HAOMO AI DAY上&#xff0c;毫末…

黑马学ElasticSearch(五)

目录&#xff1a; &#xff08;1&#xff09;DSL查询语法-DSL查询分类和基本语法 &#xff08;2&#xff09;DSL查询语法-全文检索查询 &#xff08;3&#xff09;DSL查询语法-精确查询 &#xff08;4&#xff09;DSL查询语法-地理查询 &#xff08;5&#xff09;DSL查询语…

计算机网络(一)

计算机网络1 概述1.1 计算机网络的作用1.2 因特网概述1.2.1 网络的网络1.2.2 Internet和internet的区别1.2.3 因特网发展的三个阶段1.2.4 ISP介绍1.2.5 ISP分类1.2.5.1 主干ISP1.2.5.2 地区ISP1.2.5.3 本地ISP1.2.6 因特网交换点 IXP1.3 因特网的组成1.3.1 因特网的边缘部分1.3…

资产管理4大难点,如何破解?

随着企业业务扩大、人员增多&#xff0c;固定资产的数量和种类也会随着增加。此时&#xff0c;如何高效管理企业资产就成为很多企业亟待解决的一大难题。 传统资产管理4大难点 01.资产管理部门需要联系采购部门、使用部门、财务部门等收集数据&#xff0c;汇总难且工作量大&…

vacuum移除不必要的CLOG文件

迫切模式弥补了惰性模式的缺陷。它会扫描所有页面&#xff0c;检查表中的所有元组&#xff0c;更新相关的系统视图&#xff0c;并在可能时删除不必要的CLOG文件与页面。当满足以下条件时&#xff0c;会执行迫切模式。pg_database.datfrozenxid<(OldestXmin-vacuum_freeze_ta…

【多线程】【C++ 知识点】pthread_join学习

目录pthread_join进程id和线程idpthread_join pthread_join() 主线程会进入阻塞装题&#xff0c;pthread_join()之后的代码&#xff0c;只有等待子进程退出之后才能执行。 代码块A pthread_create(&id, NULL, Fn, NULL);pthread_create(&id_1, NULL, Fn, NULL);pthre…

jdk1.8 更替为 oepnJdk8遇到的坑

背景&#xff1a;客户服务器因为说jdk要收费&#xff0c;所以要求将jdk1.8替换为openJdk&#xff0c;本地测试ok&#xff0c;则将服务器的jdk替换为openJdk8&#xff0c;出现一个登录异常&#xff0c;调查发现是一个sso登录的问题&#xff08;单点登录&#xff09;&#xff0c;…

Rhce第一次作业

chrony服务部署&#xff1a;两台机器a: 第一台机器从阿里云同步时间&#xff0c;第二台机器从第一台机器同步时间1.查看防火墙是否关闭&#xff0c;若未关闭&#xff0c;关闭防火墙2.打开chrony配置文件3.向配置文件中写入阿里云时间服务器&#xff0c;并允许两台机器所在的网段…

从0到1完成一个Vue后台管理项目(十八、基础地图绘制)

往期 从0到1完成一个Vue后台管理项目&#xff08;一、创建项目&#xff09; 从0到1完成一个Vue后台管理项目&#xff08;二、使用element-ui&#xff09; 从0到1完成一个Vue后台管理项目&#xff08;三、使用SCSS/LESS&#xff0c;安装图标库&#xff09; 从0到1完成一个Vu…

spring restTemplate的坑----会对String类型的url中的特殊字符进行转义

&#x1f4e2; &#x1f4e2; &#x1f4e2; &#x1f4e3; &#x1f4e3; &#x1f4e3;哈喽&#xff01;大家好&#xff0c;我是「奇点」&#xff0c;江湖人称 singularity。刚工作几年&#xff0c;想和大家一同进步 &#x1f91d; &#x1f91d;一位上进心十足的【Java ToB端…

基于OpenCV实现两种方法测量圆弧长度(步骤 + 源码)

导 读 本文主要介绍基于OpenCV实现两种方法测量圆弧长度(步骤 + 源码)。 背景介绍 要求:如上所示,分别用OpenCV计算出图1和图2中圆弧的长度。因为OpenCV中没有提供现成计算圆弧的方法,所以需要自己编写,本文将提供2种不同的方法来实现,仅供参考。 实现步骤 首…

mmsegmentation 训练Binary segmentation

1.一天最无聊的事从搭环境开始 1.conda create -n swin python3.7 2.conda activate swin 3.conda install pytorch1.7.0 torchvision0.8.0 torchaudio0.7.0 cudatoolkit11.0 4.pip install mmcv-full -f https://download.openmmlab.com/mmcv/dist/cu110/torch1.7.0/index.h…

Keil + STM32学习嵌入式数据结构-01

视频链接 初识数据结构&#xff0c;十天搞定嵌入式数据结构_哔哩哔哩_bilibili 课程目的 学会嵌入式经常使用的数据结构 具备基础知识 具有C语言基础&#xff08;结构体、指针、内存&#xff08;malloc)&#xff09; 具有数据结构的基础知识&#xff0c;因此提及到的基础…

Android 深入系统完全讲解(8)

2 Smali 调试 Smali 是安卓 Apk 反编译出来的格式&#xff0c;类似于我们 PC 上面的汇编语言。语法可以参考这个文 章&#xff1a;https://blog.csdn.net/yuanguozhengjust/article/details/80493963 PC 上的反编译调试工具用 OD 和 IDA&#xff08;这个也可以调试 Android &…