TinuDHT

TinuDHT is a C library for working with the DHT11 temperature/humidity sensor intended to be used with the Tinusaur but should also work with any other board based on ATtiny85 or similar microcontroller.

Tinusaur Board DHT11 LCD Battery

There are of course may libraries (sometime called drivers) to work with DHT11 and the more advanced DHT21/DHT22 but they were written primarily for the Arduino environment and do not work well (or at all) with pure ATtiny boards. Here is a list of some of the popular libraries with short descriptions from their authors:

  • Class for DHTxx sensors
    http://playground.arduino.cc/Main/DHTLib
    The DHT11, DHT21 and DHT22 are relative cheap sensors for measuring temperature and humidity. This article describes a library for reading both values from these sensors.
  • A DHT11 Class for Arduino
    http://playground.arduino.cc/Main/DHT11Lib
    The DHT11 is a relatively cheap sensor for measuring temperature and humidity. This article describes a small library for reading both from the sensor. The DHT22 is similar to the DHT11 and has greater accuracy.
  • Adafruit TinyDHT
    https://github.com/adafruit/TinyDHT
    This is an Arduino library for the Adafruit Trinket and Gemma mini microcontrollers for the DHT series of low cost temperature/humidity sensors. The library returns integer values to save space on the memory constrained ATTiny85 by not requiring the floating point library.

DHT11

The DHT11 is very basic, low-cost digital temperature and humidity sensor. It uses a capacitive humidity sensor and a thermistor for measurements, and sends out the info to the data pin. It is relatively simple to use it, but requires precise timing to retrieve the data correctly. One disadvantage of this sensor is that you can get new data from it no more often than once every 1 or 2 seconds.

DHT11

Technical parameters of DHT11:

  • Humidity: 20-90 % RH, ±5%RH
  • Temperature:0-50 ℃, ±2℃ 1
  • Power supply: 3.0 – 5.5 V DC

Pinout:

  • 1: Vdd – Power supply.
  • 2: Data – Serial data.
  • 3: N/C – Not connected.
  • 4: GND – Ground.

Sending/Receiving:

  • The host (MCU, microcontroller) sends short 18ms LOW to the data pin, then waits a little – 20-40 us and then waits for the DHT to start sending data back. The short HIGH’s are “0” and the long HIGH’s are “1”.
DHT11 Timing Diagram
DHT11 Timing Diagram

Library

The primary problem with the direct use of the Arduino libraries is that the ATtiny85 and Tinusaur in particular do not have enough resource to handle the send/receive process properly, i.e. not enough CPU power, in result of which the timing of the signals that are sent to the sensor and received from it become messed up. In addition those libraries use Arduino specific code and/or C++ specific syntax which makes them incompatible with the plain C language.

This library is based on DHT11Lib code. It was adapted for ATtiny, removed Arduino dependencies and timing was adjusted to work well on ATtiny85 at 1 MHz. There are few other changes and optimizations for speed and size.

TinuDHT is written in plain C and does not require any additional libraries to function except those that come with the WinAVR SDK.

The library consists of 2 file:

  • tinudht.h
  • tinudht.c

Source Code

Here is the source code of the TinuDHT library.

Some of the comments were striped out to save space on the screen.

tinudht.h

/*
 * Tinu DHT - Tinusaur DHT11 Library
 *
 * @file: tinudht.h
 * @created: 2014-07-08
 * @author: neven
 *
 * Source code available at: https://bitbucket.org/tinusaur/tinudht
 *
 */

#ifndef TINUDHT_H
#define TINUDHTDHT_H

#define TINUDHT_OK              0
#define TINUDHT_ERROR_CHECKSUM  -1
#define TINUDHT_ERROR_TIMEOUT   -2

typedef struct {
    uint16_t humidity;
    uint16_t temperature;
} TinuDHT;

uint8_t tinudht_read(TinuDHT *ptinudht, uint8_t dht_pin);

#endif

tinudht.c

/*
 * Tinu DHT - Tinusaur DHT11 Library
 *
 * @file: tinudht.c
 * @created: 2014-07-08
 * @author: neven
 *
 * Source code available at: https://bitbucket.org/tinusaur/tinudht
 *
 */

#include <stdlib.h>
#include <avr/io.h>
#include <util/delay.h>

#include "tinudht.h"

#define TINUDHT_RCV_TIMEOUT 255
#define TINUDHT_RCV_DELAY 10
#define TINUDHT_RCV_LENGTH 2

uint8_t tinudht_read(TinuDHT *ptinudht, uint8_t dht_pin) {

    // Buffer to received data
    uint8_t data[5];
    // Empty the buffer
    data[0] = data[1] = data[2] = data[3] = data[4] = 0;

    // Send request
    DDRB |= (1 << dht_pin); // Set port as output
    PORTB &= ~(1 << dht_pin);   // Set to 0
    _delay_ms(18);  // Wait 18 ms
    PORTB |= (1 << dht_pin);    // Set to 1
    _delay_us(40);  // Wait 40 us

    // Receive response
    DDRB &= ~(1 << dht_pin);    // Set port as input

    uint8_t timeout;

    // Acknowledge
    timeout = TINUDHT_RCV_TIMEOUT;
    while(bit_is_clear(PINB, dht_pin))  // Wait for 1
        if (timeout-- == 0)
            return TINUDHT_ERROR_TIMEOUT;

    timeout = TINUDHT_RCV_TIMEOUT;
    while(bit_is_set(PINB, dht_pin))    // Wait for 0
        if (timeout-- == 0)
            return TINUDHT_ERROR_TIMEOUT;

    uint8_t bit_index = 7;
    uint8_t byte_index = 0;
    // READ OUTPUT - 40 BITS => 5 BYTES or TIMEOUT
    for (uint8_t i = 0; i < 40; i++)
    {
        // Wait for start
        timeout = TINUDHT_RCV_TIMEOUT;
        while(bit_is_clear(PINB, dht_pin))  // Wait for 1
            if (timeout-- == 0)
                return TINUDHT_ERROR_TIMEOUT;

        // Determine the bit value
        uint8_t len = 0;
        while(bit_is_set(PINB, dht_pin)) {  // Wait for 0
            _delay_us(TINUDHT_RCV_DELAY);
            if (len++ == TINUDHT_RCV_TIMEOUT)
                return TINUDHT_ERROR_TIMEOUT;
            }

        if (len >= TINUDHT_RCV_LENGTH) data[byte_index] |= (1 << bit_index);

        if (bit_index == 0) // next byte?
        {
            bit_index = 7;  // restart at MSB
            byte_index++;   // next byte!
        }
        else bit_index--;
    }

    uint8_t checksum = data[0] + data[2];
    if (data[4] != checksum) return TINUDHT_ERROR_CHECKSUM;

    // On DHT11 data[1],data[3] are always zero so not used.
    ptinudht->humidity = data[0];
    ptinudht->temperature = data[2];

    return TINUDHT_OK;
}

Please note that the source code above may improve or change so check the latest version at the source code repository on this address: https://bitbucket.org/tinusaur/tinudht.

Usage

Using the TinuDHT library is very simple.

#include "../tinudht/tinudht.h"
#define TINUDHT_PIN PB0
void main(void) {
    TinuDHT tinudht;
    tinudht_read(&tinudht, TINUDHT_PIN);
    debug_print_dec(tinudht.humidity);
    debug_print_dec(tinudht.temperature);
    }
}

We need a buffer for the data tinudht and the pin where the data will be sent/received. Then we call the tinudht_read funcation. Note that we pass the buffer by address.

The function returns “0” for success or negative for errors.

    tinudht_read(&amp;amp;amp;amp;tinudht, TINUDHT_PIN);

The result is available as tinudht.humidity and tinudht.temperature.

Testing Program

Below is a simple program that reads the data from a DHT11 and shows it on a LCD screen.

The LCD screen is based on PCD8544 but is more popular under the Nokia 5110/3310 LCD name.

/*
 * Tinu DHT - Tinusaur DHT11 Library
 *
 * @file: main.c
 * @created: 2014-07-08
 * @author: neven
 *
 * Source code available at: https://bitbucket.org/tinusaur/tinudht
 *
 */

#include <stdlib.h>
#include <avr/io.h>

#define F_CPU 1000000UL
#include <util/delay.h>

#include "lcdddd.h"
#include "lcddddf.h"

//  #define LCD_PIN_RESET PB0   // RST, Pin 1 on LCD - RESET
//  #define LCD_PIN_SCE   PB1   // CE,  Pin 2 on LCD - Chip Enable
//  #define LCD_PIN_DC    PB2   // DC,  Pin 3 on LCD - Data/Command mode select
//  #define LCD_PIN_SDIN  PB3   // DIN, Pin 4 on LCD - Serial Data In line
//  #define LCD_PIN_SCLK  PB4   // CLK, Pin 5 on LCD - Serial Clock line
//  // ----------------------   // Vcc, Pin 6 on LCD
//  // ----------------------   // Lit, Pin 7 on LCD
//  // ----------------------   // GND, Pin 8 on LCD

// NOTE/IMPORTANT: The RESET wire of te LCD module should be connected directly
//                 to the RESET pin of the MCU - pin 1 on the chip.

#include "../tinudht/tinudht.h"

#define TINUDHT_PIN PB0

int main(void) {

    lcdddd_init(); // Initialize the LCD
    lcdddd_clear();

    _delay_ms(100); // Delay for DHT11 to stabilize (REQUIRED on power on)
    while (1) {

        lcdddd_gotoxy(0, 0);
        lcdddd_print_string("TinuDHT Test");

        // --------------------------------------------------------------------

        TinuDHT tinudht;
        tinudht_read(&tinudht, TINUDHT_PIN);

        // --------------------------------------------------------------------

        lcdddd_gotoxy(0, 4);
        lcdddd_print_string("H:");
        lcdddd_print_dec_padded(tinudht.humidity);
        lcdddd_print_string(" %");

        lcdddd_gotoxy(0, 5);
        lcdddd_print_string("T:");
        lcdddd_print_dec_padded(tinudht.temperature);
        lcdddd_print_string(" C");

        _delay_ms(1000);
        // IMPORTANT: Do not query the DHT11 more often than 1 time per second.
    }

    return 0;
}

The source code of this testing program along with the LCDDDD library to control the LCD screen is available at the source code repository in the “tinudht_test” folder.

External Resources

The source code of the TinuDHT is available at https://bitbucket.org/tinusaur/tinudht.

DHT11 Datasheet and specification (PDF): http://www.micro4you.com/files/sensor/DHT11.pdf

2 thoughts on “TinuDHT”

  1. Hi!
    First, congratulations for your project!
    I was trying to upload your code to my Attiny85, within the Arduino 1.7.6, and it gave me the following error while compiling:
    “tinudht.c:64:2: note: use option -std=c99 or -std=gnu99 to compile your code”

    Do you have any clue on how can I solve this problem?

    Reply
  2. Ah, okay. This is because we use some C language constructions that are relatively new.

    The C/C++ compiler that comes with the Arduino 1.7 dev environment should be capable of doing this – you only need to specify the options mentioned above. Unfortunately, I don’t know at the moment where’s that done – somewhere in system settings maybe.

    Reply

Leave a Comment