51xlf 发表于 2025-7-23 13:40

【APM32E030R Micro-EVB开发板评测】读取DHT11

DHT11是一款集温度和湿度测量于一体的数字传感器,采用单总线通信协议,具有体积小、功耗低、性价比高等特点‌。以下是其主要特性:


DHT11模块

DHT11的连接方式


这里我们使用的时PB1引脚。


这里使用的是定时器3实现的定时功能
   RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_TMR3);
       
        TMR_TimeBase_T baseConfig;
          baseConfig.div = 72-1;
    baseConfig.period = 0xFFFF;
    baseConfig.clockDivision = TMR_CKD_DIV1;
    baseConfig.counterMode = TMR_COUNTER_MODE_UP;
    TMR_ConfigTimeBase(TMR3, &baseConfig);
    TMR_EnableAUTOReload(TMR3);
                TMR_Enable(TMR3);1us定时的实现
TMR3->CNT=0;
        TMR_Enable(TMR3);
        while(TMR3->CNT < nus);//计数频率6MHz,6次即为1us
        TMR_Disable(TMR3);DHT11的读写代码
dht11.c
#include "dht11.h"
#include "delay.h"
void Delay_us(uint16_t time)
{   
delay_us(time);
}

void Delay_ms(uint16_t time)
{   
delay_ms(time);
}

void DHT11_IO_OUT (void){ //温湿度模块输出函数
    GPIO_Config_TconfigStruct;
    configStruct.pin = DHT11_IO; //选择端口号(0~15或all)                        
    configStruct.mode = GPIO_MODE_OUT; //推挽输出      
    configStruct.speed = GPIO_SPEED_50MHz; //设置IO接口速度(2/10/50MHz)   
    GPIO_Config(DHT11_PORT, &configStruct);
}

void DHT11_IO_IN (void){ //温湿度模块输入函数       
          GPIO_Config_TconfigStruct;
    configStruct.pin = DHT11_IO; //选择端口号(0~15或all)                        
    configStruct.mode = GPIO_MODE_IN; //浮空输入   
          configStruct.speed = GPIO_SPEED_50MHz; //设置IO接口速度(2/10/50MHz)   
    GPIO_Config(DHT11_PORT, &configStruct);
}

void DHT11_RST (void){                                                 //DHT11端口复位,发出起始信号(IO发送)
        DHT11_IO_OUT();                                                        //端口为输出
        DHT11_DQ_OUT_0;         //使总线为低电平
        Delay_ms(20);                                                         //拉低至少18ms                                               
        DHT11_DQ_OUT_1;                 //使总线为高电平                                                       
        Delay_us(30);                                                         //主机拉高20~40us
}

uint8_t DHT11_Check(void){         //等待DHT11回应,返回1:未检测到DHT11,返回0:成功(IO接收)          
    uint8_t retry=0;                        //定义临时变量
    DHT11_IO_IN();                //IO到输入状态       
//GPIO端口输入时,配置为上拉输入或者浮空输入,因为外接上拉电阻,所以默认为高电平
//有负信号输入,GPIO端口为1,当GPIO端口为1且retry小于100,retry自加,否则跳出循环执行下一步
        while ((DHT11_DQ_IN == 1) && retry<100)        //DHT11会拉低40~80us
        {
                retry++;
      Delay_us(1);
    }
    if(retry>=100)return 1;        
        else retry=0;
//DHT11发来高电平信号,GPIO端口为0,当GPIO端口为0且retry小于100,retry自加,否则跳出循环执行下一步
    while ((DHT11_DQ_IN == 0) && retry<100)//DHT11拉低后会再次拉高40~80us
        {
      retry++;
      Delay_us(1);
    }
    if(retry>=100)return 1;          
    return 0;
}

uint8_t DHT11_Init (void){        //DHT11初始化
        RCM_EnableAPB2PeriphClock(DHT11_RCC);        //开始DHT11的时钟
        DHT11_RST();                                                                //DHT11端口复位,发出起始信号
        return DHT11_Check();                                                 //等待DHT11回应
}

//从DHT11读取一个位
//返回值:1/0
uint8_t DHT11_Read_Bit(void)
{
    uint8_t retry = 0;
    while((DHT11_DQ_IN == 1) && retry < 100) //等待变为低电平
    {
      retry++;
      Delay_us(1);
    }
    retry = 0;
    while((DHT11_DQ_IN == 0) && retry < 100) //等待变高电平
    {
      retry++;
      Delay_us(1);
    }
    Delay_us(40);//等待40us
    if(GPIO_ReadInputBit(DHT11_PORT,DHT11_IO) == 1)       //用于判断高低电平,即数据1或0
      return 1;
    else
      return 0;
}

//从DHT11读取一个字节
//返回值:读到的数据
uint8_t DHT11_Read_Byte(void)
{
    uint8_t i, dat;
    dat = 0;
    for (i = 0; i < 8; i++)
    {
      dat <<= 1;                                        //左移运算符,dat左移1位
      dat |= DHT11_Read_Bit();        //"|"表示按位或等于
    }
    return dat;
}

//从DHT11读取一次数据
//temp:温度值(范围:0~50°)
//humi:湿度值(范围:20%~90%)
//返回值:0,正常;1,读取失败
uint8_t DHT11_Read_Data(uint8_t *temp, uint8_t *humi)
{
    uint8_t buf;
    uint8_t i;
    DHT11_RST();                                                //DHT11端口复位,发出起始信号
    if(DHT11_Check() == 0)                                //等待DHT11回应,0为成功回应
    {
      for(i = 0; i < 5; i++)                         //读取40位数据
      {
            buf = DHT11_Read_Byte();        //读出数据
      }
      if((buf + buf + buf + buf) == buf)        //数据校验
      {
            *humi = buf;                                //将湿度值放入指针humi
            *temp = buf;                                //将温度值放入指针temp
      }
    }
    else return 1;
    return 0;
}


dht11.h
#ifndef __DHT11_H
#define __DHT11_H
#include "APM32E030_gpio.h"
#include "APM32E030_rcm.h"

#define DHT11_RCC          RCM_AHB_PERIPH_GPIOB                //开启引脚RCC,根据具体情况修改
#define DHT11_PORT                         GPIOB                                                                //定义端口,根据具体情况修改
#define DHT11_IO                                 GPIO_PIN_1                                        //定义IO口,根据具体情况修改

//设置驱动IO端口
#define DHT11_DQ_OUT_1 GPIO_SetBit(DHT11_PORT, DHT11_IO )
#define DHT11_DQ_OUT_0 GPIO_ClearBit(DHT11_PORT, DHT11_IO )
#define DHT11_DQ_IN GPIO_ReadInputBit(DHT11_PORT,DHT11_IO)
void DHT11_IO_OUT (void);                                                                //设置IO口为输出模式
void DHT11_IO_IN (void);                                                                //设置IO口为输入模式
void DHT11_RST (void);                                                                        //复位DHT11

uint8_t DHT11_Check (void);                                                                        //检查DHT11是否正常
uint8_t DHT11_Read_Bit (void);                                                         //读取一位数据
uint8_t DHT11_Read_Byte (void);                                                        //读取一个字节
uint8_t DHT11_Init (void);                                                                                //DHT11初始化
uint8_t DHT11_Read_Data (uint8_t *temp, uint8_t *humi);                 // DHT11读取数据

#endif


main函数
DHT11_Read_Data(&temperature,&humidity);        //读取温湿度值
            sprintf(s_temp,"温度:%02d'C   ",temperature );
            OLED_ShowStringCN(0,16,(unsigned char*)s_temp,1);// 显示温度
                             sprintf(s_temp,"湿度:%02d%%    ",humidity);
            OLED_ShowStringCN(0,32,(unsigned char*)s_temp,1);// 显示湿度
      OLED_Refresh();最终实现的效果


ShadowDance 发表于 2025-7-23 14:44

这个单总线通讯,是不是可以考虑使用SPI的通讯方式啊

抒情黎明 发表于 2025-7-30 17:33

纯延时处理的话,如果遇到中断,数据传输的稳定性还能保证吗?

魔法森林精灵 发表于 2025-7-31 08:08

这个评测很详细,特别是DHT11的连接和代码实现部分,对于初学者来说很有帮助。
页: [1]
查看完整版本: 【APM32E030R Micro-EVB开发板评测】读取DHT11