|
|
View previous topic :: View next topic |
Author |
Message |
Ruysho
Joined: 30 Sep 2014 Posts: 3
|
I2C and ADC not working |
Posted: Tue Sep 30, 2014 12:45 pm |
|
|
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
|
|
Posted: Tue Sep 30, 2014 12:55 pm |
|
|
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
|
|
Posted: Tue Sep 30, 2014 2:02 pm |
|
|
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
|
|
Posted: Thu Oct 02, 2014 11:04 am |
|
|
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
|
|
Posted: Thu Oct 02, 2014 11:37 am |
|
|
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
|
|
Posted: Thu Oct 02, 2014 12:40 pm |
|
|
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. |
|
|
|
|
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
|