View previous topic :: View next topic |
Author |
Message |
skoberlink
Joined: 27 May 2010 Posts: 52
|
ADC fluctuation PIC16F88 |
Posted: Thu Jul 22, 2010 9:51 am |
|
|
I'm using a PIC16F88 to read an analog signal and move a motor to a percent of it's range based on that analog signal. I wrote my own function for handling the conversion to avoid using the CCS built-ins. It reads almost properly.
The problem is my motor goes to the right place but then twitches back and forth. If I average several reads and put in a tolerance value for movement (i.e. only move if it has to move at least a certain distance) then the twitching goes away but this significantly reduces my precision. The signal into the PIC is rock solid at exactly the values it's supposed to be.
Any ideas on what might be happening and how to fix it? Here's my read function in case you guys can spot anything:
Code: | unsigned long analog_in(unsigned char channel){
unsigned long result = 0;
channel &= 0b00000111; // truncate channel to 3 bits
ADCON1 = 0x80;
ADCON0 = 0b11000000; //clear channel
ADCON0 |= (channel<<3); // apply new channel select
ADON = 1; //turn it on
delay_us(30); //let it settle
ADGO = 1; //initiate conversion
while (ADGO) continue; // wait for result
result = (ADRESH<<8);
result |= ADRESL;
return result; // return 10 bit result
} |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Jul 22, 2010 11:17 am |
|
|
What's your compiler version ? |
|
|
SherpaDoug
Joined: 07 Sep 2003 Posts: 1640 Location: Cape Cod Mass USA
|
|
Posted: Thu Jul 22, 2010 11:24 am |
|
|
Look at the numbers coming out of the A/D. How much do they vary? If it is +/- 1 count, that is the best you can do. Is it mostly +/- 1 count with occasional bad values? If so look for something else in the system that happens when the bad value occurs that might be causing it. Also search for "Olympic averaging". It is computationally cheap and good at removing occasional bad values. At the cost of a few more clock cycles and RAM you can also do a "median filter".
On the hardware end make sure your A/D reference is as clean as your signal. One is useless without the other. Double check your grounding.
I will leave your code to others to inspect. It looks OK to me, but I don't use the internal A/Ds much. _________________ The search for better is endless. Instead simply find very good and get the job done. |
|
|
skoberlink
Joined: 27 May 2010 Posts: 52
|
|
Posted: Fri Jul 23, 2010 8:21 am |
|
|
@PCM Programmer
Compiler version is CCS 4.106
@SherpaDoug
I haven't checked the A/D output but it occurred to me while reading your response that this might be the issue. It's a stepper motor and I've been using steps as my tolerance value but the number of steps in one percentage point would change depending on the range of motion given to the motor.
But I'm just thinking "out loud" now. If I'm still having an issue those averages you mentioned looked useful. Also all signals including the reference are clean.
I'm guessing that checking the percent for tolerance instead of the number of steps will fix it. It seems kind of obvious and stupid now...lol |
|
|
skoberlink
Joined: 27 May 2010 Posts: 52
|
|
Posted: Fri Jul 23, 2010 8:56 am |
|
|
Well that did not solve it. It was an issue that needed to be fixed but I still get the twitching in the motor. I'll try some of the other average methods mentioned but I'm still open to other suggestions if you guys have any.
EDIT: btw I tried several tolerance values. The ADC reads are +/- at least 10 probably significantly more. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19520
|
|
Posted: Fri Jul 23, 2010 10:01 am |
|
|
It is well worth triple checking how 'rock solid' the input values really are.
A scope for example, will see a signal as 'flat line', that can easily have 10 steps when read with the ADC. Simple DVM's also tend to integrate values, and will not see high frequency noise. If you are using the PIC supply as your 'ref', this _will_ have HF noise on it. The Vref really needs to be from a separate source, and well decoupled, if this is not to be a problem...
Best Wishes |
|
|
skoberlink
Joined: 27 May 2010 Posts: 52
|
|
Posted: Fri Jul 23, 2010 10:06 am |
|
|
Ttelmah wrote: | It is well worth triple checking how 'rock solid' the input values really are.
A scope for example, will see a signal as 'flat line', that can easily have 10 steps when read with the ADC. Simple DVM's also tend to integrate values, and will not see high frequency noise. If you are using the PIC supply as your 'ref', this _will_ have HF noise on it. The Vref really needs to be from a separate source, and well decoupled, if this is not to be a problem...
Best Wishes |
hmmm...I am using the pic's power supply as reference. I hadn't considered noise on that between entering the PIC and being used for ADC.
I've tried reading the values using an oscilloscope and a DVM. Neither showed noise. If they are unreliable for this measurement, what can I use?
Based on what I know so far, I would guess you are correct. The problem is using Vdd as my Vref. Unfortunately I don't have the pins free to use a separate Vref. Do you have any suggestions? |
|
|
newguy
Joined: 24 Jun 2004 Posts: 1908
|
|
Posted: Fri Jul 23, 2010 11:07 am |
|
|
skoberlink wrote: | Based on what I know so far, I would guess you are correct. The problem is using Vdd as my Vref. Unfortunately I don't have the pins free to use a separate Vref. Do you have any suggestions? |
This is a multi-faceted issue with many possible remedies. For instance, higher capacitance/lower ESR capacitors on your power supply rail, with a 0.1uF cap placed very close (physically) to each PIC Vdd pin. If you don't have a ground plane, you need one. Power supply filtering, EMI filtering on each line that is prone to noise won't hurt either. A simple RC low pass filter on the problem analog line will help immensely too. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Jul 23, 2010 11:37 am |
|
|
Quote: | ADCON0 = 0b11000000
|
Also because you didn't use CCS functions, it's not immediately clear
if you have problems in your ADC setup. This morning I looked more
closely at your setup and I noticed you're using the Internal ADC
oscillator. That's a big no-no for accuracy except under certain
conditions, per the 16F88 data sheet:
Quote: |
2: When the device frequencies are greater than 1 MHz, the RC A/D
conversion clock source is only recommended for SLEEP operation. |
The A/D clock divisor should be selected according to the table in
the PIC data sheet, based on your oscillator frequency. |
|
|
SherpaDoug
Joined: 07 Sep 2003 Posts: 1640 Location: Cape Cod Mass USA
|
|
Posted: Fri Jul 23, 2010 11:56 am |
|
|
It would still be good to know if the A/D values are a wide Gaussian profile (random scatter), or if they are mostly OK with occasional bad readings throw in. If it's the latter, are the bad readings all high or all low? Is there any clear "frequency" to the noise.
Also why did you decide to roll your own A/D code?
As for noise measurement, you may be able to put your scope on AC coupling and then push the gain way up to see small noise signals. _________________ The search for better is endless. Instead simply find very good and get the job done. |
|
|
skoberlink
Joined: 27 May 2010 Posts: 52
|
|
Posted: Mon Jul 26, 2010 8:47 am |
|
|
@newguy
I'm planning to put a .1uF cap on the Vdd line. Do you think that would fix it? I do have a ground plane. I'll look into some of that other stuff.
@PCM programmer
I had missed that line from the data sheet. That could be the problem. Unfortunately I don't have the pins for an external clock. I might be able to turn down the clock speed and see if that helps at all.
@SherpaDoug
I chose to write my own function on the advice of someone more experienced than I. I was having a problem using the built-ins where the voltage coming in to the analog in was at 100% but the motor would only move to 80% of it's range. It had something to do with the math involved in the built-ins. I talked to a friend who has had more experience and he advised me to write my own function. Then I would know exactly what was going on and it was potentially more efficient.
The A/D values seem to be random. I can't see any clear frequency. It all seems completely random.
Thanks for the help so far guys! |
|
|
skoberlink
Joined: 27 May 2010 Posts: 52
|
|
Posted: Mon Jul 26, 2010 10:03 am |
|
|
Well slowing it down helped some. I've also discussed it with the guy working on a similar project and we got it down to an acceptable tolerance value. Haven't tried any of the other suggestions yet and probably won't have time to get to it now since it's a little superfluous. Thanks for the help though! All useful info. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Jul 26, 2010 10:46 am |
|
|
Quote: | Unfortunately I don't have the pins for an external clock
|
That's not what I'm talking about. Post the oscillator frequency of
your PIC. I don't care if you're using a crystal or the Internal oscillator.
But post the frequency. |
|
|
skoberlink
Joined: 27 May 2010 Posts: 52
|
|
Posted: Mon Jul 26, 2010 10:47 am |
|
|
PCM programmer wrote: | Quote: | Unfortunately I don't have the pins for an external clock
|
That's not what I'm talking about. Post the oscillator frequency of
your PIC. I don't care if you're using a crystal or the Internal oscillator.
But post the frequency. |
Ok, the frequency I was running at was 4MHz. I turned it down to 1MHz and it seemed to help but it could have been a placebo effect. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Jul 26, 2010 10:55 am |
|
|
The 16F88.h file lists these options for the A/D clock, to be used in the
setup_adc() function:
Code: |
#define ADC_CLOCK_DIV_2 0x10000
#define ADC_CLOCK_DIV_4 0x4000
#define ADC_CLOCK_DIV_8 0x0040
#define ADC_CLOCK_DIV_16 0x4040
#define ADC_CLOCK_DIV_32 0x0080
#define ADC_CLOCK_DIV_64 0x4080
#define ADC_CLOCK_INTERNAL 0x00c0
|
Download the 16F88 data sheet:
http://ww1.microchip.com/downloads/en/DeviceDoc/30487c.pdf
Look at this table on page 118 (pg 120 in the Acrobat reader):
Quote: | TABLE 12- 1: TAD vs. MAXIMUM DEVICE OPERATING FREQUENCIES – STANDARD DEVICES (C) |
It says that for a 4 MHz oscillator, you should use this divisor:
For a 1 MHz oscillator frequency, you should use this one:
The problem is that you don't want to use CCS functions, so it's more
difficult to modify your code. You'll have to go look up the register
settings and choose the bits carefully to select the correct divisor. |
|
|
|