DTH11温湿度传感器
DHT11 是一款温湿度复合传感器,常用于单片机系统中进行环境温湿度的测量。以下是对 DHT11 温湿度传感器的详细讲解:
一、传感器概述
DHT11 数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器。它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有极高的可靠性与卓越的长期稳定性。传感器包括一个电容式感湿元件和一个 NTC 测温元件,并与一个高性能 8 位单片机相连接。
二、主要特点
- 体积小、功耗低:适合集成到各种小型电子设备中。
- 数字信号输出:无需复杂的模拟信号处理,直接输出数字信号,方便与单片机进行通信。
- 响应速度快:能够快速准确地测量环境温湿度变化。
- 精度较高:温度测量范围为 0℃ - 50℃,精度为 ±2℃;湿度测量范围为 20% - 90% RH,精度为 ±5% RH。
三、工作原理
- 传感器通过单片机的一个 I/O 口进行通信。单片机向 DHT11 发送启动信号后,DHT11 开始采集温湿度数据。
- 采集完成后,DHT11 将温湿度数据转换为数字信号,并通过数据线逐位发送给单片机。
- 单片机接收到数据后,进行校验和处理,以确保数据的准确性。
四、通信协议
- 单片机与 DHT11 之间采用单总线数据格式进行通信。通信过程包括初始化、发送启动信号、接收数据等步骤。
- 初始化时,单片机将数据线拉低一段时间,然后释放数据线,等待 DHT11 的响应。
- 发送启动信号时,单片机将数据线拉低至少 18ms,然后释放数据线,等待 DHT11 的响应。
- DHT11 接收到启动信号后,会发送一个 80μs 的低电平响应信号,接着发送 80μs 的高电平响应信号,表示准备好发送数据。
- DHT11 发送的数据包括 40 位,分别为 8 位湿度整数数据、8 位湿度小数数据、8 位温度整数数据、8 位温度小数数据和 8 位校验和。数据以低位在前的方式逐位发送。
- 单片机接收到数据后,进行校验和计算。如果校验和正确,则表示数据接收成功;否则,需要重新进行数据采集。
五、使用方法
- 硬件连接:将 DHT11 的 VCC 引脚连接到单片机的电源引脚,GND 引脚连接到地,DATA 引脚连接到单片机的一个 I/O 口。
- 软件编程:在单片机程序中,需要实现 DHT11 的初始化、启动信号发送、数据接收和校验等功能。可以使用定时器或延时函数来满足通信协议的时序要求。
操作时序:
复位信号和响应信号:
被调函数(DTH11):
#include "reg52.h"
#include "delay.h"sbit dht = P3^6; // 定义连接 DHT11 传感器的引脚,这里连接到 P3.6
char datas[5]; // 用于存储从 DHT11 读取的数据/*
DHT11 的时序逻辑分析:
a : dht = 1 设置引脚为高电平。
b £ºdht = 0 将引脚拉低。
ÑÓʱ30ms 延时 30 毫秒。
c£º dht = 1 将引脚拉高。
在 60us 后读 d 点,如果 d 点是低电平(被模块拉低),说明模块存在。
*/void DH11_Star() {dht = 1; // 设置引脚为高电平dht = 0; // 将引脚拉低Delay30ms(); // 延时 30 毫秒,发送启动信号给 DHT11dht = 1; // 将引脚拉高// 卡 d 点:等待 DHT11 拉低引脚作为响应开始信号while (dht);// 卡 e 点:等待 DHT11 释放引脚(变为高电平),表示准备发送数据while (!dht);// 卡 f 点:等待 DHT11 再次拉高引脚,确认准备发送数据while (dht);
}void Read_Data() {int i; // 用于循环计数,表示读取的数据组数(这里共 5 组数据)int j; // 用于循环计数,表示每组数据中的每一位char temp; // 临时变量,用于存储每一位数据在移位过程中的值char flag; // 标志位,用于表示读取到的数据位是 1 还是 0DH11_Star(); // 调用启动 DHT11 的函数for (i = 0; i < 5; i++) {// 卡 g 点:等待 DHT11 将引脚拉低,表示开始发送一组数据while (!dht);// 有效数据都是高电平,持续时间不一样,延时 50us 后根据引脚电平判断数据是 0 还是 1for (j = 0; j < 8; j++) {while (!dht); // 等待引脚拉低,表示开始读取一位数据Delay40us(); // 延时 40 微秒,根据引脚在这个时间后的电平判断数据位if (dht == 1) {flag = 1; // 如果引脚为高电平,标志位设为 1,表示读取到的数据位是 1while (dht); // 等待引脚再次拉低,准备读取下一位数据} else {flag = 0; // 如果引脚为低电平,标志位设为 0,表示读取到的数据位是 0}temp = temp << 1; // 将 temp 左移一位,为存储下一位数据做准备temp |= flag; // 将标志位的值存入 temp,完成一位数据的读取}datas[i] = temp; // 将读取到的一组数据存储到 datas 数组中}
}
delay函数:
#include <intrins.h>
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 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 Delay1000ms() //@11.0592MHz
{unsigned char i, j, k;_nop_();i = 8;j = 1;k = 243;do{do{while (--k);} while (--j);} while (--i);
}
LCD1602:
#include "reg52.h"
#include <intrins.h>
#include "delay.h"#define databuffer P0 // 定义 8 位数据总线,连接到 P0 端口sbit RS = P1^0; // 寄存器选择引脚,连接到 P1.0
sbit RW = P1^1; // 读写选择引脚,连接到 P1.1
sbit EN = P1^4; // 使能引脚,连接到 P1.4/*
RS(Register Select):- P1.0- 当 RS = 0 时,选择指令寄存器;当 RS = 1 时,选择数据寄存器。
RW(Read/Write):- P1.1- 当 RW = 0 时,进行写操作;当 RW = 1 时,进行读操作。
E(Enable):- P1.4- 下降沿触发数据传输。*/void check_busy() {char temp = 0x80; // 初始化为 1000 0000,用于读取忙碌标志位databuffer = 0x80;// 当单片机给 1602 发送数据时,通过检查忙碌标志位来避免死循环。// 高电平表示忙碌,在读取时序中,此时模块不能接收命令。如果为低电平表示不忙碌。while (temp & 0x80) {// 进入读时序RS = 0; // 设置为指令寄存器RW = 1; // 设置为读操作EN = 0;_nop_(); // 空操作,可能用于延时等待稳定EN = 1;_nop_();_nop_();temp = databuffer; // 读取数据总线上的值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 LCD1602_Init() {//(1)延时 15msDelay15ms();//(2)写指令 38H(不检测忙碌信号) Write_Cmd_Func(0x38);//(3)延时 5msDelay5ms();//(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) {// 将当前字符写入数据寄存器以显示在 LCD 上Write_data_Func(*string);// 指针指向下一个字符string++;}break;case 2:// 设置第二行的显示地址Write_Cmd_Func(0x80 + 0x40 + col);while (*string) {Write_data_Func(*string);string++;}break;}
}
主函数:
#include "reg52.h"
#include <intrins.h>
#include "delay.h"
#include "uart.h"
#include "lcd1602.h"
#include "dht11.h"
#include "config.h"// 定义用于存储温度和湿度显示字符串的字符数组
char temp[8];
char huma[8];
// 声明外部变量 datas,可能用于存储从 DHT11 传感器读取的数据
extern char datas[5];// 函数用于构建温度和湿度的显示字符串
void build_datas() {// 将湿度的标识字符 'H' 存入 huma 数组的第一个位置huma[0] = 'H';// 将 datas 数组中第一个元素(湿度整数部分的十位数字)转换为 ASCII 码存入 huma 数组的第二个位置huma[1] = datas[0]/10 + 0x30;// 将 datas 数组中第一个元素(湿度整数部分的个位数字)转换为 ASCII 码存入 huma 数组的第三个位置huma[2] = datas[0]%10 + 0x30;// 存入小数点huma[3] = '.';// 将 datas 数组中第二个元素(湿度小数部分的十位数字)转换为 ASCII 码存入 huma 数组的第四个位置huma[4] = datas[1]/10 + 0x30;// 将 datas 数组中第二个元素(湿度小数部分的个位数字)转换为 ASCII 码存入 huma 数组的第五个位置huma[5] = datas[1]%10 + 0x30;// 存入百分号huma[6] = '%';// 字符串结束标志huma[7] = '\0';// 将温度的标识字符 'T' 存入 temp 数组的第一个位置temp[0] = 'T';// 将 datas 数组中第三个元素(温度整数部分的十位数字)转换为 ASCII 码存入 temp 数组的第二个位置temp[1] = datas[2]/10 + 0x30;// 将 datas 数组中第三个元素(温度整数部分的个位数字)转换为 ASCII 码存入 temp 数组的第三个位置temp[2] = datas[2]%10 + 0x30;// 存入小数点temp[3] = '.';// 将 datas 数组中第四个元素(温度小数部分的十位数字)转换为 ASCII 码存入 temp 数组的第四个位置temp[4] = datas[3]/10 + 0x30;// 将 datas 数组中第四个元素(温度小数部分的个位数字)转换为 ASCII 码存入 temp 数组的第五个位置temp[5] = datas[3]%10 + 0x30;// 存入摄氏度符号temp[6] = 'C';// 字符串结束标志temp[7] = '\0';
}int main() {// 延时 1000 毫秒Delay1000ms();// 初始化串口UartInit();// 初始化 LCD1602LCD1602_Init();// 再次延时 1000 毫秒Delay1000ms();Delay1000ms();// 设置 ledOne 为 0,可能用于控制某个 LEDledOne = 0;while (1) {// 延时 1000 毫秒Delay1000ms();// 读取 DHT11 传感器的数据Read_Data();// 如果温度(datas[2])大于等于 24if (datas[2] >= 24) {// 设置风扇状态为关闭(fengshan 可能是一个变量用于控制风扇)fengshan = 0;} else {// 否则设置风扇状态为开启fengshan = 1;}// 构建温度和湿度的显示字符串build_datas();// 发送湿度字符串到串口sent_string(huma);// 发送回车换行符到串口sent_string("\r\n");// 发送温度字符串到串口sent_string(temp);// 发送回车换行符到串口sent_string("\r\n");// 在 LCD1602 的第一行第二列开始显示湿度字符串LCD1602_showline(1, 2, huma);// 在 LCD1602 的第二行第二列开始显示温度字符串LCD1602_showline(2, 2, temp);}
}
成功实现:
相关文章:

DTH11温湿度传感器
DHT11 是一款温湿度复合传感器,常用于单片机系统中进行环境温湿度的测量。以下是对 DHT11 温湿度传感器的详细讲解: 一、传感器概述 DHT11 数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器。它应用专用的数字模块采集技术和温湿度传感…...
【Linux系列】CMA (Contiguous Memory Allocator) 简单介绍
CMA (Contiguous Memory Allocator) CMA是Linux内核中的一种内存分配机制,用于分配物理上连续的内存块。它主要解决了在系统运行一段时间后,物理内存碎片化导致难以分配大块连续物理内存的问题。 CMA的工作原理 在系统启动时,CMA会预留一块…...

基于单片机餐厅呼叫控制系统仿真设计
文章目录 前言资料获取设计介绍设计程序具体实现截图设计获取 前言 💗博主介绍:✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师,一名热衷于单片机技术探索与分享的博主、专注于 精通51/STM32/MSP430/AVR等单片机设计 主要对象是咱们…...
详细分析Mysql中的定时任务(Event事件)
目录 前言1. 基本知识2. Event事件3. Demo 前言 基本的知识推荐阅读: 详细分析Mysql触发器的基本使用(图文解析)详细分析SQL Server触发器的基本知识详细分析Corn表达式(附Demo) 特性事件定时任务触发器触发条件基于…...
SpinalHDL之语义(Semantic)(三)
本文作为SpinalHDL学习笔记第七十一篇,介绍SpinalHDL的规则(Rules)。 目录: 1.简介(Introduction) 2.并⾏性(Concurrency) 3.以最后赋值为准(Last valid assignment wins) 4.Scala下的信号和寄存器的内在联系(Signal and register interactions with Scala)(OOP引⽤+函数…...
SpringBoot 请求和响应
1. Spring Boot 请求与响应概述 在 Spring Boot 开发中,客户端通过浏览器发起请求,后端使用内置的 Tomcat Web 服务器处理请求,返回响应数据。请求和响应的过程遵循 HTTP 协议。Spring Boot 的核心 Servlet 程序是 DispatcherServlet&#x…...

LQR算法核心思想
本章以倒立摆为解决目的 什么是线性二次型控制器(LQR) 开环系统 即状态变量的倒数 系统的状态空间矩阵A * 系统状态变量x A状态矩阵:描述系统本身物理特性的一个矩阵,它是由系统本身的机械结构、物理结构决定的,无法…...

AI大模型之旅-最强开源文生图工具Stable Diffusion WebUI 教程
1.1克隆 Automatic1111 的 GitHub 仓库 在你想安装 Web UI 的文件夹路径下执行 git clone https://github.com/AUTOMATIC1111/stable-diffusion-webui 这将会克隆整个仓库到本地。 这里会默认访问 https://huggingface.co/ 下载 因此需要魔法 1.2 进入仓库目录 cd stable-di…...

WinForm程序嵌入Web网页
文章目录 前言一、三方库或控件的选择测试二、Microsoft Edge WebView2安装、使用步骤1.安装2.使用 前言 由于此项目需要winform客户端嵌入web网页并于JAVA端交互数据,所以研究了一下嵌入web网页这部分,趟了一遍雷,这里做下记录。 一、三方库…...

Redis string类型hash类型
string类型 类型介绍 在Redis中的所有的key都是string类型,而value的类型有多种。 Redis中的字符串是直接按照二进制的方式进行存储的,也就是不会做任何的编码转换,存的是什么,取出来的就是什么。这样一般来说,Redi…...

Solidity智能合约中的异常处理(error、require 和 assert)
Solidity 中的三种抛出异常方法:error、require 和 assert 在 Solidity 开发中,异常处理是确保智能合约安全性和正确性的关键步骤。Solidity 提供了三种主要方法来抛出异常:error、require 和 assert。本文将详细介绍这三种方法的用途、实现方…...

True NAS禁用ipv6
在 TrueNAS Scale 中,禁用 IPv6 的方法如下:12 进入 System->Advanced->Sysctl,设置一个 sysctl 可调整变量 net.ipv6.conf.all.disable_ipv6,值为 1,以完全禁用 IPv6。\...

笔记整理—linux进程部分(2)使用fork创建进程
为什么要创建进程,首先每个程序的运行都需要一个进程;多进程实现宏观上的并行。 fork的原理,是进程的分裂生长模式。如果操作系统需要一个新的进程,那么就会以cp的方法得到一个新的进程,此时老的进程是父进程ÿ…...
在Python中实现多目标优化问题(6)
在Python中实现多目标优化问题 在Python中实现多目标优化,除了传统的进化算法(如NSGA-II、MOEA/D)和一些基于机器学习的方法外,还有一些新的方法和技术。这些新方法通常结合了最新的研究成果,提供了更高效的解决方案。…...

Java EE中的编码问题及解决方案
Java EE中的编码问题及解决方案 在Java EE开发中,处理字符编码是确保数据正确传输和显示的重要环节。不同的编码不一致会导致乱码,影响用户体验。本文将总结在Java EE中可能遇到的编码问题及其解决方案。 1. 输入数据编码问题 在表单提交时,…...
9月27日,每日信息差
第一、中国科学家团队在干细胞治疗领域取得重要突破,通过化学重编程技术成功制备出胰岛细胞,并用于移植治疗一名 1 型糖尿病患者,实现了临床功能性治愈。相关研究成果已发表在国际权威期刊《细胞》上。 第二、交通运输部公路局局长周荣峰在国…...
什么是 Angular 开发中的 Dumb components
Dumb components,在 Angular 开发中也被称为 Presentational components,它们的主要职责是通过展示数据和触发事件,把业务逻辑和 UI 表现分离开来。Dumb components 只通过 Input() 接收数据,Output() 向外发送事件,不…...
Docker 进入容器运行命令的详细指南
Docker 进入容器运行命令的详细指南 Docker 是一个开源的容器化平台,广泛应用于开发和生产环境中。它允许开发者打包应用程序及其依赖项到容器中,并能够在不同的平台上快速部署和运行。容器通常是独立且隔离的,但在开发、调试或维护过程中&a…...
如何禁止非真实用户的ip访问网站服务器
为了禁止非真实用户的IP访问网站服务器,可以采用多种技术手段和策略。以下是一些常用的方法: 1. 使用IP黑名单和白名单 黑名单:定期更新和维护一个IP黑名单,阻止已知的恶意IP地址或数据中心IP访问网站。白名单:对于特…...

探索SpringBoot:学科竞赛管理项目开发
2 相关技术简介 2.1Java技术 Java是一种非常常用的编程语言,在全球编程语言排行版上总是前三。在方兴未艾的计算机技术发展历程中,Java的身影无处不在,并且拥有旺盛的生命力。Java的跨平台能力十分强大,只需一次编译,任…...
Vim 调用外部命令学习笔记
Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...

Linux 文件类型,目录与路径,文件与目录管理
文件类型 后面的字符表示文件类型标志 普通文件:-(纯文本文件,二进制文件,数据格式文件) 如文本文件、图片、程序文件等。 目录文件:d(directory) 用来存放其他文件或子目录。 设备…...

关于nvm与node.js
1 安装nvm 安装过程中手动修改 nvm的安装路径, 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解,但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后,通常在该文件中会出现以下配置&…...

k8s业务程序联调工具-KtConnect
概述 原理 工具作用是建立了一个从本地到集群的单向VPN,根据VPN原理,打通两个内网必然需要借助一个公共中继节点,ktconnect工具巧妙的利用k8s原生的portforward能力,简化了建立连接的过程,apiserver间接起到了中继节…...
大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计
随着大语言模型(LLM)参数规模的增长,推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长,而KV缓存的内存消耗可能高达数十GB(例如Llama2-7B处理100K token时需50GB内存&a…...
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问(基础概念问题) 1. 请解释Spring框架的核心容器是什么?它在Spring中起到什么作用? Spring框架的核心容器是IoC容器&#…...

安全突围:重塑内生安全体系:齐向东在2025年BCS大会的演讲
文章目录 前言第一部分:体系力量是突围之钥第一重困境是体系思想落地不畅。第二重困境是大小体系融合瓶颈。第三重困境是“小体系”运营梗阻。 第二部分:体系矛盾是突围之障一是数据孤岛的障碍。二是投入不足的障碍。三是新旧兼容难的障碍。 第三部分&am…...

LLMs 系列实操科普(1)
写在前面: 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容,原视频时长 ~130 分钟,以实操演示主流的一些 LLMs 的使用,由于涉及到实操,实际上并不适合以文字整理,但还是决定尽量整理一份笔…...
适应性Java用于现代 API:REST、GraphQL 和事件驱动
在快速发展的软件开发领域,REST、GraphQL 和事件驱动架构等新的 API 标准对于构建可扩展、高效的系统至关重要。Java 在现代 API 方面以其在企业应用中的稳定性而闻名,不断适应这些现代范式的需求。随着不断发展的生态系统,Java 在现代 API 方…...

2025年- H71-Lc179--39.组合总和(回溯,组合)--Java版
1.题目描述 2.思路 当前的元素可以重复使用。 (1)确定回溯算法函数的参数和返回值(一般是void类型) (2)因为是用递归实现的,所以我们要确定终止条件 (3)单层搜索逻辑 二…...