• 正文
  • 相关推荐
申请入驻 产业图谱

【传感器】STM32驱动DHT11读取数据

04/09 14:37
431
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

一、说明

HAL库,DeepSeek写的代码,一遍过。

二、源码

(1)DHT11.c
// dht11.c
#include "dht11.h"

#define DHT11_TIMEOUT 10000

// 微秒级延时函数(72MHz主频校准)
void DHT11_DelayUs(uint16_t us) 
{
    uint32_t delay = us * (SystemCoreClock / 8000000); // 72MHz: us*9
    while(delay--) {
        __NOP();
    }
}

static void Set_Pin_Output(DHT11_HandleTypeDef* hdht11) {
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  GPIO_InitStruct.Pin = hdht11->GPIO_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(hdht11->GPIOx, &GPIO_InitStruct);
}

static void Set_Pin_Input(DHT11_HandleTypeDef* hdht11) {
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  GPIO_InitStruct.Pin = hdht11->GPIO_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  HAL_GPIO_Init(hdht11->GPIOx, &GPIO_InitStruct);
}

static uint8_t DHT11_CheckResponse(DHT11_HandleTypeDef* hdht11) {
  uint32_t timeout = 0;
  
  Set_Pin_Input(hdht11);
  
  // 等待80us低电平
  while(HAL_GPIO_ReadPin(hdht11->GPIOx, hdht11->GPIO_Pin) == GPIO_PIN_RESET) {
    if(timeout++ > DHT11_TIMEOUT) return DHT11_ERROR_TIMEOUT;
  }
  
  timeout = 0;
  // 等待80us高电平
  while(HAL_GPIO_ReadPin(hdht11->GPIOx, hdht11->GPIO_Pin) == GPIO_PIN_SET) {
    if(timeout++ > DHT11_TIMEOUT) return DHT11_ERROR_TIMEOUT;
  }
  
  return DHT11_OK;
}

static uint8_t DHT11_ReadByte(DHT11_HandleTypeDef* hdht11) {
  uint8_t data = 0;
  
  for(int i=0; i<8; i++) {
    uint32_t timeout = 0;
    while(HAL_GPIO_ReadPin(hdht11->GPIOx, hdht11->GPIO_Pin) == GPIO_PIN_RESET) {
      if(timeout++ > DHT11_TIMEOUT) return 0;
    }
    
    DHT11_DelayUs(40); // 精确40us延时
    
    if(HAL_GPIO_ReadPin(hdht11->GPIOx, hdht11->GPIO_Pin) == GPIO_PIN_SET) {
      data |= (1 << (7-i));
      timeout = 0;
      while(HAL_GPIO_ReadPin(hdht11->GPIOx, hdht11->GPIO_Pin) == GPIO_PIN_SET) {
        if(timeout++ > DHT11_TIMEOUT) return 0;
      }
    }
  }
  return data;
}

void DHT11_Init(DHT11_HandleTypeDef* hdht11, GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) {
  hdht11->GPIOx = GPIOx;
  hdht11->GPIO_Pin = GPIO_Pin;
  hdht11->temperature = 0;
  hdht11->humidity = 0;
  Set_Pin_Output(hdht11);
  HAL_GPIO_WritePin(hdht11->GPIOx, hdht11->GPIO_Pin, GPIO_PIN_SET);
}

uint8_t DHT11_Read(DHT11_HandleTypeDef* hdht11) {
  uint8_t data[5] = {0};
  
  // 发送起始信号
  Set_Pin_Output(hdht11);
  HAL_GPIO_WritePin(hdht11->GPIOx, hdht11->GPIO_Pin, GPIO_PIN_RESET);
  HAL_Delay(18);  // 18ms低电平
  HAL_GPIO_WritePin(hdht11->GPIOx, hdht11->GPIO_Pin, GPIO_PIN_SET);
  DHT11_DelayUs(30);  // 主机拉高30us
  
  // 检测DHT11响应
  if(DHT11_CheckResponse(hdht11) != DHT11_OK) {
    return DHT11_ERROR_TIMEOUT;
  }
  
  // 读取40位数据
  for(int i=0; i<5; i++) {
    data[i] = DHT11_ReadByte(hdht11);
    if(data[i] == 0) return DHT11_ERROR_TIMEOUT;
  }
  
  // 校验和验证
  if(data[4] != (data[0] + data[1] + data[2] + data[3])) {
    return DHT11_ERROR_CHECKSUM;
  }
  
  hdht11->humidity = data[0];
  hdht11->temperature = data[2];
  
  return DHT11_OK;
}
(2)DHT11.h
// dht11.h
#ifndef __DHT11_H
#define __DHT11_H

#ifdef __cplusplus
 extern "C" {
#endif

#include "stm32f1xx_hal.h"

#define DHT11_OK          0
#define DHT11_ERROR_CHECKSUM  1
#define DHT11_ERROR_TIMEOUT   2

typedef struct {
  GPIO_TypeDef* GPIOx;
  uint16_t GPIO_Pin;
  uint8_t temperature;
  uint8_t humidity;
} DHT11_HandleTypeDef;

void DHT11_Init(DHT11_HandleTypeDef* hdht11, GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
uint8_t DHT11_Read(DHT11_HandleTypeDef* hdht11);
void DHT11_DelayUs(uint16_t us);

#ifdef __cplusplus
}
#endif

#endif /* __DHT11_H */
(3)main.c

#include "main.h"
#include "adc.h"
#include "spi.h"
#include "usart.h"
#include "gpio.h"

#include "st7735.h"
#include "dht11.h"

char numStr[3][20] ={0};
DHT11_HandleTypeDef hdht11;

int main(void)
{
  HAL_Init();
  SystemClock_Config();

  MX_GPIO_Init();
  MX_ADC1_Init();
  MX_SPI1_Init();
  MX_USART1_UART_Init();
	DHT11_Init(&hdht11, GPIOA, GPIO_PIN_3);
	ST7735_Init();

  while (1)
  {
		if(DHT11_Read(&hdht11) == DHT11_OK) {
//      printf("Temp: %dC, Humi: %d%%rn", 
//             hdht11.temperature, hdht11.humidity);
    }
		uint16_t adcValueChannel1 = Read_ADC_Value(1);  // 读取通道 1 的 ADC 值
        uint16_t adcValueChannel2 = Read_ADC_Value(2);  // 读取通道 2 的 ADC 值
		sprintf(numStr[0], "%d", hdht11.temperature); 
		sprintf(numStr[1], "%d", hdht11.humidity); 
		ST7735_DrawString(0, 40, numStr[0], ST7735_MAGENTA , ST7735_BLACK, &Font_11x18);
		ST7735_DrawString(0, 80, numStr[1], ST7735_MAGENTA, ST7735_BLACK, &Font_11x18);
		HAL_Delay(2000);
  }
  /* USER CODE END 3 */
}

三、注意事项

微妙延时函数,根据自己主频和晶振更改参数:

// 微秒级延时函数(72MHz主频校准)
void DHT11_DelayUs(uint16_t us) 
{
    uint32_t delay = us * (SystemCoreClock / 8000000); // 72MHz: us*9
    while(delay--) {
        __NOP();
    }
}

相关推荐