CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

AM2320 I2C Relative Humidity and Temperature Sensor Driver

 
Post new topic   Reply to topic    CCS Forum Index -> Code Library
View previous topic :: View next topic  
Author Message
sshahryiar



Joined: 05 May 2010
Posts: 94
Location: Dhaka, Bangladesh

View user's profile Send private message Send e-mail Visit poster's website

AM2320 I2C Relative Humidity and Temperature Sensor Driver
PostPosted: Sat May 16, 2015 9:08 pm     Reply with quote

AM2320.h

Code:
#define AM2320_address 0xB8
#define I2C_write_cmd 0x00
#define I2C_read_cmd 0x01
   
#define AM2320_read_sensor_data 0x03
#define AM2320_write_multiple_registers 0x10

#define AM2320_RH_hb 0x00       
#define AM2320_RH_lb 0x01
#define AM2320_T_hb 0x02
#define AM2320_T_lb 0x03

                               
unsigned char data_buffer[8]; 


#use I2C(MASTER, SDA = pin_B7, SCL = pin_B6)       


void AM2320_init();
void AM2320_write(unsigned char *value, unsigned char length);
void AM2320_read(unsigned char *value, unsigned char length);
unsigned long CRC16(unsigned char *ptr, unsigned char length);
void get_sensor_data(unsigned char start_address, unsigned char input_length, unsigned char output_length);
void get_RH_and_temperature(unsigned long *data1, signed long *data2);
void get_CRC(unsigned long *CRC_data);



AM2320.c

Code:
#include "AM2320.h"


void AM2320_init()
{
     unsigned char s = 0;
     
     for(s = 0; s< 8; s++)
     {
           data_buffer[s] = 0x00;
     }               
}             


void AM2320_write(unsigned char *value, unsigned char length)
{
     unsigned char s = 0x00;
     
     I2C_Start();
     I2C_Write(AM2320_address + I2C_write_cmd);
     
     for(s = 0x00; s < length; s++)
     {
           I2C_Write(*value++);
     }
     
     I2C_Stop();
}


void AM2320_read(unsigned char *value, unsigned char length)
{
     unsigned char s = 0x00;

     I2C_Start();
     I2C_Write(AM2320_address + I2C_read_cmd);
     
     for(s = 0x00; s < length; s++)
     {
         value[s] = I2C_read(1);
     }
     
     I2C_Stop();
}

           
unsigned long CRC16(unsigned char *ptr, unsigned char length)
{
      unsigned long crc = 0xFFFF;
      unsigned char s = 0x00;

      while(length--)
      {
        crc ^= *ptr++;
        for(s = 0; s < 8; s++)
        {
          if((crc & 0x01) != 0)
          {
            crc >>= 1;
            crc ^= 0xA001;
          }
          else
          {
            crc >>= 1;
          }
        }
      }

      return crc;
}


void get_sensor_data(unsigned char start_address, unsigned char input_length, unsigned char output_length)
{
     unsigned char s = 0x00;

     AM2320_write(0x00, 0x00);
     delay_us(1600);

     data_buffer[0] = AM2320_read_sensor_data;
     data_buffer[1] = start_address;
     data_buffer[2] = input_length;

     AM2320_write(data_buffer, 0x03);
     delay_us(1499);

     for(s = 0x00; s < output_length; s++)
     {
         data_buffer[s] = 0x00;
     }

     AM2320_read(data_buffer, output_length);
}


void get_RH_and_temperature(unsigned long *data1, signed long *data2)
{
     *data1 = ((unsigned long)((data_buffer[2] << 8) | data_buffer[3]));
     *data2 = ((data_buffer[4] << 8) | data_buffer[5]);
}


void get_CRC(unsigned long *CRC_data)
{
     *CRC_data = ((unsigned long)((data_buffer[7] << 8) | data_buffer[6]));
}   

_________________
https://www.facebook.com/MicroArena

SShahryiar
nuclear__



Joined: 24 Jan 2015
Posts: 63

View user's profile Send private message

call from main
PostPosted: Mon Mar 21, 2016 1:27 pm     Reply with quote

Hi
Can you give us an example on how you read values from main?
sshahryiar



Joined: 05 May 2010
Posts: 94
Location: Dhaka, Bangladesh

View user's profile Send private message Send e-mail Visit poster's website

AM2320 Relative Humidity and Temperature Sensor
PostPosted: Mon Mar 21, 2016 8:37 pm     Reply with quote

I used the same code as here but in a AT89S51. Please check the example here:

http://libstock.mikroe.com/projects/view/1331/am2320-relative-humidity-and-temperature-sensor-demo

Check out the demo video too:

https://youtu.be/EtP_Zcv0Hec
_________________
https://www.facebook.com/MicroArena

SShahryiar
nuclear__



Joined: 24 Jan 2015
Posts: 63

View user's profile Send private message

PostPosted: Tue Mar 22, 2016 5:48 am     Reply with quote

Ok, I will try to work with that. Thank you !
nuclear__



Joined: 24 Jan 2015
Posts: 63

View user's profile Send private message

PostPosted: Sun Mar 27, 2016 5:15 am     Reply with quote

Hi

I tried this but it doesn't work well.

Can you tell what is wrong?
Code:

if (!strcmp(usb_buffer,sensors)) {
            get_sensor_data(AM2320_RH_hb, 0x04, 0x08);
            get_RH_and_temperature(*RH, *T);
            get_CRC(*CRC_temp);
            CRC_data = crc16(data_buffer, 6);
            if(CRC_temp == CRC_data)
             {                 
                  printf(usb_cdc_putc,"\n\rcrc fail\r\n");
             }
             else
             {
                  printf(usb_cdc_putc,"\n\rcrc ok\r\n");
             }
            printf(usb_cdc_putc,"\n\rRH: %u T: %d crc:  \r\n",*RH,*T);
            clear_usb_buffer();         
         }
sshahryiar



Joined: 05 May 2010
Posts: 94
Location: Dhaka, Bangladesh

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Sun Mar 27, 2016 7:02 am     Reply with quote

Did you get any error message? What do you mean by "doesn't work well"?
_________________
https://www.facebook.com/MicroArena

SShahryiar
nuclear__



Joined: 24 Jan 2015
Posts: 63

View user's profile Send private message

PostPosted: Sun Mar 27, 2016 7:28 am     Reply with quote

sshahryiar wrote:
Did you get any error message? What do you mean by "doesn't work well"?
no error message. I get negative temp and humidity value around 20.which are totally wrong ( they should be +20 and 60%). When i heat them i can see values change however.
sshahryiar



Joined: 05 May 2010
Posts: 94
Location: Dhaka, Bangladesh

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Sun Mar 27, 2016 8:11 am     Reply with quote

It could be due to wrong variable type.... You need to be careful with pointers too....
_________________
https://www.facebook.com/MicroArena

SShahryiar
sshahryiar



Joined: 05 May 2010
Posts: 94
Location: Dhaka, Bangladesh

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Sun Mar 27, 2016 8:12 am     Reply with quote

What about the humidity data? Is it also negative?
_________________
https://www.facebook.com/MicroArena

SShahryiar
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Mar 27, 2016 8:22 am     Reply with quote

Quote:

I get negative temp and humidity value around 20, which are totally wrong.

That's because you didn't follow his example code in this link:
http://libstock.mikroe.com/projects/download/1331/0/1331_am2320_relative_humidity_and_temperature_sensor_demo_v1.0.0.0.zip

You have used incorrect parameters in your code below:
Quote:

if (!strcmp(usb_buffer,sensors)) {
get_sensor_data(AM2320_RH_hb, 0x04, 0x08);
get_RH_and_temperature(*RH, *T);
get_CRC(*CRC_temp);

His code is shown below. Notice how he passes the address of the
variables by putting an '&' in front of the variable name.
Code:
get_RH_and_temperature(&RH, &T);
get_CRC(&CRC_temp);


Also in his MikroC code, he has these declarations:
Quote:

signed int T = 0x0000;
unsigned int RH = 0x0000;
unsigned int CRC_data = 0x0000;
unsigned int CRC_temp = 0x0000;

Did you correctly translate these to CCS ? The correct translation is:
Code:

signed int16 T = 0x0000;
unsigned int16 RH = 0x0000;
unsigned int16 CRC_data = 0x0000;
unsigned int16 CRC_temp = 0x0000;

That's because in the CCS PCH compiler an 'int' is 8-bits, but in MikroC
an 'int' is 16-bits, so you have to use 'int16' in CCS code.
MikroC data types:
http://www.mikroe.com/download/eng/documents/compilers/mikroc/pro/pic/help/arithmetic_types.htm
CCS data types are listed in the CCS manual.

In the code below, you are printing RH and T as if they are pointers to
8-bit values. That's wrong. They are variables holding the data.
Quote:

printf(usb_cdc_putc,"\n\rRH: %u T: %d crc: \r\n",*RH,*T);

The correct line is shown below. This line uses %lu and %ld to print
16-bit values, and RH and T are given as the parameters:
Code:
   printf(usb_cdc_putc,"\n\rRH: %lu T: %ld crc:  \r\n", RH, T);


Last edited by PCM programmer on Sat Apr 16, 2016 6:22 pm; edited 1 time in total
nuclear__



Joined: 24 Jan 2015
Posts: 63

View user's profile Send private message

PostPosted: Sun Mar 27, 2016 9:37 am     Reply with quote

about & and not *, i had already test that too, but combining & with printf(usb_cdc_putc,"\n\rRH: %lu T: %ld crc: \r\n", RH, T); looks promising.

variables where correctly defined like you say.

however i get T up to 255 while heating which must be 25.5 .
i will try to figure out by myself some things and come back later.

Thanks at the moment
sshahryiar



Joined: 05 May 2010
Posts: 94
Location: Dhaka, Bangladesh

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Sun Mar 27, 2016 9:58 am     Reply with quote

You are getting 255 instead of 25.5 because in my MikroC example I avoided floating point math and instead used integral math to conserve RAM....
_________________
https://www.facebook.com/MicroArena

SShahryiar
nuclear__



Joined: 24 Jan 2015
Posts: 63

View user's profile Send private message

PostPosted: Mon Mar 28, 2016 8:05 am     Reply with quote

Something is wrong again
Below are the measurements i get while heating it.
enviromental measurements are around 20C and 50%.

RH: 175 T: 205
RH: 199 T: 236
RH: 111 T: 12
RH: 43 T: 45
RH: 18 T: 68
RH: 230 T: 85

It looks like it lose high byte or if it was byte variable.

however they are not
Code:
unsigned int16 RH = 0x0000;
unsigned int16 CRC_data = 0x0000;
unsigned int16 CRC_temp = 0x0000;
signed int16 T = 0x0000;
...........
if (!strcmp(usb_buffer,sensors)) {
            get_sensor_data(AM2320_RH_hb, 0x04, 0x08);
            get_RH_and_temperature(&RH,&T);
            get_CRC(&CRC_temp);
            CRC_data = crc16(data_buffer, 6);
            if(CRC_temp == CRC_data)
             {                 
                  printf(usb_cdc_putc,"\n\rcrc fail\r\n");
             }
             else
             {
                  printf(usb_cdc_putc,"\n\rcrc ok\r\n");
             }
            printf(usb_cdc_putc,"\n\rRH: %lu T: %ld crc:  \r\n",RH,T);
            clear_usb_buffer();

I'm not familiar with pointers and indicators and some of the programming technics you use to fully understand drivers. Any tip is appreciated!
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon Mar 28, 2016 7:29 pm     Reply with quote

Quote:
Something is wrong again
Below are the measurements i get while heating it.
It looks like it lose high byte or if it was byte variable

Sometimes the data can be garbled if the i2c protocol is not followed.
I have seen this happen with eeprom chips, in the following case:

The AM2320 data sheet says you should do a NACK on the last i2c read.
The AM2320_read() function posted in this thread is not doing the NACK.

Look at Figure 17 on page 18 of the AM2320 data sheet. On the right side
of the timing diagram it shows reading the last byte. It shows "0xFE + NACK".
https://akizukidenshi.com/download/ds/aosong/AM2320.pdf

See the modified read routine shown below. It checks inside the for()
loop for the last i2c_read(). On the last one, it does a NACK instead
of an ACK. Try substituting this routine and see if it solves your problem:
Code:

void AM2320_read(unsigned char *value, unsigned char length)
{
unsigned char s = 0x00;

I2C_Start();

I2C_Write(AM2320_address + I2C_read_cmd);
     
for(s = 0x00; s < length; s++)
   {
    if(s == length-1)  // Is this the last read ?
       value[s] = I2C_read(0);  // If so, do a Nack
    else
       value[s] = I2C_read(1);  // If not, do an Ack
   }
     
I2C_Stop();
}


For another example of this, look at the sample code here:
https://github.com/nodemcu/nodemcu-firmware/blob/dev/app/modules/am2320.c
Look at this section:
Quote:
// step 3: Read the data

Part of the code is shown below. It reads bytes in the for() loop, then
it reads the two CRC bytes. It does a NACK on the last crc byte because
it's the last i2c read operation. You can see it's a NACK because the
2nd parameter on that byte is a 0:
Quote:
for(i=0; i<len+2; i++)
b[i] = platform_i2c_recv_byte(id,1);

crc = platform_i2c_recv_byte(id,1);
crc |= platform_i2c_recv_byte(id,0) << 8;
platform_i2c_send_stop(id);
nuclear__



Joined: 24 Jan 2015
Posts: 63

View user's profile Send private message

PostPosted: Tue Mar 29, 2016 7:27 am     Reply with quote

Good catch, however it has exactly the same behaviour.
Readings rise up to 255 and then start from zero. If i still heat it, it goes again up to 255 and back to zero again.

I added 2 more print lines to get buffer[2..5] values, inside get_RH_and_temperature function. Problem is obvious now.
That's what i get while heating:

buf2:1 buf3:46 buf4:1 buf5:35
RH:46 T:35

buf2:0 buf3:151 buf4:1 buf5:147
RH:151 T:147

buf2:0 buf3:79 buf4:2 buf5:11
RH:79 T:11

So the problem is here
Code:

void get_RH_and_temperature(unsigned long *data1, signed long *data2)
{
     *data1 = ((unsigned long)((data_buffer[2] << 8) | data_buffer[3]));
     *data2 = ((data_buffer[4] << 8) | data_buffer[5]);
     printf(usb_cdc_putc,"\n\rbuf2: %u buf3: %u \r\n",data_buffer[2],data_buffer[3]);
     printf(usb_cdc_putc,"\n\rbuf4: %u buf5: %u \r\n",data_buffer[4],data_buffer[5]);
}

These 2 lines
*data1 = ((unsigned long)((data_buffer[2] << 8) | data_buffer[3]));
*data2 = ((data_buffer[4] << 8) | data_buffer[5]);

I replaced them with these
Code:

void get_RH_and_temperature(unsigned int16 *data1, signed int16 *data2)
{
     *data1=make16(data_buffer[2], data_buffer[3]);
     *data2=make16(data_buffer[4], data_buffer[5]);
}

and now works
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> Code Library All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group