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

What is wrong with this ADC code?

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







What is wrong with this ADC code?
PostPosted: Mon Feb 07, 2005 3:04 pm     Reply with quote

Folks -
Here is a simple snippet of code I use to grab data from the ADC on a 16F877A part. Actually, from the main code I sequentially grab data from ADC channels 0, 1, and 2 by passing the appropriate ADC_channel. For debugging, I added the variable "dummy" to the function and used an ICD to monitor the values of "ADC_channel" and "dummy." The real-time voltages of the analog inputs is about 1.6 to 1.7V using a 3.3V reference. And, these voltages don't vary - except for noise in the mV range - during my ADC acquisition. This gives me typical "dummy" values from 490 to 520 or so, as expected. So far, so good.

Every once in a while for the very first "dummy" value (i = 1) when ADC_channel = 1, the value of "dummy" is "0" or 32,000 or something like this. For i = 2 or higher, the value of "dummy" is OK. On the other hand, for ADC_channels 0 and 2, the first value of "dummy" (i = 1) is always around 500 or so as expected. When ADC_channel 0 is done, the ADC_channel is set to "1" and for the very first data point acquired, "dummy" is strange again - "0" or 32K.

I am waiting lots of time when I switch the ADC channel, my analog input is not changing, and the channels 0 and 2 work fine - there is something about setting the channel to 1 that throws a quirk into the works. Am I omitting something obvious?

I use PCM 3.217.

Thank you very much,
Curious newbie

Code:
int16 adc_data_grab(int8 ADC_channel, int16 averages)
{
      int16 i;
      int16 dummy;
      int32 allcounts;
      allcounts = 0;

                   set_adc_channel(ADC_channel);
      delay_us(200);

      for (i = 1; i <= averages; i++)
      {   
         dummy = read_adc();
         allcounts =  (dummy + allcounts);   
      }   

      allcounts = (allcounts/averages); 

      return(allcounts);
}
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon Feb 07, 2005 3:10 pm     Reply with quote

Can you post a sample main() function which:
1. Calls this routine and displays the result.
2. Shows all your setup code for the A/D.
3. Shows all your compiler directives.

I want to make sure that you're choosing the correct A/D clock rate
and that you're setting up Port A correctly, and maybe a few other
things.
Guest
Guest







My main
PostPosted: Mon Feb 07, 2005 5:13 pm     Reply with quote

Dear PCM -

Here it is in its leanest form. I use ICD to check the values of the ADC counts as mentioned in the first post. Thank you again.

Ed.

Code:

#include <16F877A.h>

#device *=16 ADC=10 ICD=TRUE


main()
{
   
   int16 sum_x = 0;          // Angle ADC X counts
   int16 sum_y = 0;          // Angle ADC Y counts
   int16 t_counts = 0;
   int16 num_avg = 100;

   setup_port_a(A_ANALOG_RA3_REF);      // A0 A1 A2 A5 Ref=A3
   setup_adc(ADC_CLOCK_INTERNAL);      // Use internal clock, several microseconds at most.
   setup_adc(ADC_CLOCK_DIV_32);


while(1){



   t_counts = adc_data_grab(0, num_avg);

   sum_x = adc_data_grab(1, num_avg);   // These are ADC counts!!
   sum_y = adc_data_grab(2, num_avg);   // These are ADC counts!!


   } // Close the while()

} // Close main()


PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon Feb 07, 2005 5:38 pm     Reply with quote

Before I even look at it, can you post:

1. The #fuses statement.
2. The #use delay() statement.
3. Your crystal frequency.
Guest
Guest







Ooops
PostPosted: Mon Feb 07, 2005 7:17 pm     Reply with quote

Sorry PCM - Forgot the fuses, etc. Here they are...

I am using a 20 Mhz oscillator.

Code:

#fuses HS,NOWDT,NOPROTECT,NOWRT,NOLVP,NOBROWNOUT,NOPUT,NOCPD,DEBUG
#use delay (clock = 20000000)
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon Feb 07, 2005 9:18 pm     Reply with quote

Comments:

1. In your main(), you have two setup_adc() statements.
You should just use this one:

setup_adc(ADC_CLOCK_DIV_32);

2. What is the impedance of the device that's driving pin AN1 ?
According to the 16F877A data sheet, the max impedance
allowed is 10K. Ideally it would be less than that.
I suspect that this is the problem. See comments below.

3. Here is a test. Temporarily change the A/D setup to use
the internal reference (ie., VDD). I assume this is +5v.
Run your test and see if you still get the problem. If you
still have it, then the problem is due to the signal on the AN1 pin.

The problem might be caused by excessive input impedance or noise
and it might be fixed by putting a capacitor on the pin --
perhaps 0.1 uF (100 nF). Or it might be solved by buffering
the signal with an Opamp voltage-follower circuit before it
gets to the AN1 pin.

Of course another possibility is that your analog voltage is
really varying even though you think it's steady.

If the problem goes away when you switch to the internal
reference, then it means the problem is in the external reference.
Now, how that could affect just one channel, I don't know.
If that turns out to be the problem, I'll think about it then.
bluetooth



Joined: 08 Jan 2005
Posts: 74

View user's profile Send private message

PostPosted: Tue Feb 08, 2005 7:41 am     Reply with quote

At the risk of asking a really dumb question, why is "allcounts" declared as an int32 and returned, when your prototype and the calling routine are using int16's? I would expect this to factor in to your getting some strange results.

Just something else to look at.....
Guest
Guest







Ok, you may have a point
PostPosted: Tue Feb 08, 2005 11:02 am     Reply with quote

Bluetooth -

You have a point regarding this point; I may have added this bug while sanitizing the code for posting. However, the main point is this:

When the ADC_channel is set to one (1) in the main code, and the "ADC_data_grab" function is entered and we get here:
Code:
for (i = 1; i <= averages; i++)
      {   
         dummy = read_adc();
         allcounts =  (dummy + allcounts);   
      }   

the value of the variable "dummy" is 0, or 2,200, or 22,000, or some bogus number when i = 1. However, when i > 1, the value of dummy is about 510, because the voltage on AN1 is 1.65 volts and my reference voltage is 3.3 volts. (The problem didn't go away when I tried the internal reference, but thanks PCM!)

What I am doing now is this:
Code:
     dummy_read = read_adc();
for (i = 1; i <= averages; i++)
      {   
         allcounts =  (read_adc() + allcounts);   
      }   

This way, the bogus data on the very first read_adc() is excluded from my ADC averaging that takes place right after all reads are accumulated. Using the ICD I see that indeed, the value of dummy_read can be some arbitrary integer, including 0, while "allcounts" starts at about 500 when i = 1, goes to about 1000 when i = 2, etc...

Could the problem be related to the fact that the ADC reading is 10 bits and I am logging the counts with a variable that is 32 bits? I also have the same problem on another board with an 18F452; I originally saw it on a 16F877A. Maybe its an ICD problem?

As a peripheral question, how to estimate the approximate sampling rate of the ADC in the above function?

Thanks for the help and comments. I'll pound away on it in the mean time.

Ed
bluetooth



Joined: 08 Jan 2005
Posts: 74

View user's profile Send private message

PostPosted: Tue Feb 08, 2005 11:21 am     Reply with quote

Ed:

There are a lot of places where the data sizes don't match (e.g. allcounts/averages, others) - it would be useful to see the "real" code/list file.

Also, as you are set up with the a/d formatted for 10 bits, you really should never see the "22,000" example you cite: it should never be bigger than 1023.

I would look at the listing in detail to make sure you're not becoming a victim of CCS's need for over-explicit casting.

As a side question: I assume you have set tris a as inputs?

For the sampling time, you can calculate it from the list file or toggle an i/o pin in the loop and look at it with a scope....

Good luck....
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