|
|
View previous topic :: View next topic |
Author |
Message |
kel
Joined: 17 Oct 2005 Posts: 68 Location: Brisbane
|
pic16f877a ADC & External sensors |
Posted: Tue Feb 14, 2006 7:43 pm |
|
|
Guys what is wrong with following code?
I've a temperature sensor connected to PortA A0 and a potentiometer connected to A1.first I read the A0 AdC and delay for 20us and read ADC A1.
The problem is the value reading from the sensor is the same as the value reading from the potentiometer.If i avry the potentiometer, the values in both readin g vary.This is not suppose to be true as the two readings are different.
What is the problem?
Code: | Code:
#include <16f877a.h>
#device *=16
#device adc=10
#fuse HS,NOWDT,NOPROTECT,NOLVP,NOPUT
#use dleay(clock=20000000)
#include <lcd_driver.c>
#define Tr 0.35191 //potentiometer 1 revolution 360 degs // which is 0V & 1023 adc counts.
//Tr=360/1023 gives deg/adc_cnt
struct time {
int16 adcvals;
int16 deg_temp;
int16 adc_ang_val;
}global_adc={0,0,0};
void read_adc_vals(void);
#int_TBE
TBE_isr()
{
static int1 toggle=0;
if(toggle) {
toggle=0;
global_adc.adcvals=read_adc(ADC_READ_ONLY);
}
else {
toggle=1;
read_adc(ADC_START_ONLY);
}
}
#int_RDA
RDA_isr()
{
}
/*#int_TIMER0
TIMER0_isr()
{ //static int16 tick=0;
// tick+=256; // set_timer0(206); 20 mhz clock, no prescaler, set
timer 0 to overflow in 35us
// 256-(.001024/(4*256/20000000))
}*/
void main()
{
//char cnt;
setup_adc_ports(ALL_ANALOG);
setup_adc(ADC_CLOCK_DIV_32); //ADC_CLOCK_INTERNAL//SET adc conversion clock speed
//TAD(per bit)=1/20Mhz X 32 = 0.16us ;Requires min. 12 TAD for 10 bit
//Min. conversion time approx. 2us
//set_adc_channel(0); //Set ADC channel to port0(pin 2,AN0).
//setup_timer_0(RTCC_INTERNAL|RTCC_DIV_2);
// setup_psp(PSP_DISABLED);setup_spi(FALSE);setup_timer_1(T1_DISABLED);setup_timer_2(T2_DISABLED,0,1);
// setup_comparator(NC_NC_NC_NC);setup_vref(FALSE);
enable_interrupts(INT_AD);/ enable_interrupts NT_TBE);enable_interrupts(INT_RDA);
lcd_init();
// enable_interrupts(INT_TIMER0);
enable_interrupts(GLOBAL); //printf("Sampling adc"
lcd_gotoxy(2,1);
lcd_putc("\fSampling....");
delay_ms(1000);
lcd_putc("\f");
while(1)
{
read_adc_vals();
delay_ms(200);
}
}
void read_adc_vals(void){
static int32 avgvalz;
static int16 adcvalz;
static int16 adcarr[10];
signed int8 cnt;
static float angul_deg;
set_adc_channel(0); //set channel to channel0
/*this loops are used to give smoother temperature*/
for(cnt=0; cnt<10; cnt++)
{
adcarr[cnt]=global_adc.adcvals;
}
avgvalz=0;
for(cnt=0; cnt<10; cnt++)
{
avgvalz +=adcarr[cnt];
}
delay_us(20);
set_adc_channel(1);
global_adc.adc_ang_val=read_adc();
/*Arithmatic calculations here*/
adcvalz=avgvalz/10; //taking the averages values of temps
global_adc.deg_temp = ((adcval - 559L)/2); //temperatures in deg
angul_deg=(global_adc.adc_ang_val*Tr); //Tr=360/1023
/*Print the results to the lcd display am using lcd*/
lcd_gotoxy(8, 1);
printf(LCD_PUTC," %04lu %02Lu\n\r",adcvalz,global_adc.deg_temp);
lcd_gotoxy(8, 2);
printf(LCD_PUTC," %04lu %Lu\n\r",global_adc.adc_ang_val,angul_deg);
} |
Guys help me out.Have a look at my code and help me fight the virus of stupidity.I've tried to find the bug the whole of last night but did not succeed.I'm delighted there alot of bright & highly intelligent & highly experienced people in this forum...Hope i'm not wrong.
Have anyone ever done it before?? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Feb 14, 2006 9:39 pm |
|
|
The reason no one has replied is because, in part, your code doesn't
even match your description.
Here you say:
Quote: |
I've a temperature sensor connected to PortA A0 and a potentiometer
connected to A1. First I read the A0 AdC and delay for 20us and
read ADC A1. |
No you don't.
What does your code do ? It does this:
1. You select channel 0.
2. Then you do some kind of delay loop.
3. Then you wait 20 us.
4. Then you select channel 2.
5. Then you read the A/D (for channel 2).
So does that match your description ? No way. Your code never
reads A/D channel 0.
Also, you apparently saw this thread, in which it's explained that
you need to a 20 us delay after switching the A/D channel.
http://www.ccsinfo.com/forum/viewtopic.php?t=25963
The problem is that you don't understand that lines of C code
are executed sequentially and that the order matters, and that
you can't just randomly drop in lines of code and expect things to work.
In your code, you do the 20 us delay before switching the channel.
That's the total opposite of what is shown in that thread.
That, plus the fact that you're doing some really strange stuff like
putting A/D code inside your UART's transmit interrupt service routine,
is what puts people off from answering your posts. |
|
|
kel
Joined: 17 Oct 2005 Posts: 68 Location: Brisbane
|
Sorry pcm programmer, stupid me.. |
Posted: Tue Feb 14, 2006 10:13 pm |
|
|
Thanks you thank you...I deleted the right interrupt subroutine and place the code wrongly on the uart interrupt subroutine!! I will be careful next time..
I have added the suggested correct steps and will test it shorlty and i will also let you of the progress...
This is what i had originally..
Code: | #include <16f877a.h>
#device *=16
#device adc=10
#fuse HS,NOWDT,NOPROTECT,NOLVP,NOPUT
#use dleay(clock=20000000)
#include <lcd_driver.c>
#define Tr 0.35191 //potentiometer 1 revolution 360 degs // which is 0V & 1023 adc counts.
//Tr=360/1023 gives deg/adc_cnt
struct time {
int16 adcvals;
int16 deg_temp;
int16 adc_ang_val;
}global_adc={0,0,0};
void read_adc_vals(void);
#int_AD
AD_isr()
{
static int1 toggle=0;
if(toggle) {
toggle=0;
global_adc.adcvals=read_adc(ADC_READ_ONLY);
}
else {
toggle=1;
read_adc(ADC_START_ONLY);
}
}
void main()
{
//char cnt;
setup_adc_ports(ALL_ANALOG);
setup_adc(ADC_CLOCK_DIV_32); //ADC_CLOCK_INTERNAL//SET adc conversion clock speed
//TAD(per bit)=1/20Mhz X 32 = 0.16us ;Requires min. 12 TAD for 10 bit
//Min. conversion time approx. 2us
//set_adc_channel(0); //Set ADC channel to port0(pin 2,AN0).
//setup_timer_0(RTCC_INTERNAL|RTCC_DIV_2);
// setup_psp(PSP_DISABLED);setup_spi(FALSE);setup_timer_1(T1_DISABLED);setup_timer_2(T2_DISABLED,0,1);
// setup_comparator(NC_NC_NC_NC);setup_vref(FALSE);
enable_interrupts(INT_AD);/ enable_interrupts NT_TBE);enable_interrupts(INT_RDA);
lcd_init();
// enable_interrupts(INT_TIMER0);
enable_interrupts(GLOBAL); //printf("Sampling adc"
lcd_gotoxy(2,1);
lcd_putc("\fSampling....");
delay_ms(1000);
lcd_putc("\f");
while(1)
{
read_adc_vals();
delay_ms(200);
}
}
void read_adc_vals(void){
static int32 avgvalz;
static int16 adcvalz;
static int16 adcarr[10];
signed int8 cnt;
static float angul_deg;
set_adc_channel(0); //set channel to channel0
delay_us(20);
/*this loops are used to give smoother temperature*/
for(cnt=0; cnt<10; cnt++)
{
adcarr[cnt]=global_adc.adcvals;
}
avgvalz=0;
for(cnt=0; cnt<10; cnt++)
{
avgvalz +=adcarr[cnt];
}
set_adc_channel(1);
delay_us(20);
global_adc.adc_ang_val=read_adc();
/*Arithmatic calculations here*/
adcvalz=avgvalz/10; //taking the averages values of temps
global_adc.deg_temp = ((adcval - 559L)/2); //temperatures in deg
angul_deg=(global_adc.adc_ang_val*Tr); //Tr=360/1023
/*Print the results to the lcd display am using lcd*/
lcd_gotoxy(8, 1);
printf(LCD_PUTC," %04lu %02Lu\n\r",adcvalz,global_adc.deg_temp);
lcd_gotoxy(8, 2);
printf(LCD_PUTC," %04lu %Lu\n\r",global_adc.adc_ang_val,angul_deg);
} |
I have the following questions:
Do i really need to start the adc as shown in the following code posted earlier by Tlemah coz i have seen some other codes on the forum including one of yours not showing it either?
Code: | AD_isr()
{
static int1 toggle=0;
if(toggle) {
toggle=0;
global_adc.adcvals=read_adc(ADC_READ_ONLY);
}
else {
toggle=1;
read_adc(ADC_START_ONLY);
}
} |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Feb 14, 2006 10:29 pm |
|
|
My advise for you is to do things in the most simple way possible.
Don't use the A/D isr. Don't use ADC_READ_ONLY, etc.
All those things are for intermediate-to-advanced CCS programmers.
Just use plain old read_adc().
Do all your A/D reading this way:
Code: |
int16 result;
set_adc_channel(0); // Select channel
delay_us(20); // Wait for 20 us
result = read_adc(); // Read the A/D
|
|
|
|
kel
Joined: 17 Oct 2005 Posts: 68 Location: Brisbane
|
I don't understand!! |
Posted: Tue Feb 14, 2006 10:45 pm |
|
|
Thank you programmer the code work now when i make the following changes:
void read_adc_vals(void){
static int32 avgvalz;
static int16 adcvalz;
static int16 adcarr[10];
signed int8 cnt;
static float angul_deg;
set_adc_channel(0); //set channel to channel0
delay_us(20);
/*this loops are used to give smoother temperature*/
for(cnt=0; cnt<10; cnt++)
{
Quote: | adcarr[cnt]=read_adc();//global_adc.adcvals; ??????? |
}
avgvalz=0;
for(cnt=0; cnt<10; cnt++)
{
avgvalz +=adcarr[cnt];
}
adcvalz=avgvalz/10; //taking the averages values of temps
set_adc_channel(1);
delay_us(20);
global_adc.adc_ang_val=read_adc Quote: | ();//global_adc.adcvals;?? |
/*Arithmatic calculations here*/
global_adc.deg_temp = ((adcval - 559L)/2); //temperatures in deg
angul_deg=(global_adc.adc_ang_val*Tr); //Tr=360/1023
/*Print the results to the lcd display am using lcd*/
lcd_gotoxy(8, 1);
printf(LCD_PUTC," %04lu %02Lu\n\r",adcvalz,global_adc.deg_temp);
lcd_gotoxy(8, 2);
printf(LCD_PUTC," %04lu %Lu\n\r",global_adc.adc_ang_val,angul_deg);
}
I have the following questions:
why?
does the adc value get corrupted? |
|
|
kel
Joined: 17 Oct 2005 Posts: 68 Location: Brisbane
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Feb 14, 2006 11:00 pm |
|
|
They didn't realize what they were doing. |
|
|
Ttelmah Guest
|
|
Posted: Wed Feb 15, 2006 6:45 am |
|
|
In fact if you read the thread, it was suggested that if all he wanted to do, was read the ADC, then it was much better to switch to just using the default behaviour. The problem was that he arrived with a set of code, doing things in about as complex way as possible (using ADC interrupts), which seemed to suggest that he wanted to read the ADC, very rapidly, and synchronously to a clock event. Hence a whole load of code versions were suggested doing this. Then gradually it became more and more clear that this was not the target.
This is now the fourth thread, he has run for this code, and in each, he has got other people to do a little more, but does not actually seem to solve things much himself...
Best Wishes |
|
|
kel
Joined: 17 Oct 2005 Posts: 68 Location: Brisbane
|
Telmah many thanks... |
Posted: Wed Feb 15, 2006 7:45 pm |
|
|
You are right,i've not tried long enough to seek for help.I'm a beginner and will try next time hard enough and will seek for help if i fail completely.This way, i will be able to learn understand and help others too.
My previous suggest that i should have someone actually posting the actual codes for read_adc(),set_up_adc(),setup_adc_channel(),adc_interrupt etc for me to understand them on how they are setup...
thanks again,you have always help me with my codes.
cheers mate.
|
|
|
Ttelmah Guest
|
|
Posted: Thu Feb 16, 2006 5:22 am |
|
|
There is a problem here. CCS, try in many ways to 'remove' you from the hardware. So you can (for example), just make the read_adc call, and have no idea about what is really going on below the skin. Realistically the best place for this data, is the chip's data sheet, and the application notes from MicroChip. The data sheet, really is essential reading. If you look at a daa sheet, and select the section on the ADC (I have just opened the one for the 18Fxx2 for example), you find a section giving the control 'flow' needed to handle the ADC.
Now if you look at this, you can then get an idea of what the various C instructions actually 'do'.
It starts by saying:
'configure analog pins, voltage reference, and digital I/O'. This is the 'SETUP_ADC_PORTS' instruction.
Then it goes on to say 'select ADC channel' - the 'set_ADC_CHANNEL' instruction.
Then it says 'select ADC conversion clock' - 'setup_adc'
Then it says 'turn on the ADC module'. This is automatically done for you by the compiler as part of the setup_adc instruction.
Now it then moves on to 'waiting for the acquisition time'(this is explained slightly latter in the section, including details of how to calculate it for a given hardware - this is the stage, most commonly forgotten!.
Then it says 'start the conversion'.
Next section, then says 'wait for the conversion to complete'
Then 'read the result'.
Now the read_adc function, automatically performs all three of these sections for you, _unless you specifically 'ask' it to do them seperately_. As for why you'd want to do them seperately?. This avoids having to sit waiting for the conversion to complete. So you can trigger a start, and then go away, and do something else, then read the value, without any delays.
Now the 'logic' of the function in this regard, only really becomes obvious when you read the data sheet.
However the simple use of the adc, without this complexity, is best seen by looking in the examples. EX_ADMM10.C, shows a simple example of reading an ADC, letting CCS do all the work, and averaging the results.
Best Wishes |
|
|
|
|
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
|