Geek Culture
Published in

Geek Culture

DHT1 Temperature Sensor Library for the Raspberry Pico

The Raspberry Pico, or shorthand Pico, is a new microcontroller from the Raspberry Pi foundation. It provides a dual core ARM processor, 2MB of flash memory, and 26 GPIO pins. You can program the Pico with either a C/C++ SDK or MicroPython. I became fascinated by this device and started to develop a library for controlling a shift register, specifically the HC595N shift register. To get a better grip on the Pico C SDK, I looked for another sensor for which I could develop a library, and found the DHT11 temperature sensor.

The DHT11 sensor is connected via one data pin only. It also has a proprietary protocol for exchanging data: Send pulses of low and high voltage to activate the sensor, then read pulses that represent a bit pattern that encodes the temperature readings.

This article explains the first part of my development journey: Understanding the DHT11 protocol, creating the library folder structure, and then try to read the temperature data.

This article originally appeared at my blog.

Datasheet

The first touchpoint with any sensor is to get a datasheet and understand how it works in general. My reference for the DHT11 sensor is the documentation on mouser.com. The more often you read a datasheet, the more information you will get out of it. My primary concerns at are summarized in the following list:

  • Pin layout: The sensor is sold as three or four pin version. The four-pin version is actually three pins too — they just soldered (for convenience) another pin. Anyway, the pins are v-in, ground, and data.
  • Input voltage: Supports 3–5.5V, so it can be directly connected to the Pico.
  • Communication protocol: The data pin serves as input and output. An MCU sends a characteristic signal to perform a “wake-up” call on the DHT11. The sensor acknowledges this wake up, and then sends 40bit data
  • Additional operational constraints: The sensor should not be requested within 1 second of powering up, and it should not be queried more often than every 2 seconds.

With these facts we can begin the implementation.

Library Setup

The library is separated into my trusted structure from the shift register library:

  • ./ Contains the central CMakeLists.txt file for three different build types: library only, tests, and examples.
  • ./include Contains the header file
  • ./src The library source files and its accompanying cmake configuration
  • ./test Using the CMocka framework, tests validate that the library objects and functions are correct
  • ./examples Simple recipes how to use the library

Core Objects & Functions

The library exposes the struct object DHT11 with this signature:

typedef struct DHT11
{
uint8_t DATA_PIN;
double last_temp;
double last_humidity;
double temp_measurements[30];
double humidity_measurements[30];
} DHT11;

The sensor object is created with dht11_new, and then provides these functions:

  • dht11_probe() - Take a new measurement from the sensor, but only when it’s at least two seconds after the last try
  • dht11_process() - A helper method that receives the sequenced 40bit data, calculates the checksum, and updates the internal values when the probe was valid.
  • dht11_get_last_temperature_measurement() - Returns the most recent temperature measurement
  • dht11_get_last_humidity_measurement() - Returns the most recent humidity measurement
  • dht11_get_historic_temperature_measurement() - Retrieves a temperature measurement from the last 30 probes
  • dht11_get_historic_humidity_measurement() - Retrieves a humidity measurement from the last 30 probes

Each function comes with a test suite — see test.c in the github repository. I will not detail the tests in this article, but will focus on getting the sensor to work. If you are interested in my test approach, read my earlier articles about unit tests with CMocka and testing the shift register library.

Imperative Protocol Verification

The very first version of the program can be summarized as imperative statement with explicit protocol verification.

The general idea is to define blocks of code that handle the three phases sensor startup, sensor confirmation and sensor data. Then, each phase would use a counter and a sleep_us call to explicitly wait for the time as specified in the data sheet. I would then output a debug statement after each phase to confirm that the sensor behaves as expected.

Startup and Conformation

The startup signal is simple:

  • Set the data pin to output
  • Send LOW for 18ms
  • Send HIGH for 20us
// I Activate DHT
{
gpio_put(pin, 0); // LOW
sleep_ms(18); // 18us
gpio_put(pin, 1); // HIGH
sleep_us(20); // 20us
}

To test the sensor confirmation phase, the concrete steps are:

  • Set the data pin to input
  • Wait for up to 80us that a LOW value is read
  • Print a debug statement
  • Wait for up to 80us that a HIGH value is read

The code in particular:

// II Read DHT Confirmation
{
gpio_set_dir(pin, GPIO_IN);
bool init_state = 0;
int count = 0;
while(init_state = !gpio_get(pin)) { // EXPECT LOW 80us
count++;
sleep_us(1);
};
printf("DHT Confirmation LOW: %d\n", count); count = 0;
while(init_state = gpio_get(pin)) {
count++;
sleep_us(1);
};
printf("DHT Confirmation HIGH: %d\n", count); // EXPECT HIGH 80us
}

With this initial code, I started to test the sensor.

Mind the Hardware

After spending about 4 hours of trying explicit wait, and then even to constantly write/read data via the GPIO pin, I could not get any response from the sensor.

Either my approach is just utterly wrong, or I got the protocol confused, but it corresponds to what I saw in other blog articles. So I connected the sensor with an Arduino, uploaded the trusted Adafruit DHT Lib exmaple sketch, and .. the code failed! I only saw the error message Failed to read from DHT sensor!. The sensor was broken, and all that time wasted.

So I ordered a new sensor, uploaded the Arduino sketch, and could get these results on the serial terminal:

Humidity: 46.00%  Temperature: 24.30°C 75.74°F  Heat index: 23.99°C 75.18°F

The sensor was broken! I wasted a lot of time and energy into fixing code while the problem was in the hardware. A crucial lesson in embedded software developmetn.

Getting the Timings Right

Even with a working sensor, I had no success to get the timing right. Neither reading the datasheet and double checking with another datasheet, nor looking into the official Pico example and also into an Arduino library for the same sensor type helped. Both libraries work with explicit calls to sleep for the amount of time as specified by the sensor, but I could not get it done. Investing further project time to study the timing effects of the various statements in my code - like what is the impact of the counter, and what of the printf - was also not working.

Taking some time off, and studying other projects, I found out that MicroPython implementations for this sensor are available. And these libraries are using the Pico PIO system, a special hardware system on the Pico that you program with assembly-like language. I gave up on pure C, and decided to investigate the utilization of Pico. The next blog article details how Pico can be used.

Conclusion

My first attempt to read temperature data from a DHT sensor failed. I thought long about the process and whether I should write about a failed attempt. Definitely I should because I want to share these essential learnings. First, always check that the hardware you are working with is functioning. I wasted 4 hours to fix code that was not working on a, well, broken sensor. Second, to the least of my knowledge, getting very precise timings with just the C SDK is difficult — if you have made better progress in this direction, tell me.

The next article will continue the sensor development indirectly: We will learn the basics of the PIO system, and see how to include it in a C program.

--

--

--

A new tech publication by Start it up (https://medium.com/swlh).

Recommended from Medium

Enjoyment, Struggle and Growth with Bangkit 2022 — #BangkitExperience

READ/DOWNLOAD=- Starting Out with C++: Early Objects (9th Edition) FULL BOOK PDF & FULL AUDIOBOOK

SMEs and Web Developers: who do you need to hire for your project?

How to TCPdump effectively in Kubernetes (part 2)

Building a Board Game in Unity

Pattern-Escape Spam

Weekly Tech Report

Null Safety with Flutter 2.0

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Sebastian

Sebastian

IT Project Manager & Developer

More from Medium

Twerk lidar robot — part 1

How to set up a Google Compute Engine using Ubuntu 20.04

What Time Is It? Seeed XIAO with Expansion Board Answers

Alarm clock

Use CUDA 11.0 for RAPIDS 21.12 with TensorFlow 2.4 in Ubuntu 18.04