To interface a DHT11 temperature and humidity sensor with an STM32 using HAL (Hardware Abstraction Layer), you need to implement 1-wire timing using a GPIO pin and precise microsecond delays.
Overview
- MCU: STM32 (any series, e.g., STM32F103 or STM32F407)
- Sensor: DHT11
- Interface: Single-wire digital (requires bidirectional GPIO)
- Communication: Start signal from MCU, response and data (40 bits) from DHT11
- Development Tool: STM32CubeMX + Keil / STM32CubeIDE
Step-by-Step Implementation
1. Hardware Connection
2. Microsecond Delay Function
STM32 HAL does not provide a built-in HAL_Delay_us(). You can use a hardware timer (e.g., TIM2) to create microsecond delay.
delay_us.c
c
#include "stm32f1xx_hal.h"
extern TIM_HandleTypeDef htim2;
void delay_us(uint16_t us) {
__HAL_TIM_SET_COUNTER(&htim2, 0); // reset the counter
HAL_TIM_Base_Start(&htim2);
while (__HAL_TIM_GET_COUNTER(&htim2) < us);
HAL_TIM_Base_Stop(&htim2);
}
Use CubeMX to configure TIM2 as a basic timer with 1 MHz clock (1 tick = 1 µs).
3. GPIO Helper Macros for Bidirectional I/O
c
#define DHT11_PORT GPIOA
#define DHT11_PIN GPIO_PIN_1
void DHT11_SetPinOutput(void) {
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = DHT11_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(DHT11_PORT, &GPIO_InitStruct);
}
void DHT11_SetPinInput(void) {
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = DHT11_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(DHT11_PORT, &GPIO_InitStruct);
}
4. DHT11 Protocol Implementation
dht11.c
c
#include "dht11.h"
#include "delay_us.h"
uint8_t Rh_byte1, Rh_byte2, Temp_byte1, Temp_byte2;
uint16_t SUM;
uint8_t DHT11_Data[5];
uint8_t DHT11_Start(void) {
DHT11_SetPinOutput(); // Set as output
HAL_GPIO_WritePin(DHT11_PORT, DHT11_PIN, GPIO_PIN_RESET);
HAL_Delay(18); // At least 18ms
HAL_GPIO_WritePin(DHT11_PORT, DHT11_PIN, GPIO_PIN_SET);
delay_us(20); // Wait 20–40 µs
DHT11_SetPinInput(); // Set as input
delay_us(80);
if (!(HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN))) {
delay_us(80);
if ((HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN))) return 1;
}
return 0;
}
uint8_t DHT11_ReadBit(void) {
while (!HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN)); // Wait for high
delay_us(40); // After 40us, read the pin
if (HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN))
return 1;
else
return 0;
}
uint8_t DHT11_ReadByte(void) {
uint8_t i, byte = 0;
for (i = 0; i < 8; i++) {
byte <<= 1;
byte |= DHT11_ReadBit();
while (HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN)); // Wait for low
}
return byte;
}
uint8_t DHT11_ReadData(uint8_t *temp, uint8_t *humidity) {
if (DHT11_Start()) {
Rh_byte1 = DHT11_ReadByte();
Rh_byte2 = DHT11_ReadByte();
Temp_byte1 = DHT11_ReadByte();
Temp_byte2 = DHT11_ReadByte();
SUM = DHT11_ReadByte();
if (SUM == (Rh_byte1 + Rh_byte2 + Temp_byte1 + Temp_byte2)) {
*humidity = Rh_byte1;
*temp = Temp_byte1;
return 1;
}
}
return 0;
}
5. Usage in main.c
c
#include "dht11.h"
uint8_t temperature, humidity;
int main(void) {
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_TIM2_Init(); // Ensure timer is initialized
while (1) {
if (DHT11_ReadData(&temperature, &humidity)) {
// Use temperature and humidity
} else {
// Error handling
}
HAL_Delay(2000); // DHT11 reads every 2 seconds
}
}
Summary of Required Files