1

So, I'm trying to make the DHT11 sensor work without any library on a Raspberry Pi 2 using C. I'm using this tutorial to manipulate the GPIO pins registers so i can set them as input,output, HIGH and LOW. I am also using the wiringPi library to be sure that the timers are correct when sending initialization signals to the DHT11 sensor.

Here is the code that i am trying to make work:

#include <wiringPi.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include "RPI.h"

#define MAXTIMINGS 85

int dht11_dat[5] = {0, 0, 0, 0, 0};

int read_GPIO(int number)
{
    if(GPIO_READ(number))
        return 1;
    else
        return 0;
}
void read_dht11_dat()
{

   uint8_t laststate    = 1;
   uint8_t counter      = 0;
   uint8_t j        = 0, i;
   float    f; /* fahrenheit */

   dht11_dat[0] = dht11_dat[1] = dht11_dat[2] = dht11_dat[3] = dht11_dat[4] = 0;

   if(map_peripheral(&gpio) == -1)
   {
       printf("Failed to map the physical GPIO register!");
   }

   INP_GPIO(4);//befot output, must set as INPUT
   OUT_GPIO(4);//set outout
   /* pull pin down for 18 milliseconds */
   GPIO_CLR = 1 << 4;
   delay( 18 );
   /* then pull it up for 40 microseconds */
   GPIO_SET = 1 << 4; //    digitalWrite(7, HIGH );
   delayMicroseconds( 40 );
   /* prepare to read the pin */
   INP_GPIO(4);//pinMode( 7, INPUT );


   /* detect change and read data */
   for ( i = 0; i < MAXTIMINGS; i++ )
   {
       counter = 0;

       while ( read_GPIO(4) == laststate )
       {
           counter++;
           delayMicroseconds( 1 );
           if ( counter == 255 )
           {
               break;
           }
       }

       laststate = read_GPIO(4);/*digitalRead( 7 );*/

       if ( counter == 255 )
           break;

       /* ignore first 3 transitions */
       if ( (i >= 4) && (i % 2 == 0) )
       {
           /* shove each bit into the storage bytes */
           dht11_dat[j / 8] <<= 1;
           if ( counter > 16 )
               dht11_dat[j / 8] |= 1;
           j++;
       }
   }

/*
 * check we read 40 bits (8bit x 5 ) + verify checksum in the last byte
 * print it out if data is good
 */
if ( (j >= 40) && (dht11_dat[4] == ( (dht11_dat[0] + dht11_dat[1] + dht11_dat[2] + dht11_dat[3]) & 0xFF) ) )
{
    f = dht11_dat[2] * 9. / 5. + 32;
    printf( "Humidity = %d.%d %% Temperature = %d.%d *C (%.1f *F)\n",
        dht11_dat[0], dht11_dat[1], dht11_dat[2], dht11_dat[3], f );
}
else  {
    printf( "Data not good, skip\n" );
}


//unmap_peripheral(&gpio); should this be here, im confused is this restarting the state of the gpio pin
}

 int main()
 {

   printf( "Raspberry Pi wiringPi DHT11 Temperature test program\n" );

   if ( wiringPiSetup() == -1 )
       exit( 1 );

   while ( 1 )
   {
       read_dht11_dat();
       delay( 1000 ); /* wait 1sec to refresh */
   }
   return 0;

}

So my question is why is this not working? When I test the GPIO manipulations with a simple blinking LED program everything is working OK. I assume that the problem is in the INP_GPIO, OUT_GPIO, when they are called more than once the addresses of the registers are not set appropriate. Is there a way i can somehow "restart" the gpio pins original state at the beginning of the function? I guess this will fix my problem?

Correct me if i'm wrong!

3
  • You are using a library. I'm not quite sure what distinction you are making between using wirinPi and any other library. None of the methods you are using will reliably read the DHT11.
    – joan
    Commented Dec 9, 2015 at 19:56
  • I am using the library that i linked above so you can see how the gpio manipulation is done. And im using the wiringPi just for the timers. The code is giving me output if i substitute the INP_GPIO and the others manipulationa with the wiringPi ones. Commented Dec 9, 2015 at 20:01
  • I've pointed you to code before which sets GPIO modes. Using macros instead of functions is a pretty pointless exercise.
    – joan
    Commented Dec 9, 2015 at 20:15

1 Answer 1

1

Here is a working example for the DHT11 sensor working without any external libraries on the Raspberry Pi 2. If you need any info on the functions just man them.

Here is my solution:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <time.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#define BCM2708_BASE (0x3F000000)
#define GPIO_BASE (BCM2708_BASE + 0x200000)
#define BLOCK_SIZE (4096)
#define MAXTIMINGS 85

struct bcm2835_peripheral
{
    int mem_fd;
    void *map;
    volatile unsigned int *addr;//address of mapped area
};
struct bcm2835_peripheral gpio;

/*
 *Mapping memory areas with mmap function will provide our program a direct access to device memory
 *Parameters: structrure for the addresses of the specified mapped memory areas
 */

int map_peripheral(struct bcm2835_peripheral *p)
{
    //open the /dev/mem folder with read/write
    if((p->mem_fd = open("/dev/mem", O_RDWR|O_SYNC)) < 0)
    {
        printf("Failed to open /dem/mem, did you sudo?\n");
        return -1;
    }
    p->map = mmap(NULL,BLOCK_SIZE,PROT_READ|PROT_WRITE,MAP_SHARED,p->mem_fd, GPIO_BASE);

    if(p->map == MAP_FAILED)
    {
        printf("mmap failed, MAP_FAILED\n");
        return -1;
    }
    close(p->mem_fd);
    p->addr = (volatile unsigned int *)p->map;

    return 0;
}
void unmap_peripheral(struct bcm2835_peripheral *p)
{
    munmap(p->map, BLOCK_SIZE);
    close(p->mem_fd);
}


//setting the pin as input
void input_GPIO(int gpio_numb)
{
    *(gpio.addr + ((gpio_numb)/10)) &= ~(7<<(((gpio_numb)%10)*3));
}
//setting the pin as output
void output_GPIO(int gpio_numb)
{
    input_GPIO(gpio_numb);
    *(gpio.addr + ((gpio_numb)/10)) |=  (1<<(((gpio_numb)%10)*3));
}
//setting the pin to HIGH
void high_GPIO(int gpio_numb)
{
    *(gpio.addr + 7) = 1 << gpio_numb;
}
//setting the pin to LOW
void low_GPIO(int gpio_numb)
{
    *(gpio.addr + 10) = 1 << gpio_numb;
}
//reading the state of the pin, 1 if HIGH, 0 if LOW
int read_GPIO(int gpio_numb)
{
    if(  *(gpio.addr + 13) & (1 << gpio_numb) )
    {
        return 1;
    }
    else
        return 0;
}

//this function is going to delay time in microseconds
void sleepMicro(unsigned int time)
{
    struct timeval now;
    struct timeval period;
    struct timeval end;

    gettimeofday(&now, NULL);
    period.tv_sec = time / 1000000;
    period.tv_usec = time % 1000000;
    timeradd(&now, &period, &end);
    while(timercmp(&now, &end, <))
    {
        gettimeofday(&now, NULL);
    }
}

uint8_t dht11_data[5]={0,0,0,0,0};//changed
void read_DHT11()
{
    //TODO make the function to return value to the parameteres, reference
    //TODO how to convert char floats to floats
    uint8_t laststate = 1;
    uint8_t counter = 0;
    uint8_t j = 0;
    uint8_t i = 0;
    float farenheit;

    /* From the DHT11 datasheet we read */
    dht11_data[0] = 0;  //The 8bit humidity integer data
    dht11_data[1] = 0;  //The 8bit humidity decimal data
    dht11_data[2] = 0;  //The 8bit temperature integer data
    dht11_data[3] = 0;  //The 8bit temperature decimal data
    dht11_data[4] = 0;  //The 8bit parity bit

    /* Sending initialization signal  */
    output_GPIO(4);/* set the pin as output */
    low_GPIO(4); /* pull the pin LOW  */
    sleepMicro(18 * 1000);/* delay for 18 milliseconds which are 18000 microseconds */
    high_GPIO(4); /* pull the pin HIGH */
    sleepMicro(40);/* delay for 40 microseconds */
    input_GPIO(4);/* set the pin as input so we can read output from the sensor */
    for(i = 0;i < MAXTIMINGS;i++)
    {
        counter = 0;
        while(read_GPIO(4) == laststate)
        {
            counter++;
            sleepMicro(1); //delay for 1 micro second;
            if(counter == 255)
            {
               break;
            }
        }
    laststate = read_GPIO(4);
    if(counter == 255)
    {
        break;
    }
    // top 3 transistions are ignored
    if( (i >= 4) && (i % 2 == 0) )
    {
        dht11_data[j/8] <<= 1;
        if(counter > 16)
        {
           dht11_data[j/8] |= 1;
        }
        j++;
    }
  }
    // Check if the data is correct acording to datasheet
    if( (j >= 40) && (dht11_data[4] == ((dht11_data[0] + dht11_data[1] + dht11_data[2] + dht11_data[3]) & 0xFF)))
    {
        farenheit = dht11_data[2]*9./5.+32;
        printf("Humidity = %d.%d %% Temperature = %d.%d *C (%.1f *F)\n",dht11_data[0],dht11_data[1],dht11_data[2],dht11_data[3],farenheit);
    }
    else
    {
        printf("Data not correct!\n");
    }
}

int main()//changed
{
    printf("DHT11 on a Raspberry Pi 2\n");
    map_peripheral(&gpio);
    while(1)
    {
        read_DHT11();
        sleep(1);
    }

   return 0;
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.