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

I2C and ADC not working

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Ruysho



Joined: 30 Sep 2014
Posts: 3

View user's profile Send private message

I2C and ADC not working
PostPosted: Tue Sep 30, 2014 12:45 pm     Reply with quote

Greetings!
I'm using a PIC 18F4550 for a project which consists on a voltage read provided by a potentiometer connected to AN0 and a digital temperature provided by a TMP101 connected via I2C.
The PIC should read the pot (AN0) and send the result through the serial port, then read 2 bytes from the TMP101 and send both through serial port. Finally, the process must be repeated ad eternum.
Problem is, the program stucks after sending the pot reading and I can't figure out why; any help or advice would be really appreciated.
The code I used is based on examples found in the CCS IDE help files and this forum.
Code:

#include <18F4550.h>
#DEVICE adc=8
#use delay(crystal=20000000)
#use i2c(master, sda=PIN_B0, scl=PIN_B1)
#use rs232(baud=9600, bits=8,parity=N, stop=1, xmit=PIN_C6, rcv=PIN_C7)
#fuses hs,nowdt,noput,nobrownout,nolvp,noprotect,nomclr
#include <stdlib.h>

void main (void)
{
char reading;//adc result
char temp_l=0;//temp low byte
char temp_h=0;//temp high byte

setup_adc_ports(AN0);
setup_adc_ports(VSS_VDD);

while(1)
{
//=========================
//Analog input 0 reading
//=========================
setup_adc(ADC_CLOCK_INTERNAL);
set_adc_channel(0);
read_adc(ADC_START_ONLY);
while(!adc_done())
{}
delay_us(100);
reading=read_adc(ADC_READ_ONLY);
setup_adc(ADC_OFF);
putc(reading);
delay_ms(500);
putc('\n');

//=========================================================
//TMP101 config (12 bits temp reading)
//=========================================================
i2c_start();
i2c_write(0x90);//write
i2c_write(0x01);//0x01= config register
i2c_stop();

i2c_start();
i2c_write(0x90);//write
i2c_write(0x60);//12 bits temp reading
i2c_stop();

//=========================================================
//TMP101 temp reading(dir =0b1001000 ADD= 0V)
//=========================================================
while(1){
i2c_start();
i2c_write(0x90);//write
i2c_write(0x00);//0x00= temp reading register
i2c_stop();

i2c_start();
i2c_write(0x91);//read
temp_l=i2c_read();//read low byte
temp_h=i2c_read();//read high byte
i2c_stop();

delay_ms(50);
putc(temp_l);
delay_ms(50);
putc(temp_h);
delay_ms(500);
putc('\n');
}//while ends here

}//main ends here

PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Sep 30, 2014 12:55 pm     Reply with quote

Quote:
Problem is, the program stucks after sending the pot reading


You need to do a NAK on the last read. This is part of the i2c spec.
See the 0x00 parameter in bold below:
Quote:
i2c_start();
i2c_write(0x91);//read
temp_l=i2c_read();//read low byte
temp_h=i2c_read(0);//read high byte ***Do a NAK on last read
i2c_stop();



Quote:
read_adc(ADC_START_ONLY);
while(!adc_done())
{}
delay_us(100);
reading=read_adc(ADC_READ_ONLY);
setup_adc(ADC_OFF);

The above code is hugely over-complicated. You could do it with 2 lines.
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Tue Sep 30, 2014 2:02 pm     Reply with quote

Just a few other tiny comments for improvement:

The program doesn't compile because it is missing a terminating '}' in one of the while loops.

The program lacks indentation making it more difficult to read and error prone.

Why so many delay calls?

... but the one required delay call before the ADC call is missing.

Code:
#use delay(crystal=20000000)
These are many zeroes. You wouldn't be the first to mistype one, that's why I like:
Code:
#use delay(crystal=20MHz)


Code:
char temp_l=0;//temp low byte
char temp_h=0;//temp high byte
Great that you add comments to your code, but unnecessary when you write:
Code:
byte temperature_low=0;
byte temperature_high=0;
This also makes a better distinction between a 'temp'orary variable and 'temp'erature variable.
Ruysho



Joined: 30 Sep 2014
Posts: 3

View user's profile Send private message

PostPosted: Thu Oct 02, 2014 11:04 am     Reply with quote

Sorry for taking so long to respond. My project was halted for a while in the workshop.
I've tried doing a NACK in the last I2C read, however, the program still won't make it past that point.
I reviewed some of the hints ckielstra pointed and the code had an extra while(1) which was unintended. Also indented the code a bit, renamed some variables and erased some unnecessary comments.
The code ended looking like this:
Code:

#include <18F4550.h>
#DEVICE adc=8
#use delay(crystal=20MHz)
#use i2c(master, sda=PIN_B0, scl=PIN_B1)
#use rs232(baud=9600, bits=8,parity=N, stop=1, xmit=PIN_C6, rcv=PIN_C7)
#fuses hs,nowdt,noput,nobrownout,nolvp,noprotect,nomclr
#include <stdlib.h>

void main (void)
{

char reading;//adc result
char temperature_l=0;
char temperature_h=0;
//=========================================================
//ADC config
//=========================================================
setup_adc_ports(AN0);
setup_adc_ports(VSS_VDD);
setup_adc(ADC_CLOCK_INTERNAL);

//=========================================================
//TMP101 config (12 bits temperature reading)
//=========================================================
i2c_start();
i2c_write(0x90);//write
i2c_write(0x01);//0x01= config register
i2c_stop();
i2c_start();
i2c_write(0x90);//write
i2c_write(0x60);//12 bits temp reading
i2c_stop();


while(1)
{
   //=========================
   //Analog input 0 reading
   //=========================
   set_adc_channel(0);
   delay_us(20);
   reading=read_adc();
   putc(reading);
   putc('\n');
   delay_ms(500);

   //=========================================================
   //TMP101 temp reading(dir =0b1001000 with ADD= 0V)
   //=========================================================
   i2c_start();
   i2c_write(0x90);//write
   i2c_write(0x00);//0x00= temperature reading register
   i2c_stop();
   
   delay_ms(350);
   
   i2c_start();
   i2c_write(0x91);//read
   temperature_l=i2c_read();//read low byte
   temperature_h=i2c_read(0);//read high byte NACK done
   i2c_stop();

   putc(temperature_l);
   putc(temperature_h);
   delay_ms(500);
   putc('\n');

}//while ends here

}//main ends here


Silly question? Do I need to set the pins in some way before using i2c or does the #use i2c directive take care of all the required pin settings?
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Oct 02, 2014 11:37 am     Reply with quote

Quote:
setup_adc_ports(AN0);
setup_adc_ports(VSS_VDD);

This function doesn't work with cumulative sequential calls. Only the
last one will take effect. Look at the setup_adc_ports() parameters
in the 18F4550.h file. You are setting up the PIC pins as "All Analog"
which is not what you want. The separator between parameters in
this function is a comma.

#use i2c() takes care of the TRIS.

Do you have pullup resistors on SDA and SCL ? You need them for i2c.
Ruysho



Joined: 30 Sep 2014
Posts: 3

View user's profile Send private message

PostPosted: Thu Oct 02, 2014 12:40 pm     Reply with quote

Found the problem at last.
As PCM programmer stated, I was setting all available analog inputs. The pins used for SDA and SCL (B0 and B1) are among these, so I inadvertently overrided any configuration #use i2c made.
The last version of the project included a second potentiometer conected to AN1. The resulting code is as follows:
Code:

#include <18F4550.h>
#DEVICE adc=8
#use delay(crystal=20MHz)
#use i2c(master, sda=PIN_B0, scl=PIN_B1)
#use rs232(baud=9600, bits=8,parity=N, stop=1, xmit=PIN_C6, rcv=PIN_C7)
#fuses hs,nowdt,noput,nobrownout,nolvp,noprotect,nomclr
#include <stdlib.h>

void main (void)
{

char reading;//adc result
char temperature_l=0;
char temperature_h=0;
//=========================================================
//ADC config
//=========================================================
setup_adc_ports(AN0_TO_AN1,VSS_VDD);
setup_adc(ADC_CLOCK_INTERNAL);

//=========================================================
//TMP101 config (12 bits temperature reading)
//=========================================================
i2c_start();
i2c_write(0x90);//write
i2c_write(0x01);//0x01= config register
i2c_stop();
i2c_start();
i2c_write(0x90);//write
i2c_write(0x60);//12 bits temp reading
i2c_stop();

while(1)
{
   //=========================
   //Analog input 0 reading
   //=========================
   set_adc_channel(0);
   delay_us(20);
   reading=read_adc();
   putc(reading);
   putc('\n');
   delay_ms(500);
   
   //=========================
   //Analog input 1 reading
   //=========================
   set_adc_channel(1);
   delay_us(20);
   reading=read_adc();
   putc(reading);
   putc('\n');
   delay_ms(500);
   
   //=========================================================
   //TMP101 temp reading(dir =0b1001000 with ADD= 0V)
   //=========================================================
   i2c_start();
   i2c_write(0x90);//write
   i2c_write(0x00);//0x00= temperature reading register
   i2c_stop();
   
   //delay_ms(350);
   
   i2c_start();
   i2c_write(0x91);//read
   temperature_l=i2c_read();//read low byte
   temperature_h=i2c_read(0);//read high byte NACK done
   i2c_stop();

   putc(temperature_l);
   putc(temperature_h);
   delay_ms(500);
   putc('\n');

}//while ends here

}//main ends here

Thank you all for your aid. Your help is greatly appreciated.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion 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