kcpi
Posts: 4
Joined: Mon Feb 10, 2014 11:24 am

AM2301 with Raspberrypi - Issue, not working properly

Mon Feb 10, 2014 6:06 pm

Hi Raspi users,

Currently i am working on to write a c program to read temperature and
humidity from AM2301. Below is my c program. The output can be seen
with below link(google spread sheet)

https://docs.google.com/spreadsheet/ccc ... ring#gid=0

What i want from forum people is:

1. Sensor reading is not accurate, consistent
2. Parity byte is not matching with sum of other readings
3. If i remove "printf" statement, the complete reading is going bad

I know, using while loop without any break/infinite loop breaker is not a good practice, but it should not give any problem at this point of time.

I think i am doing something wrong in calculating data from sensor. Please help me to correct it.

Code :

Code: Select all

#include <wiringPi.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#define MAX_TIME 85
#define DHT11PIN 7
int bit[5]={0,0,0,0,0};

void dht21_read_val()
{
	uint8_t counter=0;
	uint8_t j=0,i;
	int index=0;
	int temp1,temp2,hum1,hum2,hum;
	unsigned long t1,t2;
	int cnt =7;

	for(i=0;i<5;i++)
	{
	    bit[i]=0;
	}

	pinMode(DHT11PIN,OUTPUT);
	digitalWrite(DHT11PIN,LOW);
		delay(18);
	digitalWrite(DHT11PIN,HIGH);
		delayMicroseconds(40);
	pinMode(DHT11PIN,INPUT);
		delayMicroseconds(10);

	while(digitalRead(DHT11PIN)==LOW)
	{
	}

	while(digitalRead(DHT11PIN)==HIGH)
	{
	}
	
	for(i=0;i<40;i++)
	{
		while(digitalRead(DHT11PIN)==LOW)
		{
		}
		t1 = micros();
		
		while(digitalRead(DHT11PIN)==HIGH)
		{
		}
		t2 = micros();

		if( (t2-t1) > 50)
		{
			bit[index] |= (1<<cnt);
			printf("1");
			
		}
		else
		{	
			printf("0");
			
		}

		if(cnt == 0)
		{
			cnt = 7;
			index++;
			printf("/");
		}
		else
			cnt--;
	}

	hum1  = bit[0];
	hum2  = bit[1];
	temp1 = bit[2];
	temp2 = bit[3];
	temp1 = temp1*10+temp2/10;  // to merge both digits


	hum = (hum1*256)+hum2;  // to convert high order byte of humidty to decimal
        printf("\n\tTEMPERATURE     :%d.%d",temp1,temp2%10);
        printf("\n\tHUMIDITY        :%d.%d",hum/10,hum%100);
	

}

int main(void)
{
	if(wiringPiSetup()==-1)
	{ 
		exit(1);
	} 
	dht21_read_val();
	printf("\n");

	return 0;
}
Thanks to wiringPi for providing such a good interface for gpio. I referred one of Raspi user code (not sure from where i got this) to write the above program.

kcpi
Posts: 4
Joined: Mon Feb 10, 2014 11:24 am

Re: AM2301 with Raspberrypi - Issue, not working properly

Sun Feb 16, 2014 10:53 am

Now i am able to calculate parity of data received from sensor and parity is matching with sum of humidity and temperature.

But still i am facing a printf issue, if i remove printf statements(extract of the printf part from code is below), reading is not accurate, it is showing 50% less of actual data. Example, if temp is 22, reading is 11.

Code: Select all

printf("1");
printf("0");
printf("/");
Thanks for any help. Below is the modified code

Code: Select all

#include <wiringPi.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#define MAX_TIME 85
#define DHT11PIN 7
int bit[5]={0,0,0,0,0};

void dht11_read_val()
{
        uint8_t counter=0;
        uint8_t j=0,i;
        int index,cnt;
        uint8_t temp1,temp2,hum1,hum2;
        double temp,hum;
        unsigned long t1,t2;

resample:

        temp1=temp2=hum1,hum2=0;
        temp=hum=0;
        cnt =7;
        index=0;

        for(i=0;i<5;i++)
        {
            bit[i]=0;
        }

        pinMode(DHT11PIN,OUTPUT);
        digitalWrite(DHT11PIN,LOW);
                delay(18);
        digitalWrite(DHT11PIN,HIGH);
                delayMicroseconds(40);
        pinMode(DHT11PIN,INPUT);
                delayMicroseconds(10);

        while(digitalRead(DHT11PIN)==LOW)
        {
        }

        while(digitalRead(DHT11PIN)==HIGH)
        {
        }

        for(i=0;i<40;i++)
        {
                while(digitalRead(DHT11PIN)==LOW)
                {
                }
                t1 = micros();

                while(digitalRead(DHT11PIN)==HIGH)
                {
                }
                t2 = micros();

                if( (t2-t1) > 50)
                {
                        bit[index] |= (1<<cnt);
                        printf("1");

                }
                else
                {
                        printf("0");

                }

                if(cnt == 0)
                {
                        cnt = 7;
                        index++;
                        printf("/");
                }
                else
                        cnt--;
        }

        hum1  = bit[0];
        hum2  = bit[1];
        temp1 = bit[2];
        temp2 = bit[3];
        int c = 0xB0;

        hum = (hum1*100)+hum2;
        temp= (temp1*100)+temp2;

        if( (hum1+hum2+temp1+temp2) != bit[4])
        {
                sleep(5);
                goto resample;
        }
        else
        {
                printf("\n\tTEMPERATURE     :%.1f\n",temp/10);
                printf("\tHUMIDITY        :%.1f\n",hum/10);
        }
}


int main(void)
{
        if(wiringPiSetup()==-1)
        {
                exit(1);
        }
        dht11_read_val();
        printf("\n");

        return 0;
}

danjperron
Posts: 3531
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Re: AM2301 with Raspberrypi - Issue, not working properly

Sun Feb 16, 2014 3:01 pm

Hi kcpi,

I don't know if you notice the post just next to yours.

I do use the DHT22 which is exactly the same sensor but without wires.

All code using time loop will have big problem when the RPI cpu usage is very high.

I see only 2 ways , one will be to write a driver and the other one is use something that is not affected with the cpu process.

I did made a small program in python to use the SPI instead of timing loop. The avantage is that you have a precise timing cut which you could decode all the timing provide by the sensor. Even if your cpu is at 95% usage, it will work.

It should be easy to modify the code in C.


this is the post http://www.raspberrypi.org/phpBB3/viewt ... 83#p506283

Daniel

danjperron
Posts: 3531
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Re: AM2301 with Raspberrypi - Issue, not working properly

Sun Feb 16, 2014 7:06 pm

The Schema
DHT22SPI.jpg
DHT22 SPI interface
DHT22SPI.jpg (29.11 KiB) Viewed 13073 times

And this is the code in C.

Code: Select all

pi@raspberrypi ~/dht22spi $ cat dht22spi.c
/* dht22spi
 * SPI device interface to read DHT22 sensor
 *
 * Copyright (c) February 2014  Daniel Perron
 *
 *
 * Software inspire from 
 * http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=blob_plain;f=Documentation/spi/spidev_test.c
 * Copyright (c) 2007  MontaVista Software, Inc.
 * Copyright (c) 2007  Anton Vorontsov <avorontsov@ru.mvista.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License.
 *
 * Cross-compile with cross-gcc -I/path/to/cross-kernel/include
 */

#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <malloc.h>
#include <string.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>


static void pabort(const char *s)
{
	perror(s);
	abort();
}

static uint8_t mode;
static uint8_t bits = 8;
static uint32_t speed = 500000;
static uint16_t delay;
static unsigned char Bits[8]={128,64,32,16,8,4,2,1};


static void transfer(int fd, unsigned char *ArrayTx, unsigned char *ArrayRx, int ArraySize)
{
	int ret;

        ArrayRx[0]=0;
	struct spi_ioc_transfer tr = {
		.tx_buf = (unsigned long)ArrayTx,
		.rx_buf = (unsigned long)ArrayRx,
		.len = ArraySize,
		.delay_usecs = delay,
		.speed_hz = speed,
		.bits_per_word = bits,
	};

	ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
	if (ret < 1)
		pabort("can't send spi message");
}



int GetBit(unsigned char * Array, int bitIdx)
{
   int ByteIdx = bitIdx/8;
   if( (Array[ByteIdx] & Bits[bitIdx % 8]) == 0)
     return 0;
   return 1;
}


int GetNextDelay(unsigned char * Array,  int * bitIdx,  int MaxBit)
{
   int index,Lastbit,delta;

   if( *bitIdx >= MaxBit) return(0);

   index = *bitIdx;
   Lastbit = GetBit(Array,index);
   while(index < MaxBit)
   {
     if(GetBit(Array,++index) != Lastbit)
      {
        delta = index - *bitIdx;
        *bitIdx = index;
        return( (int) (1000000.0 * delta  / speed));  // return value in usec
      }
   }
   return(0);
}




int DecodeArray(unsigned char *ArrayIn,unsigned char *ArrayOut, int TotalBit)
{
  int ByteIdx,BitIdx;
  int BitPointer=0;
  int HighPulse;
  //first get rid off start
  GetNextDelay(ArrayIn,&BitPointer,TotalBit);

  //get rid off wait
  GetNextDelay(ArrayIn,&BitPointer,TotalBit);


  //get rid off ACK
  GetNextDelay(ArrayIn,&BitPointer,TotalBit);

  //get rid off ACK
  GetNextDelay(ArrayIn,&BitPointer,TotalBit);

  for(ByteIdx=0;ByteIdx<5;ByteIdx++)
   {
    ArrayOut[ByteIdx]=0;
    for(BitIdx=0;BitIdx<8;BitIdx++)
    {
     // get low level
     GetNextDelay(ArrayIn,&BitPointer,TotalBit);

     // get High level
     HighPulse = GetNextDelay(ArrayIn,&BitPointer,TotalBit);
  
     if(HighPulse < 5) return 0;
     if(HighPulse > 80) return 0;
     if(HighPulse > 43)
        ArrayOut[ByteIdx]|= Bits[BitIdx];
     }
   }
 return 1;
}









int main(int argc, char *argv[])
{
	int ret = 0;
	int fd;
        int loop;
        unsigned char checkSum;
        unsigned char ArrayOut[5];
        float Temperature,Humidity;

	fd = open("/dev/spidev0.0", O_RDWR);
	if (fd < 0)
		pabort("can't open device");

	/*
	 * spi mode
	 */

        mode = 0;
	ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
	if (ret == -1)
		pabort("can't set spi mode");

	ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
	if (ret == -1)
		pabort("can't get spi mode");

	/*
	 * bits per word
	 */
	ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
	if (ret == -1)
		pabort("can't set bits per word");

	ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
	if (ret == -1)
		pabort("can't get bits per word");

	/*
	 * max speed hz
	 */
	ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
	if (ret == -1)
		pabort("can't set max speed hz");

	ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
	if (ret == -1)
		pabort("can't get max speed hz");

        // use a array size fpr 10ms;
        int BitSize =  (int)  ( 0.010 * speed);

        int ArraySize =  BitSize / 8;

        int TotalBit = ArraySize * 8;



        unsigned char * Array= (unsigned char *) malloc(ArraySize);


        // need to have the 1.5 ms to 0
        int startOfRx = (int) (0.0015 * speed) / 8;
	memset(Array,0, startOfRx);
        memset(&Array[startOfRx],0xff, ArraySize-startOfRx);

        transfer(fd,Array, Array,ArraySize);


        if(DecodeArray(Array,ArrayOut,TotalBit))
        {
          checkSum=0;
          for(loop=0;loop<4;loop++)
            checkSum+=ArrayOut[loop];
          if(checkSum!=ArrayOut[4])
            printf("Checksum invalid\n");
          else
            {
              Temperature = ((int) (ArrayOut[2]&0x7f) * 256 + ArrayOut[3])/10.0;
              if((ArrayOut[2] & 0x80)== 0x80)
                 Temperature = -(Temperature);

              Humidity = ((int) ArrayOut[0]*256 + ArrayOut[1])/10.0;


              printf("Temperature = %5.1f Celsius\n",Temperature);
              printf("Humidity    = %5.1f %%\n",Humidity);

            }
        }
        else
         printf("Unable to read DHT22 sensor\n");
	close(fd);
        free(Array);
	return ret;
}

Glenn Gerrard
Posts: 1
Joined: Mon Apr 28, 2014 3:45 pm

Re: AM2301 with Raspberrypi - Issue, not working properly

Mon Apr 28, 2014 4:18 pm

Hi - I was able to get the sensor working with LOLDHT - but I can't seem to get the readings into a Google Spreadsheet. kepi - can you share the script you used to populate your spreadsheet?

Thanks,
Glenn

loggin
Posts: 2
Joined: Sat Dec 20, 2014 2:27 pm

Re: AM2301 with Raspberrypi - Issue, not working properly

Sat Dec 20, 2014 2:32 pm

.
Last edited by loggin on Sun Dec 21, 2014 2:45 pm, edited 1 time in total.

danjperron
Posts: 3531
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Re: AM2301 with Raspberrypi - Issue, not working properly

Sat Dec 20, 2014 8:46 pm

Hi loggin,

could you explain why is more reliable?

The SPI method is way more reliable! Try to run a process on the raspberry PI like "motion" with a webcam and try to read the sensor. It won't work if you use timing in user mode.

http://www.raspberrypi.org/forums/viewt ... 93#p657393

This is how the SPI method works!

Daniel

loggin
Posts: 2
Joined: Sat Dec 20, 2014 2:27 pm

Re: AM2301 with Raspberrypi - Issue, not working properly

Sun Dec 21, 2014 2:44 pm

Hi Daniel,
I agreed with you of course.Sorry for my mistake and I'm gonna try both methods in different cases.
Best regards!

Return to “Automation, sensing and robotics”