Reading the Temp & Humidity from the DHT11 connected to a Raspberry PI

 


Connecting the thermal module (DHT11) is quite simple. Here're the pins that I used.


Module    RPI

GND        GND (Pin 6)

VCC        VCC (Pin 1 - may need Pin 2 (5v) for longer distances)

Data        GPIO 0 (Pin 11)


Overall, the way to read data from the thermal module is to pulse the data pin and then wait for 40 bits of data.

The Pulse

The RPi needs to pulse the data pin low for 18ms (milliseconds) and then wait for module to pulse the data signal low then high for 80us (microseconds)


The Data

The data is transmitted as 50us of the data line getting pulled low, followed by the line getting pulled high for ~27us (for a "0") or high for 70us (for a "1").


The 40 bits

The 40 bits are made up of the following

2 x 8 bits of humidity

2 x 8 bits of temperature

8 bits of parity

The humidity and temperature are made up of the first 8 bits are the whole part of the number when the second 8 bits are the fractional part. For example 0x10 0x12 would be 0x10.0x12 = 16.18 (% or C, for humidity or temperature)

The Code

The key parts of the code are the pulse and reading the data

The Pulse Code

                pinMode(pin, OUTPUT);

                digitalWrite(pin, LOW);

                delay(18);

                digitalWrite(pin, HIGH);

                delayMicroseconds(start);

                pinMode(pin, INPUT);


The above code sets the pin as OUTPUT, sets it LOW and then delays for 18 milliseconds. It then sets the pin back to HIGH and waits for "start" - this defaults to 60us. Then the pin is set for input. We're ready to read the data.

The Data Code

The code for reading the data has the following structure

1. Wait for High. We need to wait for a HIGH, so we know when to start timing when we get a HIGH. If we don't get a HIGH after 200 attempts, then we bail. 

2. Wait for Low. We need to time how long a HIGH is, so we can determine if the value is a zero (~27us) or a one (~70us). We increment 'counter' for each microsecond. If we don't get a HIGH after 200 attempts, then we bail. (We could wait a longer period of time between each sample)

3. Verify Checksum. We verify that sum(bytes 1+2+3+4) AND 0xff == byte 5.


The Complete Code


#include <wiringPi.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <getopt.h>
#include <string.h>

#define DATABITS 1 + 40 //40 data bits plus the start bit
#define PIN 0           //default GPIO pin (wPi pin number)
#define START 60        //wait after start
#define THRESHOLD 45    //Threshold between a zero (should be ~27uS) and a one (should be ~70us)
#define RETRY 3         //Retry attempts

#define soptions "p:s:t:r:hv"

void help()
{
    printf("\
   --pin\tGPIO Pin to use (wPi Number)\n\
   --start\tStart wait in microseconds (default START )\n\
   --threshold\tZero or One threshold (default THRESHOLD )\n\
   --help\tHelp\n\
   --verbose\tOutput Verbose Information\n");
}

static struct option const long_options[] =
    {
        {"pin", required_argument, NULL'p'},       // List all minions
        {"start", required_argument, NULL's'},     // all output (default)
        {"threshold", required_argument, NULL't'}, // delay after packet.
        {"retry", required_argument, NULL't'},     // retry attempts.
        {"help", no_argument, NULL'h'},            // Help
        {"verbose", no_argument, NULL'v'},         // verbose output.
        {NULL, no_argument, NULL0}};

int main(int argcchar *argv[])
{
    int counter = 0;
    int i, checksum, len = 0, bit;
    int pin = PIN; //Raspberry Pi GPIO pin
    int start = START;
    int threshold = THRESHOLD;
    int attempt, retry = RETRY;
    int tempData[5] = {00000};
    int verbose = 0;
    int c;

    // Need a better way to parse the options. There's no real error handling.

    while ((c = getopt_long(argc, argv, soptions, long_options, NULL)) != -1)
    {
        switch ((char)c)
        {
        case 'p'//list all registered minions
            pin = atoi(optarg);
            break;
        case 's':
            start = atoi(optarg);
            break;
        case 't':
            start = atoi(optarg);
            break;
        case 'r':
            retry = atoi(optarg);
            break;
        case 'v':
            verbose = 1;
            break;
        default:
        case 'h':
            help();
            exit(0);
            break;
        }
    }

    if (wiringPiSetup() == -1)
    {
        printf("Unable to set up WiringPi - check your installation\n");
        return (2);
    }

    for (attempt = 0; attempt < retry; attempt++)
    {
        pinMode(pin, OUTPUT);
        digitalWrite(pin, LOW);
        delay(18);
        digitalWrite(pin, HIGH);
        delayMicroseconds(start);
        pinMode(pin, INPUT);

        for (bit = 0; bit < DATABITS; bit++)
        {
            //wait for low to go high
            counter = 0;
            while (digitalRead(pin) == LOW)
            {
                counter++;
                delayMicroseconds(1);
                if (counter == 200)
                {
                    if (verbose)
                        printf("No LOW detected for bit %d\n", bit);
                    break;
                }
            }
    
            //Now high, wait for low
            counter = 0;
            while (digitalRead(pin) == HIGH)
            {
                counter++;
                delayMicroseconds(1);
                if (counter == 200)
                {
                    if (verbose)
                        printf("No HIGH detected for bit %d\n", bit);
                    break;
                }
            }

            if (counter == 200)
            {
                break;
            }

            if (bit > 0)
            {
                tempData[(bit - 1) / 8] <<= 1;
                tempData[(bit - 1) / 8] += counter < threshold ? 0 : 1;
            }
        }

        if (counter == 200)
        {
            if (verbose)
                printf("Transmission error \n");
        }
        else
        {
            checksum = tempData[0] + tempData[1] + tempData[2] + tempData[3];
            checksum & +0xff;

            if (checksum == tempData[4])
            {
                printf("Humidity = %d.%d%% Temperature = %d.%dC \n",
                       tempData[0], tempData[1], tempData[2], tempData[3]);
                return (0);
            }
            else
            {
                if (verbose)
                {
                    printf("Checksum error %x:%x\n", checksum, tempData[4]);
                    printf("%x:%x:%x:%x:%x\n\n"tempData[0], tempData[1], tempData[2], tempData[3], tempData[4]);
                }
            }
        }
        delay(100);  //delay 100ms (not uS)
        memset(tempData, 05);
    }
    return (1);
}

Compile options

Assuming that above is in powertemp.c, us the following to compile (assume that gpio is installed)

gcc -o pt powertemp.c -lwiringPi -lwiringPiDev













Comments

Popular posts from this blog

Quick guide: ADS1115 on Raspberry Pi

Configuring Email on Rasbian Buster (Not Sending Email)

Bash Garage Door Monitor on Raspberry Pi