|
|
View previous topic :: View next topic |
Author |
Message |
marken
Joined: 22 Apr 2010 Posts: 6 Location: UK
|
ADC result flickers |
Posted: Tue Apr 27, 2010 7:27 am |
|
|
Hi there,
I have a temperature sensor Tsic101 with analogue output voltage.
My uC is PIC 18LF4550. I have connected the sensor to AN0 Pin 2 of the microcontroller. I display the value to an LCD display.
The senor and the PIC are powered from 3V source.
At the room temperature the temp = 18.6C, adc_value = 117, adc_volts =0.343V
About once in 30sec the decimal digit from temp, the last digit from adc_value and the third decimal from adc_volts flickers.
I have scoped the AN0 and there is no noise, clear signal.
Any idea how to make the reading stable?
Regards
Marken
This is my code:
Code: | #include <18f4550.h> // device selection
#device adc=10
#fuses HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL5,CPUDIV1,VREGEN
//#fuses HS, NOWDT, PUT, BROWNOUT, NOLVP
#use delay(clock=20000000) // 20 MhZ
#use standard_io(A)
#use standard_io(C)
#use standard_io(D)
//#use standard_io(E)
#include <string.h>
#define AN0_TO_AN2 0x0C
//Data type definition
BYTE data;
long int addr;
int16 count;
int16 eeprom;
char string[7];
float adc_volts;
void main()
{
int16 adc_value;
float temp;
float adc_volts;
set_adc_channel(0);
delay_ms(180);
adc_value = read_adc();
adc_volts = (float)(adc_value *3)/1023.0;
temp = (float)(adc_volts * 200)-50;
dt_lcd_gotoxy(0,4); // goto cursur location x= 0..127 PIXEL COLUMNS // y= 0..7 CHAR. ROWS
printf(dt_lcd_printchar,"Fixture temp:%2.1fC ", temp);
dt_lcd_gotoxy(0,7);
printf(dt_lcd_printchar,"ADC=:%lu ", adc_value); // Display variable adc_value for debug
dt_lcd_gotoxy(60,7);
printf(dt_lcd_printchar,"A0V=:%2.3fV ", adc_volts);
...
}
|
_________________ test |
|
|
andrewg
Joined: 17 Aug 2005 Posts: 316 Location: Perth, Western Australia
|
Re: ADC result flickers |
Posted: Tue Apr 27, 2010 7:38 am |
|
|
marken wrote: | Any idea how to make the reading stable? |
Sure. Read the data sheet, which says:
Quote: | For device frequencies above 1 MHz, the device must be in Sleep for the entire conversion or the A/D accuracy may be out of specification. |
The CCS manual give an example of an ADC read during sleep.
Apart from that, take a bunch of readings and average them. _________________ Andrew |
|
|
marken
Joined: 22 Apr 2010 Posts: 6 Location: UK
|
Thanks for the replay |
Posted: Tue Apr 27, 2010 7:47 am |
|
|
Hi Andrew,
I will investigate the sleep mode conversion.
With regards to average multiple readings, I have thought about that but I just do not want big arrays. However I was reading about moving window average. Are you familiar with this method to get me started?
Regards
Marken _________________ test |
|
|
SherpaDoug
Joined: 07 Sep 2003 Posts: 1640 Location: Cape Cod Mass USA
|
|
Posted: Tue Apr 27, 2010 11:54 am |
|
|
Look at "Olympic" averaging. It is really good at removing occasional bad readings and is very low overhead. Here is a previous post on it: Quote: |
I often use the "Olympic scoring" filter, which is VERY easy to implement.
Loop 10 times.
In each loop read the A/D and keep the sum, the maximum reading and the minimum reading.
When the loop is done subtract the max and min from the sum and divide by 8 (shift 3 bits).
This only needs 3 RAM locations plus the loop counter and a single easy division. It removes high and low outliers and averages the rest. If the A/D is 12 bits the sum will still fit in a 16bit variable. |
To find more search this forum for "Olympic". _________________ The search for better is endless. Instead simply find very good and get the job done. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Apr 27, 2010 1:18 pm |
|
|
Where is your line of code for the setup_adc() function ? |
|
|
marken
Joined: 22 Apr 2010 Posts: 6 Location: UK
|
Setup adc |
Posted: Wed Apr 28, 2010 1:08 am |
|
|
Hi PCM Programmer,
I do have the function in my code I just miss to list it.
My function:
SETUP_ADC(ADC_CLOCK_INTERNAL);
Is this ok as I have LV power 3.3V?
Regards
Marken _________________ test |
|
|
marken
Joined: 22 Apr 2010 Posts: 6 Location: UK
|
Olympic scoring |
Posted: Wed Apr 28, 2010 1:12 am |
|
|
Hi SherpaDoug,
Thanks for the suggestion I was up late last night doing some research on this method. It looks good as I am not an advanced programmer.
I will try to implement it today.
Thanks again.
Regards
Marken _________________ test |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19546
|
|
Posted: Wed Apr 28, 2010 3:16 am |
|
|
Multiple things here.
First the point about ADC clocks. ADC_CLOCK_INTERNAL, is _not_ recommended for operation with a processor clock faster than 1MHz, unless you put the processor to sleep for the conversion. Is your chip an F4550, or an LF4550?. You show the 'F' in your code, but are talking about 20MHz operation at 3.3v. This is not 'legal' for the F4550, but is just OK for the LF4550. Assuming it is the LF4550, change your clock selection to ADC_CLOCK_DIV_32 Table 21-1 in the data sheet, gives the selections that should be used. ADC_CLOCK_INTERNAL, does generate lower accuracy readings, if used outside the specified range, which may well be your main problem.
Second the point about the signal actually being stable. The ADC, is potentially recording signals at 0.1% full scale. On a typical scope, this is perhaps 1/4 the thickness of the line actually being traced. Your signal may well have 'real' noise at the level being recorded, but you are just not seeing it. Switch the scope to AC coupled, and turn the gain up by 20*. If the signal is now showing some noise, then this is what the ADC is recording...
Then you have the question of averaging. The Olympic averaging system, is ideal, if there are real 'spike' signals, but you may just be seeing the effect of purely random noise (effectively 'hiss' on an old radio). The value read from the ADC, will never be perfectly stable. If your signal is sitting between two counts of the ADC, and has some random noise present (there is some in the chip itself, and there will be some on the signal), you should receive equal numbers of the two counts. If it is sitting 80% of the way from one count to the other, you should receive 80% of the 'closer' count, and 20% of the other. Averaging, will allow you potentially to 'see' the long term trend of the basic data. There are a number of methods, but one that works well, is the 'sum, divide & subtract', which allows work to be minimised on each loop, but to give good long term averages. It is less effective at removing the 'odd' values, than the Olympic sort. Classic code for this simple approach is:
Code: |
int32 rolling_sum;
int16 reading;
#define DIV_FACTOR (4)
//Then at each reading
rolling_sum+=read_adc();
reading=rolling_sum/DIV_FACTOR;
rolling_sum-=reading;
//reading then contains the averaged value
|
Increasing the 'DIV_FACTOR' value gives more averaging. Keeping this as a binary value (2,4,8,16), makes the arithmetic fast/efficient.
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
|