STM32获取DHT11温湿度(单总线通信实验笔记)

发布者:dong125612最新更新时间:2022-08-18 来源: csdn关键字:STM32 手机看文章 扫描二维码
随时随地手机看文章

笔记:

在这里插入图片描述

DHT11是一款湿温度一体化的数字传感器。该传感器包括一个电阻式测湿元件和一个NTC测温元件,并与一个高性能8位单片机相连接。通过单片机等微处理器简单的电路连接就能够实时的采集本地湿度和温度。DHT11与单片机之间能采用简单的单总线进行通信,仅仅需要一个1/0口。传感器内部湿度和温度数据40Bit的数据一次性传给单片机,数据采用校验和方式进行校验,有效的保证数据传输的准确性。DHT11功耗很低, 5V电源电压下,工作平均最大电流0.5mA


DHT11数字湿温度传感器采用单总线数据格式。即,单个数据引脚端口完成输入输出双向传输。其数据包由SByte (40Bit)组成。数据分小数部分和整数部分,一次完整的数据传输为40bit,高位先出。DHT11的数据格式为: 8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据+8bit校验和。其中校验和数据为前四个字节相加。传感器数据输出的是未编码的二进制数据。数据(湿度、温度、整数、小数)之间应该分开处理。

数据类型是这样子的:

在这里插入图片描述

由以上数据就可得到湿度和温度的值,计算方法:

湿度= byte4 . byte3-45.0 (%RH)

温度=byte2 . bytel=28.0 (℃)

校验和= byte4+ byte3+ byte2+ byte1-73(湿度+温度)(校验正确)

在这里插入图片描述

但是小数往往不准,达不到精度要求!!!

一般通信时间3ms左右,时序图:

在这里插入图片描述

STM32发送高(20us)低(18us),然后去读取DHT11的响应,低(40us)高(40us),然后等待他发送数据过来了,数据格式:低高

在这里插入图片描述
在这里插入图片描述

低为起始位,证明1个位的数据要发送了,然后再看拉高的时间,

如果为26us为低,逻辑“0”,

如果大于100us为高,逻辑“1”

由这些01010组成8位的数据为1bety数据,一共会发五个,5bety=5*8=40位

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

程序流程图:

在这里插入图片描述

用的是正点原子的代码,理论上通用,备注自己加的,有问题还请指正


#define输入输出操作:


#define DHT11_IO_IN()  {GPIOG->CRH&=0XFFFF0FFF;GPIOG->CRH|=8<<12;}//定义GPIOG的第11引脚模式为输入,用的是寄存器操作 高八位第四个F为11引脚,CRH模式为12

#define DHT11_IO_OUT() {GPIOG->CRH&=0XFFFF0FFF;GPIOG->CRH|=3<<12;}//定义GPIOG的第11引脚模式为输输出

IO操作函数    

#define DHT11_DQ_OUT PGout(11) //数据端口 PG11输出

#define DHT11_DQ_IN  PGin(11)  //数据端口 PG11输入


//初始化DHT11的IO口 DQ 同时检测DHT11的存在

//返回1:不存在

//返回0:存在     

u8 DHT11_Init(void)

{  

  GPIO_InitTypeDef  GPIO_InitStructure;

 

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG, ENABLE); //使能PG端口时钟

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; //PG11端口配置

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

  GPIO_Init(GPIOG, &GPIO_InitStructure); //初始化IO口

  GPIO_SetBits(GPIOG,GPIO_Pin_11); //PG11 输出高

    

DHT11_Rst();  //复位DHT11

return DHT11_Check();//等待DHT11的回应


拉高拉低DHT11_Rst:


//拉高拉低

void DHT11_Rst(void)    

{                 

DHT11_IO_OUT(); //SET OUTPUT

    DHT11_DQ_OUT=0; //拉低DQ

    delay_ms(20);    //拉低至少18ms

    DHT11_DQ_OUT=1; //DQ=1 

delay_us(30);      //主机拉高20~40us

}


拉高拉低完之后等待DHT11回应拉低拉高:


//等待DHT11的回应

//返回1:未检测到DHT11的存在

//返回0:存在

u8 DHT11_Check(void)

{   

u8 retry=0; //定义一个玩意计数,怕卡死在这个函数

DHT11_IO_IN(); //设置输入模式  

    while (DHT11_DQ_IN&&retry<100)//DHT11会拉低40~80us,等待他读取到dht11拉低

{

retry++;

delay_us(1); //理论上应该是和时许保持一致的,但是他没有

};  

if(retry>=100)return 1; //超时退出返回1(错误)

else retry=0; //没问题就使计算等于0,继续下一轮计数

    while (!DHT11_DQ_IN&&retry<100)//DHT11拉低后会再次拉高40~80us

{

retry++;

delay_us(1); //理论上应该是和时许保持一致的,但是他没有

};

if(retry>=100)return 1;     

return 0; //返回0,证明DHT11已经完成回应了

}


读取1bit,变低后变高,看高的时间:


//从DHT11读取一个位

//返回值:1/0

u8 DHT11_Read_Bit(void)  

{

  u8 retry=0; //计时值

while(DHT11_DQ_IN&&retry<100)//等待变为低电平(等待上一次高低平完成,已经正在变为低电平)

{

retry++;

delay_us(1); //理论上应该和时序图的 12us吻合,但是他没有,效果达到就行了

}

retry=0;

while(!DHT11_DQ_IN&&retry<100)//等待变高电平,变高就退出这里

{

retry++;

delay_us(1);

}

delay_us(40); //等待40us

if(DHT11_DQ_IN)return 1;//如果DHT11_DQ_IN是高则为高,则为逻辑1 是低说明已经从高下去了,则为逻辑0

else return 0;    

}


读取1个字节:


一个字节=8位 = 1beyt = 8bit


//从DHT11读取一个字节

//返回值:读到的数据

u8 DHT11_Read_Byte(void)    

{        

    u8 i,dat;

    dat=0;

for (i=0;i<8;i++) //获取1bit,给dat,然后左移一位,再给dat,这样子就完成了8个bit变成1bety的操作了   相当于是1bety保存了8bit

{

    dat<<=1; 

    dat|=DHT11_Read_Bit();//“|”表示按位或

    }     

    return dat;

}


将bety变成数据,数组的形式存起来:


//从DHT11读取一次数据

//temp:温度值(范围:0~50°)

//humi:湿度值(范围:20%~90%)

//返回值:0,正常;1,读取失败

u8 DHT11_Read_Data(u8 *temp,u8 *humi)    

{        

  u8 buf[5];

u8 i;

DHT11_Rst();

if(DHT11_Check()==0)

{

for(i=0;i<5;i++)//读取40位数据

{

buf[i]=DHT11_Read_Byte();

}

if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4])

{

*humi=buf[0];

*temp=buf[2];

/*小数位置不准,舍弃了,如果有需要可以自己添加buf[1]和buf[3]*/


}

}else return 1;

return 0;     

}


主函数:


#include "delay.h"

#include "key.h"

#include "sys.h"

#include "usart.h"  

#include "dht11.h"

 int main(void)

 {  

u8 temperature;      

u8 humidity;       

delay_init();     //延时函数初始化   

  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级

uart_init(115200); //串口初始化为115200

  

  while(DHT11_Init()) //DHT11初始化

{

delay_ms(200);

}    

 

while(1)

{         

DHT11_Read_Data(&temperature,&humidity); //读取温湿度值,赋值给temperature,humidity

printf("temperature:%d,humidity:%d rn",&temperature,&humidity); //通过串口打印出来

}

}


参考视频:

https://www.bilibili.com/video/BV1kx411k7JT?p=62

关键字:STM32 引用地址:STM32获取DHT11温湿度(单总线通信实验笔记)

上一篇:STM32hal库串口中断接收任意字符
下一篇:STM32获取MPU6050数据

推荐阅读最新更新时间:2024-11-11 22:16

ST-LINK和STM32的连接调试
STM32和ST-link仿真器的接口连接,采用SWD模式
[单片机]
STM32串口DMA容易忽视的问题
博主昨天晚上在STM32串口DMA的问题上纠结了好长时间,所以今天上午写篇博客来谈谈我对串口DMA发送的理解→_→今天主要讨论三个问题:1、什么叫串口DMA 请求;2、串口简要复习;3、串口DMA发送流程。 1、什么叫串口DMA 请求(博主用的是战舰STM32开发板) 说这个问题之前先简单回顾DMA的基本特性。先导出原子哥的PPT内容: DMA全称Direct Memory Access,即直接存储器访问。 DMA传输将数据从一个地址空间复制到另一个地址空间。当CPU初始化这个传输动作,传输动作本身是由DMA控制器来实现和完成的。 STM32有两个DMA控制器(DMA2只存在于大容量产品中),DMA1有7个通道
[单片机]
<font color='red'>STM32</font>串口DMA容易忽视的问题
STM32之SPI的思考
选择了与硬件打交道,就得戒骄戒躁,踏踏实实,一步一步的走下去。可能因为一个非常小的问题,就导致你失败。失败不可怕,可怕的是不能静下心来去思考。我在公司第一次调试硬件,spi的通信,是stm32的硬件既有的通信接口。之前用51的io口模拟过i2c的,感觉spi相对来说更简单些,结果调试spi的读写花费了我3天的时间。stm32f0与网上关于stm32f1大量的例程还不一样,刚刚上市半年多,应该是,并且有几项设置是stm32f1没有的,这也正是关键的地方。你直接把他们的程序拿过来用,可能就卡死了,为什么?因为f0多了个fifo设置,fifo不设置,默认应该是half of 32 bits,当你只接收到8个bit时,rxne不会置位,程
[单片机]
STM32 GPIO的十大优越功能综述
前几天Hotpower邀请大家讨论一下GPIO的功能、性能和优缺点(STM32的GPIO很强大~~~),等了几天没见太多人发言,但综合来看提到了3点:1)真双向IO,2)速度快,3)寄存器功能重复。关于第3点有说好,有说多余的,见仁见智。 下面我就在做个抛砖引玉,根据ST手册上的内容,简单地综述一下GPIO的功能: 一、共有8种模式,可以通过编程选择: 1. 浮空输入 2. 带上拉输入 3. 带下拉输入 4. 模拟输入 5. 开漏输出——(此模式可实现hotpower说的真双向IO) 6. 推挽输出 7. 复用功能的推挽输出 8. 复用功能的开漏输出 模式7和模式8需根据具体的复用功能决定。 二、专门的寄存器(GPIOx_
[单片机]
STM32使用FSMC控制NAND flash 例程
近几天开发项目需要用到STM32驱动NAND FLASH,但由于开发板例程以及固件库是用于小页(512B),我要用到的FLASH为1G bit的大页(2K),多走了两天弯路。以下笔记将说明如何将默认固件库修改为大页模式以驱动大容量NAND,并作驱动。 本文硬件:控制器:STM32F103ZET6,存储器:HY27UF081G2A 首先说一下NOR与NAND存储器的区别,此类区别网上有很多,在此仅大致说明: 1、Nor读取速度比NAND稍快 2、Nand写入速度比Nor快很多 3、NAND擦除速度(4ms)远快于Nor(5s) 4、Nor 带有SRAM接口,有足够的地址引脚来寻址,可以很轻松的挂接到CPU地址和数据总线上,对CPU要
[单片机]
STM32实验2:IO输入
端口初始化 #include stm32f10x.h //PA15void KEY_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//使能外设置时钟 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15; //PA15上拉输入 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(GPIOA, &GPIO_InitStructure); }1234567891011
[单片机]
十五年创新路:意法半导体举办首届STM32中国线上技术周
2022年是意法半导体STM32家族问世15周年。在全球疫情阻止人们面对面沟通交流的当下,7月18-22日,意法半导体举办首届暨2022年STM32中国线上技术周,庆祝与生态合作伙伴共同创新的十五载。 在这个为期五天的线上活动中,意法半导体总裁兼首席执行官Jean-Marc Chery、意法半导体执行副总裁、通用微控制器子产品部总经理Ricardo De Sa Earp、意法半导体执行副总裁、中国区市场营销负责人曹志平(Henry Cao) 将分别作主题演讲。同时,意法半导体和合作伙伴带来30多场在线研讨会、100多个展品视频演示。在在线研讨会后设有技术问答环节,参观者将有机会与我们的专家和工程师进行现场互动。 下面,
[单片机]
十五年创新路:意法半导体举办首届<font color='red'>STM32</font>中国线上技术周
stm32的中断与事件
事件:是表示检测有一某件触发事件发生了。 中断:有某个事件发生并产生中断,并跳转到对应的中断处理程序中。 事件可以触发中断,也可以不触发 中断有可能被更优先的中断屏蔽,事件不会 事件本质上就是一个触发信号,是用来触发特定的外设模块或核心本身(唤醒). 事件只是一个触发信号(脉冲),而中断则是一个固定的电平信号
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved