Skip to content

Overview

The DHT11 is the classic entry-level temperature and humidity sensor: temperature in °C, humidity in %RH (relative humidity percentage — "how much water vapor the air holds"). It communicates over just one data wire (this one-wire-carries-both-data-and-clock style is called a single-wire bus): range 0~50°C (accuracy ±2°C), humidity 20~90%RH (accuracy ±5%RH). This tutorial uses the Ai-WB2 to read the DHT11's temperature and humidity, printing them on the serial in real time, and walks through the full flow of wiring → coding → building → flashing (writing the compiled program into the board's chip) → running and verification.

In plain words: the single-wire bus is like "talking over one wire" — the controller and the data line agree: first pull low then high to tell the sensor "I want to ask", and the sensor answers with 40 bits of data (16 bits humidity + 16 bits temperature + checksum) encoded as high-level pulses of different lengths. The driver used in this tutorial parses those 40 bits and hands you two numbers: temperature and humidity.

This tutorial is based on the official Ai-Thinker SDK (Ai-Thinker-Open/Ai-Thinker-WB2, version release_bl_iot_sdk_1.6.40) example applications/iot-solution/demo_dht11; the code can be found directly in the local SDK.

🎯Page GoalRead the DHT11 temperature and humidity over the single-wire bus, print temperature and humidity on the serial every 500 ms, and understand single-wire communication and multi-file driver project structure.
🧰Prerequisites① An Ai-WB2 development board + a DHT11 temperature and humidity sensor module ② Development environment set up per [SDK Installation](../sdk/sdk_intro), and [GPIO Output (LED)](../basic/gpio_led) done.
🔗RelatedAnother single-wire temperature sensor: [DS18B20 Temperature Sensor](./ds18b20); an I2C temperature/humidity sensor: [SHT30 Temperature and Humidity Sensor](./sht3x).

Hardware Wiring

Wire per the official example (see the SDK’s applications/iot-solution/demo_dht11/README.md), using dupont wires (jumper wires with pins at both ends):

Ai-WB2 Pin DHT11 Pin
IO11 DATA
3V3 VCC
GND GND

💡 The DHT11 is a single-wire device — VCC to 3.3V (the DHT11 accepts 3.3V~5V supply; this tutorial uses 3.3V throughout). ⚠️ The official README says IO4, but this version’s official driver actually uses GPIO11 (see .port = 11 in demo_dht11/driver_dht11_interface_bl602.c) — wire to IO11 per the code; the wrong pin reads nothing. 💡 With long dupont wires (>20cm), add a 5.1kΩ pull-up resistor between DATA and 3V3 (a small resistor holding the line high by default) for more stable communication.

Enter the Example Project

This tutorial directly uses the demo_dht11 example project shipped with the official SDK; open a terminal and enter it:

cd ~/Ai-Thinker-WB2/applications/iot-solution/demo_dht11

Note: cd is the “change directory” command — entering the DHT11 example project directory; all subsequent make build and make flash flash commands must run in this directory first.

This is a multi-file project: main program + the official ported DHT11 driver library (from the open-source LibDriver, wrapping the single-wire timing):

File Purpose
demo_dht11/main.c Main program source, the main file this tutorial looks at
demo_dht11/driver_dht11_basic.c/h Basic read/write interface (init, read temperature/humidity), calling the low-level timing driver
demo_dht11/driver_dht11.c/h Single-wire timing core (40-bit send/receive, checksum)
demo_dht11/driver_dht11_interface_bl602.c Platform adaptation layer: hooks the driver to the WB2’s GPIO11
Makefile Build entry, usually no changes needed
Write the Code

Open demo_dht11/main.c — the complete code for this step has been moved to the end of this page:

📜 Full Code — in the “Full Code” section below, collapsed by default — click to expand, identical to the official example (applications/iot-solution/demo_dht11/demo_dht11/main.c).

Code highlights:

Code Purpose
dht11_basic_init() Initializes the DHT11 driver (configures the single-wire pin for send/receive); without it the driver can’t work
dht11_basic_read(&temperature, &humidity) Starts a single-wire communication to read temperature/humidity: temperature is float (°C), humidity is uint8_t (integer %); a failed read returns 1
blog_info("%.2f C degree\t%u%%", ...) Prints temperature and humidity on the serial; no print = no visible result
vTaskDelay(pdMS_TO_TICKS(500)) Samples every 500 ms; too fast and the DHT11 hasn’t refreshed its internal data, so you read stale unchanged values
Build the Project

Build in the project directory:

make -j8

Note: make is the “build” command, turning code into firmware (the program file) the board can run; -j8 builds with 8 parallel CPU cores, faster.

On success a firmware build_out/demo_dht11.bin is generated.

⚠️ If it reports riscv64-unknown-elf-gcc: command not found, the toolchain permissions aren’t configured — run cd toolchain/riscv/Linux && . chmod755.sh first, then rebuild.

Flash the Firmware

Keep the board connected via USB, confirm the serial device (usually /dev/ttyUSB0 on Linux), and flash:

make flash p=/dev/ttyUSB0 b=921600

Note: make flash is the “flash” command, writing the compiled firmware into the board’s chip. After p= comes the serial device (change it to your computer’s actual one — check with ls /dev/ttyUSB*), b= is the flash baud rate (transfer speed).

⏳ During flashing, press and hold the EN button on the board when prompted to enter download mode (some boards enter automatically); wait for the progress bar to complete — that means the flash succeeded. For flashing on Windows, see Windows Quick Start.

Run and Verify

After flashing, the board automatically restarts and runs; open the serial assistant (baud rate 921600 — the baud rate is the serial transfer speed, both ends must be set the same) and temperature/humidity prints every 500 ms:

26.00 C degree	45%
26.00 C degree	46%
...

Breathe on the sensor — the humidity value should rise; pinch the sensor with your hand — the temperature value should slowly climb.

Seeing the serial print temperature/humidity every 500 ms means success; if nothing prints or the values are fixed (e.g. always 0), it hasn’t succeeded yet — check the FAQ at the end.

💡 Watch the IO11 waveform with a logic analyzer to see the single-wire start signal and the 40 data pulses (see the official example’s img/logic_analyzer.jpg).


API Summary for This Tutorial

dht11_basic_init()

Initializes the DHT11 driver: registers the platform interface functions (GPIO read/write, microsecond delay, interrupt disable) and completes the sensor self-check.

Parameters:

  • None

Return: 0 on success; 1 on failure (e.g. sensor init self-check failed). Driver implementation in demo_dht11/driver_dht11_basic.c

dht11_basic_read(temperature, humidity)

Performs one measurement per the DHT11 single-wire timing and reads the 40-bit data (8-bit humidity integer + 8-bit humidity decimal + 8-bit temperature integer + 8-bit temperature decimal + 8-bit checksum), parsing out temperature and humidity.

Parameters:

  • temperature: float * output pointer, receives the temperature (°C), required
  • humidity: uint8_t * output pointer, receives the humidity (%RH, integer), required

Return: 0 on success; 1 on failure (read failure or checksum error). Driver implementation in demo_dht11/driver_dht11_basic.c

blog_info(fmt, ...)

Prints an INFO-level log (UART0, subject to level filtering); this tutorial prints temperature/humidity with it.

Parameters:

  • fmt: format string, same usage as printf, required
  • ...: variadic args matching the fmt placeholders; can be omitted

Return: none

vTaskDelay(ms)

Suspends the current task for the given milliseconds, yielding the CPU to other tasks.

Parameters:

  • ms: delay in milliseconds, values: any non-negative integer (internally converted to system ticks via pdMS_TO_TICKS)

Return: none


Full Code

Below is the complete demo_dht11/main.c source, identical to the official example (applications/iot-solution/demo_dht11/demo_dht11/main.c). This is a multi-file project; the rest of the driver files (driver_dht11*.c/h, driver_dht11_interface_bl602.c) live in the same directory, no changes needed:

📜 Click to expand the full demo_dht11/main.c code
c
#include <stdio.h>

#include <FreeRTOS.h>
#include <task.h>
#include <blog.h>
#include "driver_dht11_basic.h"

int main(void)
{
    dht11_basic_init();

    float temperature;
    uint8_t humidity;
    for (;;) {
        dht11_basic_read(&temperature, &humidity);
        blog_info("%.2f C degree\t%u%%", temperature, humidity);
        vTaskDelay(pdMS_TO_TICKS(500));
    }

    return 0;
}

FAQ & Troubleshooting

⚠️ The serial never prints (can't read)
Cause: DATA isn't on IO11 (the official README's IO4 is misleading), poor dupont wire contact, or a damaged sensor
Fix: confirm DATA is on IO11 (per the driver code's .port = 11); re-seat the dupont wires; try another DHT11

⚠️ Values always 0 or garbled
Cause: insufficient VCC supply, no common ground between the board and module (GND not connected), or long-wire interference causing checksum failure
Fix: confirm VCC to 3V3 and GND to GND (common ground = the two devices' grounds must be joined, otherwise voltage has no reference point); with long wires add a 5.1kΩ pull-up between DATA and 3V3

⚠️ Temperature and humidity values fixed
Cause: read interval too short — the DHT11's internal measurement data hasn't refreshed yet (datasheet recommends ≥1 second between reads)
Fix: this example's 500 ms interval usually works; if the values stay unchanged for a long time, raise vTaskDelay to 1000 and retry

⚠️ Serial device not found or no permission
Cause: on Linux /dev/ttyUSB0 doesn't exist or permission denied; on Windows the USB-to-serial driver isn't installed
Fix: on Linux check with ls /dev/ttyUSB*; if permission denied run sudo usermod -aG dialout $USER and log back in; on Windows install the driver in Device Manager and confirm the COM port

⚠️ Flashing keeps waiting, progress bar doesn't move
Cause: download mode wasn't entered, or the cable only charges and can't transfer data
Fix: press and hold EN during flashing to enter download mode as prompted; try a Type-C data-capable cable

⚠️ make reports Makefile not found
Cause: the build command ran in the wrong directory (must be inside the example project directory)
Fix: run cd ~/Ai-Thinker-WB2/applications/iot-solution/demo_dht11 first, then make -j8

Self-Check

The serial prints temperature/humidity every 500 ms; breathing raises the humidity, pinching raises the temperature — the DHT11 measurement is verified.

Released under the MIT License. Build Time 2026-09-11 14:52:23