Data Packet Structure
The DHT11 sensor uses a single-wire communication protocol. Each data transmission consists of a 5-byte packet organized as follows:
- Byte 0: Integer part of humidity
- Byte 1: Fractional part of humidity
- Byte 2: Integer part of temperature
- Byte 3: Fractional part of temperature
- Byte 4: Checksum byte
The sensor transmits data most significant bit first.
The humidity and temperature values are calculated as:
Humidity = buf[0] (integer)
Temperature = buf[2] (integer)
Checksum = buf[0] + buf[1] + buf[2] + buf[3]
Communication Timing Sequence
The complete communication cycle requires approximately 3ms.
Step 1: Master Start Signal
The MCU pulls the data line LOW for atleast 18ms, then releases it HIGH for 20-40μs.
Step 2: DHT11 Acknowledgment
The sensor responds by pulling the data line LOW for 40-50μs.
Step 3: DHT11 Ready Signal
After acknowledgment, the sensor pulls the data line HIGH for 40-50μs before transmitting data.
Data Bit Encoding
The sensor encodes each bit using pulse width modulation:
| Bit Vallue | Low Duration | High Duration |
|---|---|---|
| 0 | 12-14μs | 26-28μs |
| 1 | 12-14μs | 116-118μs |
The initial low pulse signals the start of each bit transmission. The subsequent high pulse duration determines whether the bit is 0 or 1.
Implementation
DHT11.h
#ifndef __DHT11_H__
#define __DHT11_H__
#include "sys.h"
#define DHT11_PIN GPIO_Pin_11
#define DHT11_PORT GPIOG
#define DHT11_OUT_HIGH() GPIO_SetBits(DHT11_PORT, DHT11_PIN)
#define DHT11_OUT_LOW() GPIO_ResetBits(DHT11_PORT, DHT11_PIN)
#define DHT11_READ() GPIO_ReadInputDataBit(DHT11_PORT, DHT11_PIN)
void DHT11_Init(void);
u8 DHT11_Read_Data(u8 *temp, u8 *humi);
#endif
DHT11.c
#include "dht11.h"
#include "delay.h"
// Configure GPIO as output mode
static void DHT11_GPIO_OUT(void) {
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG, ENABLE);
GPIO_InitStruct.GPIO_Pin = DHT11_PIN;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(DHT11_PORT, &GPIO_InitStruct);
}
// Configure GPIO as input mode
static void DHT11_GPIO_IN(void) {
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Pin = DHT11_PIN;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(DHT11_PORT, &GPIO_InitStruct);
}
// Send reset pulse to DHT11
static void DHT11_Reset(void) {
DHT11_GPIO_OUT();
DHT11_OUT_LOW();
delay_ms(20);
DHT11_OUT_HIGH();
delay_us(30);
}
// Check sensor acknowledgment
// Return 0: acknowledgment received
// Return 1: no response
static u8 DHT11_Check(void) {
u8 timeout = 0;
DHT11_GPIO_IN();
while (DHT11_READ() && timeout < 100) {
timeout++;
delay_us(1);
}
if (timeout >= 100) return 1;
timeout = 0;
while (!DHT11_READ() && timeout < 100) {
timeout++;
delay_us(1);
}
if (timeout >= 100) return 1;
return 0;
}
// Read single bit from DHT11
static u8 DHT11_Read_Bit(void) {
u8 timeout = 0;
while (DHT11_READ() && timeout < 100) {
timeout++;
delay_us(1);
}
timeout = 0;
while (!DHT11_READ() && timeout < 100) {
timeout++;
delay_us(1);
}
delay_us(40);
return DHT11_READ() ? 1 : 0;
}
// Read single byte from DHT11
static u8 DHT11_Read_Byte(void) {
u8 i;
u8 byte = 0;
for (i = 0; i < 8; i++) {
byte <<= 1;
byte |= DHT11_Read_Bit();
}
return byte;
}
// Initialize DHT11 sensor
void DHT11_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG, ENABLE);
GPIO_InitStruct.GPIO_Pin = DHT11_PIN;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(DHT11_PORT, &GPIO_InitStruct);
GPIO_SetBits(DHT11_PORT, DHT11_PIN);
DHT11_Reset();
}
// Read temperature and humidity from DHT11
// Return 0: success
// Return 1: failure
u8 DHT11_Read_Data(u8 *temp, u8 *humi) {
u8 buffer[5];
u8 i;
DHT11_Reset();
if (DHT11_Check() == 0) {
for (i = 0; i < 5; i++) {
buffer[i] = DHT11_Read_Byte();
}
if ((buffer[0] + buffer[1] + buffer[2] + buffer[3]) == buffer[4]) {
*humi = buffer[0];
*temp = buffer[2];
return 0;
}
}
return 1;
}
main.c
#include "sys.h"
#include "usart.h"
#include "delay.h"
#include "led.h"
#include "lcd.h"
#include "dht11.h"
int main(void) {
u8 counter = 0;
u8 temperature = 0;
u8 humidity = 0;
delay_init();
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
uart_init(115200);
LED_Init();
LCD_Init();
POINT_COLOR = RED;
while (DHT11_Read_Data(&temperature, &humidity)) {
LCD_ShowString(30, 130, 200, 16, 16, "DHT11 Error");
delay_ms(200);
LCD_Fill(30, 130, 239, 146, WHITE);
delay_ms(200);
}
LCD_ShowString(30, 130, 200, 16, 16, "DHT11 OK");
POINT_COLOR = BLUE;
LCD_ShowString(30, 150, 200, 16, 16, "Temp: C");
LCD_ShowString(30, 170, 200, 16, 16, "Humi: %");
delay_ms(200);
while (1) {
if (counter % 10 == 0) {
DHT11_Read_Data(&temperature, &humidity);
LCD_ShowNum(30 + 40, 150, temperature, 2, 16);
LCD_ShowNum(30 + 40, 170, humidity, 2, 16);
}
delay_ms(10);
counter++;
if (counter == 20) {
counter = 0;
LED0 = !LED0;
}
}
}
Key Implementation Notes
-
GPIO Configuration: The data pin must be switched between output mode (for sending reset signal) and input mode (for receiving data).
-
Timing Critical: The delay between acknowledgment detection and bit reading (40μs) is crucial for sampling the data at the correct moment.
-
Checksum Verification: Always verify the checksum byte before using the temperature and humidity values.
-
Polling Interval: Allow at least 2 seconds between readings to ensure the sensor has sufficient time to complete its measurement cycle.