STM32第九课:DHT11温湿度传感器
文章目录
- 需求
- 一、DHT11温湿度传感器
- 二、模块配置流程
- 1.配置时钟和IO
- 2.读取数据
- 3.数据处理
- 三、导入语音模块
- 四、关键代码
- 总结
需求
1.完成DHT11温湿度检测模块的配置。
2.处理DHT11获取的数据,在串口打印处理后的实时数据。
2.通过Su-03t语音识别模块实现实时温湿度的问答。

一、DHT11温湿度传感器
DHT11 数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器。它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有枀高的可靠性与卓越的长期稳定性。传感器包括一个电容式感湿元件和一个 NTC 测温元件,并与一个高性能 8 位单片机相连接。
引脚说明:
1、VDD 供电 3.3~5.5V DC
2、DATA 串行数据,单总线
3、NC 空脚
4、GND 接地,电源负枀
二、模块配置流程
1.配置时钟和IO


由原理图可知该模块连接的是stm32的PG11引脚所以此时我们只需要配置PG11的引脚即可。

根据该模块手册中的数据时序图可知:该引脚需要既能输入也能输出,所以为了能够同时满足输入和输出,我们将PG11引脚配置成开漏模式。

代码如下(示例):
void DHT11_Config()
{//配置为开漏模式//开时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG,ENABLE);//配置ioGPIO_InitTypeDef GPIO_InitStruct = {0};GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;GPIO_InitStruct.GPIO_Pin = GPIO_Pin_11;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOG,&GPIO_InitStruct);DHT11HIGH();
}
配置完成后拉高电平是为了满足主机“拉高等待”状态。
为了方便后续操作,先重定义一下拉高电平,拉低电平和读操作。
#define DHT11HIGH() GPIO_SetBits(GPIOG,GPIO_Pin_11)#define DHT11LOW() GPIO_ResetBits(GPIOG,GPIO_Pin_11)#define DHT11read() GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_11)
2.读取数据
根据官方提供的外设读取步骤一步步进行操作即可

由图可知要先拉高电平

再拉低电平并持续18ms

再输出高电平,然后用while检测83us的低电平应答信号。
收到应答信号后,再用while检测87us的高电平外设准备接受信号。


接收到高电平外设准备接受信号后就可以接收40位的数据了。
直接定义一个数组进行for循环接收。
由于该模块发送的数据为高低电平信号,并且是根据高电平持续时间的不同来判断究竟是高电平还是低电平,此时我们只需要加个延迟,比差值大 ,比74us小即可,此处我用的是45us。
3.数据处理

由手册可知,为了能够准确的将温湿度转换为10进制
此刻我们先用for循环将40个数据进行8位分组处理。
for(i=0;i<40;i++){ //0~7 8~15 16~23 24~31 32~39data[i/8]+=(arr[i]<<(7-i%8));}
分完组后在计算下和校验一下。
最后根据手册说明将16位数据转换为10进制并打印出来。
//根据DHT11时序读取数据
void DHT11_ReadData()
{uint16_t i = 0;uint16_t timeout = 0;uint8_t data[5] = {0};uint8_t arr[50] = {0};//输出一个最少18ms的低电平,最大30msDHT11HIGH();DHT11LOW();Delay_nms(18);DHT11HIGH();//检测有持续83us低电平和87us的高电平timeout=0;while(DHT11read()==1)//检测83us低电平{timeout++;Delay_nus(1);if(timeout>=100){return ;}}timeout=0;while(DHT11read()==0)//检测87us的高电平{timeout++;Delay_nus(1);if(timeout>=100){return ;}}//读取40位数据for(i=0;i<40;i++){timeout=0;while(DHT11read()==1)//等待us低电平{timeout++;Delay_nus(1);if(timeout>=100){return ;}}timeout=0;while(DHT11read()==0)//等待能判断的高电平标志{timeout++;Delay_nus(1);if(timeout>=100){return ;}}Delay_nus(45);arr[i]=DHT11read();}for(i=0;i<40;i++){ //0~7 8~15 16~23 24~31 32~39data[i/8]+=(arr[i]<<(7-i%8));}if(((data[0]+data[1]+data[2]+data[3])&0xff) != data[4]){return;}hum=data[0]+data[1]/10.0;tem=data[2]+(data[3]&0x7f)/10.0;if((data[3]&0x80) != 0){tem = 0-tem;}printf("读取完毕:湿度:%.1f 温度:%.1f\r\n",hum,tem);return;
}
三、导入语音模块
先在su03t.c文件中外部声明一下处理后的温度和湿度。
extern float hum;
extern float tem;
查看语音模块固件烧录时定义的指令,找到湿度温度播报的指令

可以看到温度指令为06,湿度指令为07。
最后将该数据和指令添加到int Su03tDealData()函数中就完成了。

四、关键代码
main.c
#include "stm32f10x.h"
#include "usart.h"
#include "stdio.h"
#include "delay.h"
#include "kqm.h"
#include "string.h"
#include "su03t.h"
#include "dht11.h"int main()
{NVIC_SetPriorityGrouping(5);//两位抢占两位次级Usart1_Config(); SysTick_Config(72000);Kqm_U4Config();Su03t_U5Config();DHT11_Config();while(1){ if(led2cnt[0]>=led2cnt[1]){//过去2sled2cnt[0]=0;DHT11_ReadData();}KQM_DealData();Su03tDealData();}
}
dht11.c
#include "dht11.h"
float hum,tem;
//PG11要能够切换输入输出
void DHT11_Config()
{//配置为开漏模式//开时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG,ENABLE);//配置ioGPIO_InitTypeDef GPIO_InitStruct = {0};GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;GPIO_InitStruct.GPIO_Pin = GPIO_Pin_11;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOG,&GPIO_InitStruct);DHT11HIGH();
}//根据DHT11时序读取数据
void DHT11_ReadData()
{uint16_t i = 0;uint16_t timeout = 0;uint8_t data[5] = {0};uint8_t arr[50] = {0};//输出一个最少18ms的低电平,最大30msDHT11HIGH();DHT11LOW();Delay_nms(18);DHT11HIGH();//检测有持续83us低电平和87us的高电平timeout=0;while(DHT11read()==1)//检测83us低电平{timeout++;Delay_nus(1);if(timeout>=100){return ;}}timeout=0;while(DHT11read()==0)//检测87us的高电平{timeout++;Delay_nus(1);if(timeout>=100){return ;}}//读取40位数据for(i=0;i<40;i++){timeout=0;while(DHT11read()==1)//等待us低电平{timeout++;Delay_nus(1);if(timeout>=100){return ;}}timeout=0;while(DHT11read()==0)//等待能判断的高电平标志{timeout++;Delay_nus(1);if(timeout>=100){return ;}}Delay_nus(45);arr[i]=DHT11read();}for(i=0;i<40;i++){ //0~7 8~15 16~23 24~31 32~39data[i/8]+=(arr[i]<<(7-i%8));}if(((data[0]+data[1]+data[2]+data[3])&0xff) != data[4]){return;}hum=data[0]+data[1]/10.0;tem=data[2]+(data[3]&0x7f)/10.0;if((data[3]&0x80) != 0){tem = 0-tem;}printf("读取完毕:湿度:%.1f 温度:%.1f\r\n",hum,tem);return;
}
dht11.h
#ifndef _DHT11_H_
#define _DHT11_H_
#include "stm32f10x.h"
#include "delay.h"
#include "stdio.h"
#include "string.h"
void DHT11_Config();
void DHT11_ReadData();#define DHT11HIGH() GPIO_SetBits(GPIOG,GPIO_Pin_11)#define DHT11LOW() GPIO_ResetBits(GPIOG,GPIO_Pin_11)#define DHT11read() GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_11)#endif
su03t.c
#include "stm32f10x.h"
#include "stdio.h"
#include "string.h"
#include "su03t.h"typedef struct{uint8_t u5_recv[10];//保存数据数组uint8_t u5_cnt;//数组下标uint8_t u5_tflag;
}UART5DATA;//数据类型void Su03t_U5Config()//串口5 PC12(TX) PD2(RX)
{//开时钟U5 PD12(TX) PD2(RX)RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD|RCC_APB2Periph_GPIOC,ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART5,ENABLE);//配置PC12(TX)GPIO_InitTypeDef GPIO_InitStruct = {0};GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;//复用推完输出GPIO_InitStruct.GPIO_Pin = GPIO_Pin_12;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOC,&GPIO_InitStruct);//PD2(RX)GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOD,&GPIO_InitStruct);//配置串口5 波特率9600 数据位8,校验位0,停止位1USART_InitTypeDef USART_InitStruct = {0};//可以通过结构体类型跳转USART_InitStruct.USART_BaudRate = 9600;//波特率USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//硬件控制流不开USART_InitStruct.USART_Mode = USART_Mode_Rx|USART_Mode_Tx;//打开接收USART_InitStruct.USART_Parity = USART_Parity_No;USART_InitStruct.USART_StopBits = USART_StopBits_1;USART_InitStruct.USART_WordLength = USART_WordLength_8b;USART_Init(UART5,&USART_InitStruct);//使能串口USART_Cmd(UART5,ENABLE);//配置串口4的中断(采用中断接收)USART_ITConfig(UART5,USART_IT_RXNE,ENABLE);//使能串口4 的接收非空中断USART_ITConfig(UART5,USART_IT_IDLE,ENABLE);//总线空闲中断NVIC_SetPriority(UART5_IRQn,6);//设置优先级0~15NVIC_EnableIRQ(UART5_IRQn);//使能中断通道
}//串口5发送单字节函数
void Uart5Senddata(uint8_t data)
{//等待发送完成while(USART_GetFlagStatus(UART5,USART_FLAG_TC)==0);//如果上次发送完成,就发送USART_SendData(UART5,data);
}//串口5发送数组函数
void U5_Sendarr(uint8_t * data,uint32_t len)
{uint32_t i=0;for(i=0;i<len;i++){Uart5Senddata(*data);data++;}
}UART5DATA u5_data={0};
void UART5_IRQHandler()//串口5中断执行
{uint8_t data=0;//判断接收中断是否发生if(USART_GetITStatus(UART5,USART_IT_RXNE)==SET){data = UART5->DR;//USART1->DR = data;//回显u5_data.u5_recv[u5_data.u5_cnt]=data;u5_data.u5_cnt++;u5_data.u5_cnt%=10;}//触发空闲中断,表示总线空闲,接收完毕if(USART_GetITStatus(UART5,USART_IT_IDLE)==SET){data = UART5->SR;//清理空闲中断,先读SR再读DRdata = UART5->DR; u5_data.u5_tflag=1;}
}//将double转换成8位类型数组arr
void DoubleToUint8(double data,uint8_t *arr)
{uint8_t *p = (uint8_t *)&data;uint8_t i=0;for(i=0;i<8;i++){arr[i]=p[i];printf("%02x ",*(p+i));}printf("\r\n");return;
}extern float voc;
extern float ch2o;
extern float co2;
extern float hum;
extern float tem;int Su03tDealData()
{if(u5_data.u5_tflag!=1){return 1;}if(u5_data.u5_recv[0]!=0xAA||u5_data.u5_recv[1]!=0x55){printf("数据帧头出错\r\n");return 2;}if(u5_data.u5_recv[4]!=0xAA||u5_data.u5_recv[3]!=0x55){printf("数据帧尾出错\r\n");return 3;} switch(u5_data.u5_recv[2]){case 1:printf("接收01,空气质量指令\r\n");Su03tSendMsg(1,voc);//vocbreak;case 2: printf(" 接收02,甲醛指令\r\n");Su03tSendMsg(2,ch2o);//vocbreak;case 3: printf(" 接收03,Co2指令\r\n");Su03tSendMsg(3,co2);//vocbreak;case 6: printf(" 接收06,温度指令\r\n");Su03tSendMsg(6,tem);break;case 7: printf(" 接收07,湿度指令\r\n");Su03tSendMsg(7,hum);break;}memset(&u5_data,0,sizeof(u5_data));return 0;
}//拼接指令函数 AA 55 04 00 00 00 00 00 80 37 40 55 AA
void Su03tSendMsg(uint8_t cmd,double data)
{uint8_t msg[13]={0};//存放要发送的指令msg[0]=0xAA;msg[1]=0x55;msg[2]=cmd;DoubleToUint8(data,&msg[3]);msg[11]=0x55;msg[12]=0xAA;//通过串口5发送U5_Sendarr(msg,13);
}
su03t.h
#ifndef _SU03T_H_
#define _SU03T_H_
#include "stm32f10x.h"
void Su03t_U5Config();
void Uart5Senddata(uint8_t data);
void U5_Sendarr(uint8_t * data,uint32_t len);
void UART5_IRQHandler();
void DoubleToUint8(double data,uint8_t *arr);
int Su03tDealData();
void Su03tSendMsg(uint8_t cmd,double data);
#endif
总结
1.先根据原理图和该模块的手册,配置对应的时钟和io。
2.进行数据读取,严格按照该模块手册中的时序一步一步来。
3.最后进行数据处理并导入到语音模块。
相关文章:
STM32第九课:DHT11温湿度传感器
文章目录 需求一、DHT11温湿度传感器二、模块配置流程1.配置时钟和IO2.读取数据3.数据处理 三、导入语音模块四、关键代码总结 需求 1.完成DHT11温湿度检测模块的配置。 2.处理DHT11获取的数据,在串口打印处理后的实时数据。 2.通过Su-03t语音识别模块实现实时温湿…...
JVM线上监控环境搭建Grafana+Prometheus+Micrometer
架构图 一: SpringBoot自带监控Actuator SpringBoot自带监控功能Actuator,可以帮助实现对程序内部运行情况监控,比如监控内存状况、CPU、Bean加载情况、配置属性、日志信息、线程情况等。 使用步骤: 1. 导入依赖坐标 <dependency><…...
MyBatis(17)MyBatis 如何处理枚举类型
MyBatis 处理枚举类型的机制相对直接,它提供了一种灵活的方式来处理Java枚举(enum)类型和数据库之间的映射。在MyBatis中,你可以通过两种方式处理枚举类型:使用枚举的名称(name)或者枚举的序号&…...
云数据中心运维新纪元:让Linux服务器如虎添翼
文章目录 一、Linux系统管理的高级技巧1. 性能调优与监控:2. 自动化与脚本编写:3. 文件系统与存储管理: 二、服务器配置优化的策略1. 硬件选型与配置:2. 网络配置与优化:3. 应用部署与调优: 三、安全策略的…...
C# 多线程造成CPU占用率高
当线程多的时候就会造成CPU内存占用率过高 private void button1_Click(object sender, EventArgs e){Thread TH1, TH2, TH3, TH4, TH5;TH1 new Thread(Thread1){IsBackground true};TH2 new Thread(Thread2){IsBackground true};TH3 new Thread(Thread3){IsBackground t…...
谈谈在不同公司中的SAP职位
今天反客为主,聊一下这个HR的话题,考虑到SAP职位的专业性,感觉还是有必要谈一谈这个话题。最近跟几位HR的小伙伴聊了一下,讨论了下不同公司的SAP职位的招聘要求,感觉还是有那么几个存在的问题: 追求完美的…...
服务器连接不上
记录今天2024/07/02的问题: 我今天真的是非常无语,今天在连服务器的时候,突然发现连不上了。 后来才意识到,原来是我笔记本先是开了全局代理,然后再用easy connected连接。当时还跳出了一个窗口如下,我当时…...
论文辅导 | 基于贝叶斯优化-卷积神经网络-双向长短期记忆神经网络的锂电池健康状态评估
辅导文章 模型描述 准确估计电池健康状态是设备稳定运行的关键。针对当前健康状态研究中容量难以直接测量、估计模型调参费时等问题,提出基于多健康特征的贝叶斯优化(BO)算法优化卷积神经网络(CNN)与双向长短期记忆&a…...
安卓实现微信聊天气泡
一搜没一个能用的,我来: 布局文件: <?xml version"1.0" encoding"utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android"http://schemas.android.com/apk/res/android"xml…...
软件测试(功能、接口、性能、自动化)详解 | 测试人生路
一、软件测试功能测试 测试用例编写是软件测试的基本技能;也有很多人认为测试用例是软件测试的核心;软件测试中最重要的是设计和生成有效的测试用例;测试用例是测试工作的指导,是软件测试的必须遵守的准则。 黑盒测试常见测试用…...
【面试题】网络IO模型
IO(Input/Output)模型指的是计算机系统中对输入/输出操作进行处理的不同方式。它定义了操作系统内核、应用程序和I/O设备之间如何交互和协调数据传输。不同的IO模型在效率、复杂性和适用场景方面都有所差异。以下是几种主要的IO模型及其特点:…...
数据结构-----【链表:基础】
链表基础 1、链表的理论基础 1)基础: 链表:通过指针串联在一起的线性结构,每个节点由两部分组成,一个是数据域,一个是指针域(存放指向下一个节点的指针),最后一个指针…...
如何在pycharm里面运行pytest用例
pycharm运行三种方式 1.以xx.py脚本方式直接执行,当写的代码里面没用到unittest和pytest框架时,并且脚本名称不是以test_开头命名的,此时pycharm会以xx.py脚本方式运行 2.当脚本命名为test_xx.py时,用到unittest框架,…...
Charles抓包工具踩坑记录
请添加图片描述 Charles抓包工具 证书问题 输入网址:chls.pro/ssl 第一个下载证书网址,会出现一直加载不出来,无法下载证书的情况 解决:选择下面save Charles Root。。。 2 证书在mac中禁止修改问题 解决也很简单,按照…...
【RabbitMQ实战】邮件发送(直连交换机、手动ack)
一、实现思路 二、异常情况测试现象及解决 说明:本文涵盖了关于RabbitMQ很多方面的知识点, 如: 消息发送确认机制 、消费确认机制 、消息的重新投递 、消费幂等性, 二、实现思路 1.简略介绍163邮箱授权码的获取 2.编写发送邮件工具类 3.编写RabbitMQ配置文件 4.生产者发起调用…...
python 笔试面试八股(自用版~)
1 解释型和编译型语言的区别 解释是翻译一句执行一句,更灵活,eg:python; 解释成机器能理解的指令,而不是二进制码 编译是整个源程序编译成机器可以直接执行的二进制可运行的程序,再运行这个程序 比如c 2 简述下 Pyth…...
《SpringBoot+Vue》Chapter04 SpringBoot整合Web开发
返回JSON数据 默认实现 依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>在springboot web依赖中加入了jackson-databind作为JSON处理器 创建一个实体类对象…...
腾讯地图异步调用
<template><!-- 定义地图显示容器 --><div id"container"></div> </template><script setup>import { onMounted } from vue;const mapKeys import.meta.env.VITE_GLOB_TX_MAP_KEYS;function initMap() {// //定义地图中心点坐…...
通过docker overlay2 目录名查找占用磁盘空间最大的容器名和容器ID
有时候经常会有个别容器占用磁盘空间特别大, 这个时候就需要通过docker overlay2 目录名查找占用磁盘空间最大的容器名和容器ID: 1、 首先进入到 /var/lib/docker/overlay2 目录下,查看谁占用的较多 [rootPPS-97-8-ALI-HD1H overlay2]# cd /var/lib/doc…...
每周算法:有向图强连通分量
题目链接 受欢迎的牛 题目描述 每头奶牛都梦想成为牛棚里的明星。被所有奶牛喜欢的奶牛就是一头明星奶牛。所有奶牛都是自恋狂,每头奶牛总是喜欢自己的。奶牛之间的“喜欢”是可以传递的——如果 A A A 喜欢 B B B, B B B 喜欢 C C C,那…...
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...
Ubuntu系统下交叉编译openssl
一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机:Ubuntu 20.04.6 LTSHost:ARM32位交叉编译器:arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...
DockerHub与私有镜像仓库在容器化中的应用与管理
哈喽,大家好,我是左手python! Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库,用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...
【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...
屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!
5月28日,中天合创屋面分布式光伏发电项目顺利并网发电,该项目位于内蒙古自治区鄂尔多斯市乌审旗,项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站,总装机容量为9.96MWp。 项目投运后,每年可节约标煤3670…...
如何将联系人从 iPhone 转移到 Android
从 iPhone 换到 Android 手机时,你可能需要保留重要的数据,例如通讯录。好在,将通讯录从 iPhone 转移到 Android 手机非常简单,你可以从本文中学习 6 种可靠的方法,确保随时保持连接,不错过任何信息。 第 1…...
12.找到字符串中所有字母异位词
🧠 题目解析 题目描述: 给定两个字符串 s 和 p,找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义: 若两个字符串包含的字符种类和出现次数完全相同,顺序无所谓,则互为…...
Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习)
Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习) 一、Aspose.PDF 简介二、说明(⚠️仅供学习与研究使用)三、技术流程总览四、准备工作1. 下载 Jar 包2. Maven 项目依赖配置 五、字节码修改实现代码&#…...
C++ 设计模式 《小明的奶茶加料风波》
👨🎓 模式名称:装饰器模式(Decorator Pattern) 👦 小明最近上线了校园奶茶配送功能,业务火爆,大家都在加料: 有的同学要加波霸 🟤,有的要加椰果…...
PHP 8.5 即将发布:管道操作符、强力调试
前不久,PHP宣布了即将在 2025 年 11 月 20 日 正式发布的 PHP 8.5!作为 PHP 语言的又一次重要迭代,PHP 8.5 承诺带来一系列旨在提升代码可读性、健壮性以及开发者效率的改进。而更令人兴奋的是,借助强大的本地开发环境 ServBay&am…...
