Hardware-accelerated DHT22 library for the Raspberry Pi Pico / Pico W.
The entire DHT22 protocol — wake-up pulse, sensor handshake, and 40-bit data capture — is offloaded to the RP2040's PIO coprocessor. Fully non-blocking, zero bit-banging, zero delayMicroseconds(), zero interrupts.
- PIO-accelerated — wake-up, handshake, and bit capture are 100% hardware
- Non-blocking / async — request a reading, poll
update(), retrieve when ready; the CPU is never stalled - Wi-Fi safe — dynamic PIO allocation prevents collisions with the CYW43 driver on Pico W
- RAII resource management — PIO state machines and instruction memory are automatically released on destruction
- Runtime pin switching — multiplex multiple sensors through a single PIO instance via
setPin() - Checksum validation — every reading is integrity-checked
- Negative temperature support — correctly handles the DHT22 sign bit
- Structured error states — state machine with IDLE, WAITING_PIO, DATA_READY, ERROR_TIMEOUT, ERROR_CHECKSUM
- Minimal footprint — 17 PIO instructions, lightweight C++ classes
| Component | Description |
|---|---|
| Raspberry Pi Pico / Pico W | RP2040-based board |
| DHT22 (AM2302) | Temperature & humidity sensor |
| 4.7 kΩ resistor | Pull-up between data line and 3.3V |
Pico GP15 ──┬── DHT22 Data (pin 2)
│
4.7kΩ
│
3.3V
DHT22 VCC (pin 1) ── 3.3V
DHT22 GND (pin 4) ── GND
DHT22 pin 3 ── not connected
- Download this repository as a
.zipfile - Go to Sketch → Include Library → Add .ZIP Library...
- Select the downloaded file
- Select your board: Tools → Board → Raspberry Pi Pico / Pico W
Add to your platformio.ini:
[env:pico] platform = raspberrypi board = pico framework = arduino lib_deps = https://github.com/angeloINTJ/DHT22PIO_RP2040.git
Open the Arduino IDE, go to Sketch → Include Library → Manage Libraries..., search for DHT22PIO_RP2040 and click Install.
#include <DHTBus.h> #include <DHT22PIO.h> DHTBus bus(pio0); DHT22PIO sensor(bus); void setup() { Serial.begin(115200); bus.begin(15); // GP15 } void loop() { sensor.requestReading(15); while (sensor.getState() == DHT22PIO::WAITING_PIO) { sensor.update(); } float temp, hum; if (sensor.getResults(temp, hum)) { Serial.print(temp, 1); Serial.print(" °C, "); Serial.print(hum, 1); Serial.println(" %RH"); } else { sensor.reset(); } delay(3000); }
The key advantage of this library is that update() returns immediately — the CPU is free to handle other tasks while the PIO captures data in hardware:
void loop() { // Kick off a reading (returns instantly) if (!readingInProgress) { sensor.requestReading(15); readingInProgress = true; } // Poll (non-blocking — returns immediately) sensor.update(); if (sensor.getState() == DHT22PIO::DATA_READY) { float temp, hum; sensor.getResults(temp, hum); readingInProgress = false; } // CPU is free for other work here: // update display, handle web requests, read other sensors... }
| Example | Description |
|---|---|
| BasicReading | Minimal read loop — start here |
| MultiSensor | Multiple DHT22 on different pins with one PIO instance |
| NonBlockingRead | True async pattern with free CPU cycles |
| DiagnosticMode | State machine lifecycle and timing inspection |
| HeatIndex | Compute feels-like temperature (NOAA Rothfusz equation) |
DHTBus bus(pio0); // or pio1 bool ok = bus.begin(pin); // Initialize PIO + claim state machine bus.setPin(pin); // Switch GPIO at runtime bus.startPIORead(); // Start wake-up + data capture bus.stopPIORead(); // Halt the state machine bool avail = bus.hasData(); // Check RX FIFO uint32_t raw = bus.readFIFO(); // Pop one word from FIFO
DHT22PIO sensor(bus); // Async read cycle sensor.requestReading(pin); // Start (non-blocking) sensor.update(); // Poll (call frequently) DHT22PIO::State s = sensor.getState(); // Check progress sensor.reset(); // Clear error state // Retrieve data (only valid when state == DATA_READY) float temp, hum; sensor.getResults(temp, hum); // Error reporting char msg[64]; sensor.getLastErrorString(msg, sizeof(msg));
requestReading() update() update()
IDLE ──────────────► WAITING_PIO ──────► DATA_READY
│ │
│ timeout │ getResults()
▼ ▼
ERROR_TIMEOUT IDLE
│
│ bad checksum
▼
ERROR_CHECKSUM
reset() returns any error state → IDLE
The RP2040 has two PIO blocks, each with 4 state machines and 32 instruction slots. This library loads a 17-instruction program that implements the full DHT22 protocol in hardware:
- Wake-up pulse — drives the pin LOW for exactly 1.56 ms using nested countdown loops
- Handshake — waits for the sensor's ACK sequence (~80 μs LOW + ~80 μs HIGH)
- Bit capture — for each of the 40 data bits, waits for the rising edge, delays 40 μs, then samples the pin:
- If HIGH → the 70 μs pulse (bit '1') is still active
- If LOW → the 28 μs pulse (bit '0') has already ended
The PIO clock runs at 1 MHz (1 μs/tick). All timing is cycle-accurate regardless of CPU load.
┌──────────────┐ ┌──────────────┐
│ DHT22PIO │────▶│ DHTBus │
│ (Driver) │ │ (PHY Layer) │
│ │ │ │
│ • State mach │ │ • PIO mgmt │
│ • Checksum │ │ • startRead │
│ • Temp/Hum │ │ • stopRead │
│ • Error rpt │ │ • FIFO access│
└──────────────┘ └──────┬───────┘
│
┌──────▼───────┐
│ RP2040 PIO │
│ State Mach. │
│ │
│ 17-instr asm │
│ 1 μs/tick │
└──────┬───────┘
│
GPIO pin
│
┌────▼────┐
│ DHT22 │
└─────────┘
Contributions are welcome! Please read CONTRIBUTING.md before submitting a pull request.
- Fork this repository
- Create a feature branch:
git checkout -b feature/my-improvement - Commit your changes:
git commit -m "Add: description of change" - Push to the branch:
git push origin feature/my-improvement - Open a Pull Request
This project is licensed under the MIT License — see LICENSE for details.
- Aosong Electronics for the DHT22/AM2302 datasheet
- Raspberry Pi Foundation for the RP2040 PIO architecture
- The Arduino-Pico community for the RP2040 Arduino core
- OneWirePIO_RP2040 — PIO-accelerated DS18B20 library by the same author