dht11.h
#ifndef __DHT11_H
#define __DHT11_H#include "stm32f1xx_hal.h" // 根據實際芯片型號調整(如stm32f4xx_hal.h)// DHT11數據結構
typedef struct {GPIO_TypeDef *GPIOx; // GPIO端口(如GPIOA)uint16_t GPIO_Pin; // GPIO引腳(如GPIO_PIN_0)uint8_t Temperature; // 溫度(整數部分,°C)uint8_t Humidity; // 濕度(整數部分,%)
} DHT11_TypeDef;// 函數聲明
void DHT11_Init(DHT11_TypeDef *DHT11, GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin);
uint8_t DHT11_ReadData(DHT11_TypeDef *DHT11);// 微秒級延時函數(需用戶實現,或使用下方dht11.c中的模板)
void delay_us(uint16_t us);#endif /* __DHT11_H */
dht11.c
#include "dht11.h"
#include <stdint.h>// 私有函數聲明
static uint8_t DHT11_Start(DHT11_TypeDef *DHT11);
static uint8_t DHT11_ReadByte(DHT11_TypeDef *DHT11);
static void Set_Pin_Output(DHT11_TypeDef *DHT11);
static void Set_Pin_Input(DHT11_TypeDef *DHT11);// 初始化DHT11
void DHT11_Init(DHT11_TypeDef *DHT11, GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin) {DHT11->GPIOx = GPIOx;DHT11->GPIO_Pin = GPIO_Pin;DHT11->Temperature = 0;DHT11->Humidity = 0;
}// 讀取溫濕度數據(返回0成功,1失敗)
uint8_t DHT11_ReadData(DHT11_TypeDef *DHT11) {uint8_t data[5] = {0};if (DHT11_Start(DHT11) != 0) return 1; // 啟動失敗// 讀取40位數據(5字節)for (int i = 0; i < 5; i++) {data[i] = DHT11_ReadByte(DHT11);}// 校驗和驗證if ((data[0] + data[1] + data[2] + data[3]) != data[4]) {return 1; // 校驗失敗}DHT11->Humidity = data[0];DHT11->Temperature = data[2];return 0;
}// 啟動DHT11(發送開始信號)
static uint8_t DHT11_Start(DHT11_TypeDef *DHT11) {Set_Pin_Output(DHT11);// 主機拉低至少18msHAL_GPIO_WritePin(DHT11->GPIOx, DHT11->GPIO_Pin, GPIO_PIN_RESET);delay_us(18000);// 主機拉高20-40μsHAL_GPIO_WritePin(DHT11->GPIOx, DHT11->GPIO_Pin, GPIO_PIN_SET);delay_us(30);// 切換為輸入模式,等待DHT11響應Set_Pin_Input(DHT11);// 檢測DHT11的低電平響應信號(超時檢測)uint32_t timeout = 10000; // 10ms超時while (HAL_GPIO_ReadPin(DHT11->GPIOx, DHT11->GPIO_Pin) == GPIO_PIN_RESET) {if (--timeout == 0) return 1;delay_us(1);}// 檢測DHT11的高電平信號(超時檢測)timeout = 10000;while (HAL_GPIO_ReadPin(DHT11->GPIOx, DHT11->GPIO_Pin) == GPIO_PIN_SET) {if (--timeout == 0) return 1;delay_us(1);}return 0; // 啟動成功
}// 讀取一個字節的數據
static uint8_t DHT11_ReadByte(DHT11_TypeDef *DHT11) {uint8_t byte = 0;for (int i = 0; i < 8; i++) {// 等待低電平結束(數據位開始)while (HAL_GPIO_ReadPin(DHT11->GPIOx, DHT11->GPIO_Pin) == GPIO_PIN_RESET);// 延時40μs判斷高低電平(0: 26-28μs, 1: 70μs)delay_us(40);if (HAL_GPIO_ReadPin(DHT11->GPIOx, DHT11->GPIO_Pin) == GPIO_PIN_SET) {byte |= (1 << (7 - i)); // 高位在前}// 等待高電平結束while (HAL_GPIO_ReadPin(DHT11->GPIOx, DHT11->GPIO_Pin) == GPIO_PIN_SET);}return byte;
}// 設置引腳為輸出模式
static void Set_Pin_Output(DHT11_TypeDef *DHT11) {GPIO_InitTypeDef GPIO_InitStruct = {0};GPIO_InitStruct.Pin = DHT11->GPIO_Pin;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(DHT11->GPIOx, &GPIO_InitStruct);
}// 設置引腳為輸入模式
static void Set_Pin_Input(DHT11_TypeDef *DHT11) {GPIO_InitTypeDef GPIO_InitStruct = {0};GPIO_InitStruct.Pin = DHT11->GPIO_Pin;GPIO_InitStruct.Mode = GPIO_MODE_INPUT;GPIO_InitStruct.Pull = GPIO_PULLUP;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(DHT11->GPIOx, &GPIO_InitStruct);
}// 微秒級延時函數(需用戶根據實際定時器實現)
__weak void delay_us(uint16_t us) {/* 默認實現(需替換為您的實際延時函數) */for (uint16_t i = 0; i < us; i++) {for (uint16_t j = 0; j < 10; j++) { // 粗略延時(需校準)__NOP();}}
}
使用教程
#include "dht11.h"DHT11_TypeDef myDHT11;DHT11_Init(&myDHT11, GPIOA, GPIO_PIN_1);if (DHT11_ReadData(&myDHT11) == 0){//溫度處理 + LED1控制if(myDHT11.Temperature>TT){HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_SET);//LED1motorIndex=3;//HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_SET);OLED_ShowString(112, 16, "H", OLED_8X16);//溫度過高顯示"H"}else{HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET);//LED1motorIndex=0;//HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_RESET);OLED_ShowString(112, 16, "L", OLED_8X16);//溫度正常顯示"L"}sprintf(str, "溫度:%d.0℃", myDHT11.Temperature);OLED_ShowString(1, 16, str, OLED_8X16);//濕度處理if(myDHT11.Humidity>HT){HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_SET);//LED2OLED_ShowString(112, 32, "H", OLED_8X16);//濕度過高顯示"H"}else{HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_RESET);OLED_ShowString(112, 32, "L", OLED_8X16);//濕度正常顯示"L"}sprintf(str, "濕度:%dRH%%", myDHT11.Humidity);OLED_ShowString(1, 32, str, OLED_8X16);}