STM32F4_DHT11数字温湿度传感器
目录
前言
1. DHT11简介
2. DHT11数据结构
3. DHT11的传输时序
3.1 DHT11开始发送数据流程
3.2 主机复位信号和DHT11响应信号
3.3 数字 “0” 信号表示方法
3.4 数字 “1” 信号表示方法
4. 硬件分析
5. 实验程序详解
5.1 main.c
5.2 DHT11.c
5.3 DHT11.h
前言
DHT11数字温湿度传感器不但能测温度,还能测湿度。本节我们将利用STM32F4来读取DHT11的温湿度传感器,获取环境的温度和湿度值。
1. DHT11简介
DHT11是广州奥松有限公司生产的一款温湿度一体化的数字传感器。该传感器包括一个电阻式测湿元件和一个NTC测温元件,并与一个高性能8位单片机相连。通过单片机等微处理器简单的电路连接就能实时的采集本地的温度和湿度。DHT11 与单片机之间能采用简单的单总线进行通信,仅仅需要一个I/O 口。
性能指标和特性:
- 工作电压范围:3.5V~5.5V
- 工作电流:0.5mA
- 湿度测量范围:20-90%RH
- 温度测量范围:0-50℃
- 湿度分辨率:1%RH 8位
- 温度分辨率:1℃ 8位
- 采样周期:1S
- 单总线结构
- 与TTL兼容(5V)
2. DHT11数据结构
DHT11数字温湿度传感器采用单总线数据格式。通过单个数据的引脚端口就可以完成输入输出双向传输。其数据包由5Byte(5*8=40Bit)组成。数据分小数部分和整数部分。
一次完整的数据传输为40bit,高位先行。
数据格式:8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据+8bit校验和
其中校验和数据为前四个字节相加。
DHT11和DS18B20相同,传感器输出的都是未编码的二进制数字。数据(湿度、温度、整数、小数)之间应该分开进行处理。
比方说:
DHT11温湿度传感器一次完整的数据传输位如上图所示
那么:humidity(湿度)=byte4 . byte3=45.0(%RH)
temperature(温度)=byte2 . byte1=28.0(℃)
校验位byte0:byte4+byte3+byte2+byte1=73(humidity+temperature)
因此:温湿度的读取方式就是整数部分的二进制转换成十进制放在整数部分;小数部分的二进制转换成十进制放在小数部分。
注意:DHT11和MCU的一次通讯时间最大3ms,主机连续向DHT11采样的间隔建议不小于100ms。
3. DHT11的传输时序
3.1 DHT11开始发送数据流程
主机发送开始信号后,延时等待20us~40us后读取DHT11的应答信号,正常的话,DHT11 会拉低数据线,保持40~50us时间,读取总线为低电平,说明DHT11发送响应信号,DHT11发送响应信号后,再把总线拉高,保持40-50us,准备发送数据,每一位 bit 数据都以低电平开始。
如果读取响应为高电平,则DHT11没有响应,检查线路是否连接正常。
3.2 主机复位信号和DHT11响应信号
主机发送复位信号后,主机拉低总线,延时至少18ms,然后将主机拉高,延迟20-40us等待DHT11的应答信号。读取总线电平,如果为低电平,则表示从机DHT11发送应答信号成功。然后从机把总线拉高,准备发送数据。之所以拉高,是因为每发送一位数据都是以低电平开始的,为发送数据做准备。
3.3 数字 “0” 信号表示方法
因为DHT11也是遵循单总线协议的。所以也是通过高低电平延时不同时间进行组合来发送逻辑1或者逻辑0.
从机DHT11拉低总线,延时12-14us,然后从机释放总线,延时26-28us。表示发送数字 “0”
3.4 数字 “1” 信号表示方法
从机DHT11拉低总线,延时12-14us,然后从机释放总线,延时116-118us。表示发送数字 “1”
4. 硬件分析
- VCC:正电源,支持3.5V~5.5V
- Dout:输出引脚
- NC:空脚
- GND:地
DHT11数字温湿度传感器的第一脚接电源正极,第四脚接电源地端。数据端为第二脚。第二端数据引脚可以直接接在主机(单片机)的IO口。同时为了提高稳定性,一般在数据端和电源正极之间接一只4.7K的上拉电阻。第三脚NC为空脚,此管脚悬空不用。
5. 实验程序详解
实验现象:开机的时候先检测是否有DHT11存在,如果没有,则提示错误。只有在检测到DHT11之后才会开始读取温湿度值。如果发现了DHT11,则程序每隔100ms左右读取一次数据。
5.1 main.c
#include "stm32f4xx.h"
#include "delay.h"
#include "usart.h"
#include "LED.h"
#include "lcd.h"
#include "Key.h"
#include "usmart.h"
#include "MyI2C.h"
#include "AT24C02.h"
#include "DS18B20.h"
#include "DHT11.h"//LCD状态设置函数
void led_set(u8 sta)//只要工程目录下有usmart调试函数,主函数就必须调用这两个函数
{LED1=sta;
}
//函数参数调用测试函数
void test_fun(void(*ledset)(u8),u8 sta)
{led_set(sta);
}
int main(void)
{u8 t=0;u8 temperature;u8 humidity;delay_init(168);uart_init(115200);LED_Init();LCD_Init();POINT_COLOR=RED;LCD_ShowString(30,50,200,16,16,"Explorer STM32F4");LCD_ShowString(30,70,200,16,16,"DHT11 Text");LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTER");LCD_ShowString(30,110,200,16,16,"2023/20/23");while(DHT11_Init())//返回1表示没有检测到DHT11的存在,报错{LCD_ShowString(30,130,200,16,16,"DHT11 Rrror");delay_ms(200);LCD_Fill(30,130,239,130+16,WHITE); //清除这块区域 x 30~239 y 130~130+16delay_ms(200);}LCD_ShowString(30,130,200,16,16,"DHT11 OK");POINT_COLOR=BLUE;LCD_ShowString(30,150,200,16,16,"Temperature: C");LCD_ShowString(30,170,200,16,16,"Humidity: %");while(1){if(t%10==0) //每100ms读取一次{DHT11_Read_Data(&temperature,&humidity); //读取温湿度的值LCD_ShowNum(30+12*8,150,temperature,2,16); //显示温度LCD_ShowNum(30+9*8,170,humidity,2,16); //显示湿度}delay_ms(10);t++;if(t==20){t=0;LED0=!LED0;}}
}
5.2 DHT11.c
#include "stm32f4xx.h"
#include "DHT11.h"
#include "delay.h"//复位DHT11
void DHT11_Reset(void)
{//复位DHT11的时序:主机拉低总线,延时至少18ms,然后主机拉高总线,延时20-40us,等待从机应答DHT11_IO_OUT(); //复位时序是主机来完成的,所以首先设置主机IO引脚输出模式DHT11_DQ_OUT=0; //主机拉低总线delay_ms(20); //延时至少18msDHT11_DQ_OUT=1; //主机拉高总线delay_us(30); //延时20-40us
}
//等待DHT11的应答信号
//返回1:未检测到DHT11的存在
//返回0:存在
u8 DHT11_CheckExist(void)
{//应答信号的时序是:主机发送应答信号后,从机DHT11会拉低信号线,保持40-50us。此时,若读取主机总线为低电平,这说明DHT11发送了应答信号//DHT11发送应答信号之后,再把总线拉高,保持40-50us,准备发送数据,每一位bit数据都是以低电平开始的。u8 Existence=0;DHT11_IO_IN(); //主机IO引脚设置为输入模式,等待从机的应答信号输入while(DHT11_DQ_IN&&Existence<100) //从机DHT11会拉低信号线,保持40-80us,等待应答 按位&&操作必须两个条件都为真才是真{//DHT11_DQ_IN为真,就一直在这里循环,表示始终没有接收到从机DHT11的应答信号;因为总线拉低,读取高电平是始终没有响应的//DHT11_DQ_IN是从机DHT11发送主机MCU的信号,应答信号时,从机会拉低信号线,因此,如果主机收到的是高电平,那么意味着没有发送应答信号//Existence<100表示:设置一个缓冲时间去等待从机发送应答,这里设置的就是100usExistence++;delay_us(1);}if(Existence>=100){return 1; //主机给从机的缓冲时间是100us,主机等了从机100us还是没有接收到应答信号,那么返回信息,未检测到DHT11的存在}else //在给定的100us内接收到了应答信号,将缓冲计时变量Existence清0,为后续总线拉高后延迟做准备Existence=0;while(!DHT11_DQ_IN&&Existence<100) //拉低后再次拉高,准备发送数据,延迟40-80us{//!DHT11_DQ_IN表示主机接收到了应答信号,也就是主机接收到了低电平,延迟100usExistence++;delay_us(1);}if(Existence>=100){return 1;}return 0;
}
//从DHT11读取一个位
//返回值:1/0
u8 DHT11_Read_Bit(void)
{//DHT11读取一位的时序:不管读的那一位是高电平1还是低电平0,首先从机DHT11都需要拉低总线//数据0:从机拉低总线,延时12-14us,然后从机释放总线,延时26-28us//数据1:从机拉低总线,延时12-14us,然后从机释放总线,延时116-118usu8 data=0;while(DHT11_DQ_IN&&data<100)//等待变为低电平//主机从DHT11读取一位,从机要拉低总线,在没有拉低之前,主机收到的DHT11_DQ_IN一定是高电平1,而通过观察低电平的时序可以发现,不管是逻辑1还是0,低电平延时12-14us//所以设置的100us是远远大于低电平延时时间的,所以data<100这个条件在此while循环中一定为真,跳出循环的条件一定是DHT11_DQ_IN=0,也就是等待变为低电平{data++;delay_us(1);}data=0; //离开while循环时主机一定收到了低电平,此时DHT11_DQ_IN=0;设置data=0是为后续等待高电平做准备while(!DHT11_DQ_IN&&data<100) //等待变为高电平{//从上面的循环出来时,DHT11_DQ_IN=0,取反就为真//条件data<100:低电平0的整个发送时序延时时间(包括低电平延时12-14us,高电平延时26-28us)也远远小于100us,所以data<100在该循环中也是始终为真的// 高电平1的整个发送时间是大于100us的(低电平延时12-14us,高电平延时116-118us)//经分析,离开循环的条件是DHT11_DQ_IN变为高电平=1,取反等于0,为假。在低电平0的12-14us过去以后,高电平信号就会来临data++;delay_us(1);}//delay_us(40) 没有这个延迟40us是无法判断是数据1还是数据0的delay_us(40);//从上一个while循环出来以后,时序停留在刚刚变为高电平的瞬间,这个时候延时40us,数据0会跳过高电平,数据1会停留在高电平if(DHT11_DQ_IN) //这个时候根据主机读到的是1还是0设置返回值return 1;elsereturn 0;
}
//从DHT11读取一个字节
//返回值:读到的数据
u8 DHT11_Read_Byte(void)
{u8 i,data;data=0;for(i=0;i<8;i++){data=data<<1; //DHT11读取的字节是高位先行的,所以每循环一次都要将上次读取的那一位左移,右侧最低位补0,每次都将新读取的那一位数据和0进行|或运算。data=data|DHT11_Read_Bit();}return data;
}
//从DHT11读取一位数据
//temperature:温度值(范围:0~50℃)
//humidity:湿度值(范围:20%~90%)
//返回值:0 正常;1 读取失败
u8 DHT11_Read_Data(u8 *temperature,u8 *humidity)
{//DHT11的数据格式是:5个字节,40位数据,前两位是湿度的整数和小数部分,第三、第四位是温度的整数和小数部分,最后一位是校验位u8 Buf[5]; //定义一个数组来存放收到的5个字节的数组u8 i;DHT11_Reset();if(DHT11_CheckExist()==0) //应答信号返回值为0,表示检测到了DHT11应答信号{for(i=0;i<5;i++) //调用读字节函数将读取到的5个字节存放到Buf数组中{Buf[i]=DHT11_Read_Byte();}if((Buf[0]+Buf[1]+Buf[2]+Buf[3])==Buf[4]) //检验成功{*humidity=Buf[0]; //这里只显示了温湿度的整数部分*temperature=Buf[2];}}elsereturn 1; //DHT11_CheckExist()==1 表示没有检测到DHT11的应答信号,报错return 0; //返回正常情况
}
//初始化DHT11的IO口 DQ 同时检测DHT11的存在
//返回1:不存在
//返回0:存在
u8 DHT11_Init(void)
{RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG,ENABLE); //使能GPIOG时钟GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT; //默认设置为输出模式GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOG,&GPIO_InitStructure);DHT11_Reset();return DHT11_CheckExist(); //初始化返回检测DHT11是否成功,0:成功 1:收不到应答信号,报错
}
5.3 DHT11.h
#ifndef _DHT11__H_
#define _DHT11__H_
#include "sys.h"//IO方向设置
//IO方向是通过位段设置的,调用GPIO模式寄存器,以下代码已经多次使用,如有不理解,可回头温习DS18B20的实验代码
#define DHT11_IO_IN() {GPIOG->MODER&=~(3<<(9*2));GPIOG->MODER|=0<<9*2;} //PG9输入模式
#define DHT11_IO_OUT() {GPIOG->MODER&=~(3<<(9*2));GPIOG->MODER|=1<<9*2;} //PG9输出模式 //IO引脚设置
#define DHT11_DQ_OUT PGout(9) //PG9输出
#define DHT11_DQ_IN PGin(9) //PG9输入void DHT11_Reset(void);
u8 DHT11_CheckExist(void);
u8 DHT11_Read_Bit(void);
u8 DHT11_Read_Byte(void);
u8 DHT11_Read_Data(u8 *temperature,u8 *humidity);
u8 DHT11_Init(void);#endif
本节程序每一步都进行了详细的注释,有哪里解释的不对的,欢迎指正!!!
相关文章:

STM32F4_DHT11数字温湿度传感器
目录 前言 1. DHT11简介 2. DHT11数据结构 3. DHT11的传输时序 3.1 DHT11开始发送数据流程 3.2 主机复位信号和DHT11响应信号 3.3 数字 “0” 信号表示方法 3.4 数字 “1” 信号表示方法 4. 硬件分析 5. 实验程序详解 5.1 main.c 5.2 DHT11.c 5.3 DHT11.h 前言 DH…...

WiFi(Wireless Fidelity)基础(十一)
目录 一、基本介绍(Introduction) 二、进化发展(Evolution) 三、PHY帧((PHY Frame ) 四、MAC帧(MAC Frame ) 五、协议(Protocol) 六、安全&#x…...

操作系统—— 精髓与设计原理--期末复习
一、计算机系统概述 1、基本构成 计算机有四个主要的结构化部件: ①处理器(Processor):控制计算机的操作,执行数据处理功能。当只有一个处理器时,它通常指中央处理器(CPU) ②内存…...

每天一道算法练习题--Day21 第一章 --算法专题 --- ----------位运算
我这里总结了几道位运算的题目分享给大家,分别是 136 和 137, 260 和 645, 总共加起来四道题。 四道题全部都是位运算的套路,如果你想练习位运算的话,不要错过哦~~ 前菜 开始之前我们先了解下…...

D1. LuoTianyi and the Floating Islands (Easy Version)(树形dp)
Problem - D1 - Codeforces 这是问题的简化版本。唯一的区别在于在该版本中k≤min(n,3)。只有在两个版本的问题都解决后,才能进行黑客攻击。 琴音和漂浮的岛屿。 洛天依现在生活在一个有n个漂浮岛屿的世界里。这些漂浮岛屿由n−1个无向航线连接,任意两个…...

rk3588移植ubuntu server
ubuntu server 18.04 arm版本. 1、使用qemu运行 安装qemu-system-aarch64 sudo apt install -y qemu-system-arm 2、下载ubuntu server Index of /releases/18.04.3 3、创建虚拟磁盘 qemu-img create ubuntuimg.img 40G 4、创建虚拟机 弹出界面,直接回车选…...

如何更好地刷力扣
之前刷力扣是一口气看很多题目,打算时不时看一会题解,逐渐熟悉套路,争取背过,最后就可以写出来了。我个人是背知识比较喜欢这种方法,但后来发现根本不适用 算法题本身就比较复杂,不经过实际写代码中的思考…...

上采样和下采样
首先,谈谈不平衡数据集。不平衡数据集指的是训练数据中不同类别的样本数量差别较大的情况。在这种情况下,模型容易出现偏差,导致模型对数量较少的类别预测效果不佳。 为了解决这个问题,可以使用上采样和下采样等方法来调整数据集…...

小猪,信息论与我们的生活
前言 动态规划是大家都熟悉与陌生的知识,非常灵活多变,我自己也不敢说自己掌握了,今天给大家介绍一道题,不仅局限于动态规划做题,还会上升到信息论,乃至于启发自己认知世界的角度 因为比较难,本…...

【鸿蒙应用ArkTS开发系列】- http网络库使用讲解和封装
目录 前言http网络库组件介绍http网络库封装创建Har Module创建RequestOption 配置类创建HttpCore核心类创建HttpManager核心类对外组件导出添加网络权限 http网络库依赖和使用依赖http网络库(httpLibrary)使用http网络库(httpLibrary&#x…...

【Java零基础入门篇】第 ⑥ 期 - 异常处理
博主:命运之光 专栏:Java零基础入门 学习目标 掌握异常的概念,Java中的常见异常类; 掌握Java中如何捕获和处理异常; 掌握自定义异常类及其使用; 目录 异常概述 异常体系 常见的异常 Java的异常处理机制…...

计算职工工资
目录 问题描述 程序设计 问题描述 【问题描述】 给定N个职员的信息,包括姓名、基本工资、浮动工资和支出,要求编写程序顺序输出每位职员的姓名和实发工资(实发工资=基本工资+浮动工资-支出)。 【输入形式】 输入在一行中给出正整数N。随后N行,每行给出一位职员的信息,…...

2019年上半年软件设计师下午试题
试题四(共 15 分) 阅读下列说明和 C 代码,回答问题 1 至 3,将解答写在答题纸的对应栏内 【说明】 n 皇后问题描述为:在一个 n*n 的棋盘上摆放 n 个皇后,要求任意两个皇后不能冲突, 即任意两个皇后不在同一行、同一列或者同一斜…...

IS200TPROH1BCB用于工业应用和电力分配等。高压型隔离开关用于变电站
IS200TPROH1BCB用于工业应用和电力分配等。高压型隔离开关用于变电站 什么是隔离器,它与断路器有何不同 什么是隔离器,为什么要使用隔离器 隔离器是一种开关装置,它可以手动或自动操作,隔离一部分电能。隔离器可用于在无负载情…...

【MySql】数据库 select 进阶
数据库 数据库表的设计ER 关系图三大范式 聚合函数与分组查询聚合函数 (count、sum、avg、max、min)分组查询 group by fields....having....(条件) 多表联查内连接外连接(左连接,右连接)自连接子查询合并查询 UNION 数据库表的设计 ER 关系…...

CVPR 2023 | VoxelNeXt实现全稀疏3D检测跟踪,还能结合Seg Anything
在本文中,研究者提出了一个完全稀疏且以体素为基础的3D物体检测和跟踪框架VoxelNeXt。它采用简单的技术,运行快速,没有太多额外的成本,并且可以在没有NMS后处理的情况下以优雅的方式工作。VoxelNeXt在大规模数据集nuScenes、Waymo…...

本地使用3台centos7虚拟机搭建K8S集群教程
第一步 准备3台centos7虚拟机 3台虚拟机与主机的网络模式都是桥接的模式,也就是他们都是一台独立的“主机” (1)kebe-master的配置 虚拟机配置: 网络配置: (2)kebe-node1的配置 虚拟机配…...

NVIDIA CUDA驱动安装
1 引言 因为笔记本电脑上运行Milvus图像检索代码,需要安装CUDA驱动。电脑显卡型号是NVIDIA GeForce GTX 1050 Ti Mobile, 操作系统是Ubuntu 20.04,内核版本为Linux 5.15.0-72-generic。 2 CUDA驱动测试 参考网上的资料:https://blog.csdn.…...

python 从excel中获取需要执行的用例
classmethod def get_excel_data(cls, excel_name, sheet_name, case_numNone):"""读取excel文件的方法:param excel_name: 文件名称:param sheet_name: sheet页的名称:param case_name: 执行的case名称:return:"""def get_row_data(table, row)…...

Web3中文|乱花渐欲meme人眼,BRC-20总市值逼近10亿美元
现在的Web3加密市场,用“乱花渐欲meme人眼”来形容再合适不过了。 何为meme? “meme”这个词大概很多人都不知道如何正确发音,并且一看到它就会和狗狗币Dogecoin等联系在一起。那它究竟从何而来呢? Meme:[mi:m]&#x…...

盖雅案例入选「首届人力资源服务国际贸易交流合作大会20项创新经验」
近日,首届人力资源服务国际贸易交流合作大会顺利召开。为激励企业在人力资源服务贸易领域不断创新,加快培育对外贸易新业态、新模式,形成人力资源服务领域国际竞争新优势,大会评选出了「首届人力资源服务国际贸易交流合作大会20项…...

[论文笔记]SimMIM:a Simple Framework for Masked Image Modeling
文章地址:https://arxiv.org/abs/2111.09886 代码地址:https://github.com/microsoft/SimMIM 文章目录 摘要文章思路创新点文章框架Masking strategyPrediction headPrediction targetEvaluation protocols 性能实验实验设置Mask 策略预测头目标分辨率预…...

mysql从零开始(4)----索引/视图/范式
接上文 mysql从零开始(3) 索引 索引是在数据库表的字段上添加的,是为了提高查询效率存在的一种机制。一张表的一个字段可以添加一个索引,也可以多个字段联合起来添加索引。索引相当于一本书的目录,是为了缩小扫描范围…...

Flutter框架:从入门到实战,构建跨平台移动应用的全流程解析
第一章:Flutter框架介绍 Flutter框架是由Google推出的一款跨平台移动应用开发框架。相比其他跨平台框架,Flutter具有更高的性能和更好的用户体验。本章将介绍Flutter框架的概念、特点以及与其他跨平台框架的比较,以及Flutter开发环境的搭建和…...

Spring AOP+注解方式实现系统日志记录
一、前言 在上篇文章中,我们使用了AOP思想实现日志记录的功能,代码中采用了指定连接点方式(Pointcut(“execution(* com.nowcoder.community.controller..(…))”)),指定后不需要在进行任何操作就可以记录日志了&…...

OpenGL 4.0的Tessellation Shader(细分曲面着色器)
细分曲面着色器(Tessellation Shader)处于顶点着色器阶段的下一个阶段,我们可以看以下链接的OpenGL渲染流水线的图:Rendering Pipeline Overview。它是由ATI在2001年率先设计出来的。 目录 细分曲面着色器细分曲面Patch细分曲面控…...

项目经理如何及时掌控项目进度?
延迟是指超出计划的时间,而无法掌控则意味着管理者对实际情况一无所知。 为了解决这些问题,我们需要建立好的制度和沟通机制。例如使用项目管理软件来跟踪进度、定期开会并避免沟通障碍等。 管理者可以建立相关制度: 1、建立进度记录制度。…...

HTML <applet> 标签
HTML5 中不支持 <applet> 标签在 HTML 4 中用于定义嵌入式小程序(插件)。 实例 一个嵌入的 Java applet: <applet code="Bubbles.class" width="350" height="350"> Java applet that draws animated bubbles. </applet&g…...

加密与解密
加密与解密 加密方式分类 加密方式主要分为两种 一种是对称加密一种是非对称加密 对称加密 对称和非对称两种方式主要说的是加密和解密两个过程。 如果对数据用一个钥匙进行了加密,那么, 你想成功读取到这个加密了的数据的话,就必须对这…...

京东金融Android瘦身探索与实践
作者:京东科技 冯建华 一、背景 随着业务不断迭代更新,App的大小也在快速增加,2019年~2022年期间一度超过了117M,期间我们也做了部分优化如图1红色部分所示,但在做优化的同时面临着新的增量代码,包体积一直…...