View previous topic :: View next topic |
Author |
Message |
sahu77
Joined: 08 Sep 2011 Posts: 202
|
Average ADC result |
Posted: Wed Jan 02, 2013 9:31 am |
|
|
how can read Average ADC result with high value & low value ? _________________ sahu |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9226 Location: Greensville,Ontario
|
|
Posted: Wed Jan 02, 2013 10:12 am |
|
|
hmm..
a rather 'generic' question..
no PIC type, compiler version ,ADC peripheral......
..making it hard to guess what you mean.
however...
simply put..
(high value + low value) /2
will give the average of those two numbers.
but...
do you have 8 bit ADC result, 10 bit, 12 bit, 32 bit.....?????
do you want integer result, floating point, int16 ????
You really need to supply more information as there are lots of correct answers to the question.
hth
jay |
|
|
sahu77
Joined: 08 Sep 2011 Posts: 202
|
|
Posted: Wed Jan 02, 2013 10:23 am |
|
|
temtronic wrote: | hmm..
a rather 'generic' question..
no PIC type, compiler version ,ADC peripheral......
..making it hard to guess what you mean.
however...
simply put..
(high value + low value) /2
will give the average of those two numbers.
but...
do you have 8 bit ADC result, 10 bit, 12 bit, 32 bit.....?????
do you want integer result, floating point, int16 ????
You really need to supply more information as there are lots of correct answers to the question.
hth
jay |
16f676
compiler version V4.057
i have 8 bit ADC result, 10 bit,
i want int16 or int32 _________________ sahu |
|
|
Gabriel
Joined: 03 Aug 2009 Posts: 1067 Location: Panama
|
|
Posted: Wed Jan 02, 2013 10:47 am |
|
|
Quote: | i want int16 or int32 |
you understand that you wont be getting 16 or 32 bit accuracy.
you can get close to 10 bit accuracy _formated_ in a 16/32 bit variable.
you cant produce 6 aditional bits of resolution by oversampling...
just FYI...
Edit: you can look at the LM35 driver i posted to get _an idea_ of how to do an average of ADC samples with Highest and lowest values...
if you read multiple samples do it in powers of 2 so that when you divide its faster..2,4,8,16 etc...
G _________________ CCS PCM 5.078 & CCS PCH 5.093 |
|
|
Gabriel
Joined: 03 Aug 2009 Posts: 1067 Location: Panama
|
|
Posted: Wed Jan 02, 2013 10:54 am |
|
|
Code: | counter=0; // clear counter
lowest=0xFFFF; // reset lowest
highest=0; // reset highest
while(counter<18) // Take 18 readings and average (16+highest+lowest)
{
temporary=READ_ADC(); // take an ADC reading
if(temporary<lowest) // check if smaller than lowest
lowest=temporary; // save value if smaller
if(temporary>highest) // check if larger than highest
highest=temporary; // save value if larger
temperature+=temporary; // add the ADC values for averaging (Vout on LM35)
counter++;
}
temperature-=highest; // remove highest value
temperature-=lowest; // remove lowest value
temperature/=16; |
that should put you on your way...
G. _________________ CCS PCM 5.078 & CCS PCH 5.093 |
|
|
gpsmikey
Joined: 16 Nov 2010 Posts: 588 Location: Kirkland, WA
|
|
Posted: Wed Jan 02, 2013 6:18 pm |
|
|
You probably should also put provisions in there for clearing the "highest" and "lowest" values when you want. If nothing else, often strange readings get recorded when you power up/come out of reset. You are also going to need to make sure you have filtering on the sensor (at least a low pass) to help avoid strange noises from giving false high or low readings that then get logged in your limits variables.
mikey _________________ mikey
-- you can't have too many gadgets or too much disk space !
old engineering saying: 1+1 = 3 for sufficiently large values of 1 or small values of 3 |
|
|
Gabriel
Joined: 03 Aug 2009 Posts: 1067 Location: Panama
|
|
Posted: Thu Jan 03, 2013 6:45 am |
|
|
Highest and Lowest get Reset before every Averaged reading:
Code: | lowest=0xFFFF; // reset lowest
highest=0; // reset highest |
so after each time you execute the code i posted, you should have a fresh value for high and low...
unless you mean somthing else and i didnt get it... which happens often.
... the code as posted also removed the highest and the lowest from the average, its an "olympic average"... which should provide some filtering...
however I agree, some external filtering depending on the application is generaly a good idea.
G. _________________ CCS PCM 5.078 & CCS PCH 5.093 |
|
|
sahu77
Joined: 08 Sep 2011 Posts: 202
|
|
Posted: Thu Jan 03, 2013 9:24 am |
|
|
Gabriel wrote: | Code: | counter=0; // clear counter
lowest=0xFFFF; // reset lowest
highest=0; // reset highest
while(counter<18) // Take 18 readings and average (16+highest+lowest)
{
temporary=READ_ADC(); // take an ADC reading
if(temporary<lowest) // check if smaller than lowest
lowest=temporary; // save value if smaller
if(temporary>highest) // check if larger than highest
highest=temporary; // save value if larger
temperature+=temporary; // add the ADC values for averaging (Vout on LM35)
counter++;
}
temperature-=highest; // remove highest value
temperature-=lowest; // remove lowest value
temperature/=16; |
that should put you on your way...
G. |
its right way reading 2 adc channel AN0 & AN1 ??
as u say !
Code: | /***************************************************************************
Function getchreading
Calculate minivolts on selected channel
****************************************************************************/
int16 getchreading(int channel)
{
SETUP_ADC_PORTS(sAN0|sAN1); // Select Analog channels on PIC
SETUP_ADC(ADC_CLOCK_DIV_8); // Select ADC conversion Clock
delay_ms(40); // give some time for charge capicitor to stabilize
int counter=0; // temporary counter
signed int16 temperature=0; // temporary adc_value variable
int16 highest=0; // saves highest reading for filtering
int16 lowest=0xFFFF; // saves lowest reading for filtering
int16 temporary=0;
int32 temp_result, adc_value, tlong;;
set_adc_channel(channel); // Select Channel
// Average ADC value
delay_us(15); // small delay to settle
counter=0; // clear counter
lowest=0xFFFF; // reset lowest
highest=0; // reset highest
while(counter<18) // Take 18 readings and average (16+highest+lowest)
{
temporary=READ_ADC(); // take an ADC reading
if(temporary<lowest) // check if smaller than lowest
lowest=temporary; // save value if smaller
if(temporary>highest) // check if larger than highest
highest=temporary; // save value if larger
temp_result-=temporary; // substract the ADC values for averaging (adc i\p)
counter++;
}
temp_result+=highest; // remove highest value
temp_result+=lowest; // remove lowest value
temp_result/=16; // average by 16
adc_value = temp_result
tlong = (int32)ADC_value*5000; //Convert the result in millivolts
tlong = tlong/1023; // 0..1023 -> 0-5000mV
SETUP_ADC(ADC_OFF); // turn off ADC module
return (int32) tlong;
}
/*****************************************************************************
Function ProcessMains
Reads Form AN0 ADC_Value and Reads Form AN1 ADC_Value
****************************************************************************/
int ProcessMains(void)
{
ch_0 = getchreading(0);
ch_1 = getchreading(1);
.here do somthing ch_0 & ch_1
.
.
.
.} |
_________________ sahu |
|
|
Gabriel
Joined: 03 Aug 2009 Posts: 1067 Location: Panama
|
|
Posted: Thu Jan 03, 2013 9:58 am |
|
|
Code: | temp_result-=temporary; // subtract the ADC values for averaging (adc i\p) |
Code: | temp_result+=highest; // remove highest value
temp_result+=lowest; // remove lowest value |
check the function i posted (its even in your reply)... your math is inverted.
you probably haven't compiled this yet, or printed the results to terminal..
Code: | temp_result/=16; // average by 16
adc_value = temp_result
tlong = (int32)ADC_value*5000; //Convert the result in millivolts
tlong = tlong/1023; // 0..1023 -> 0-5000mV |
is it ADC_value or adc_value?
be consistent...
Code: | int counter=0; // temporary counter
signed int16 temperature=0; // temporary adc_value variable
int16 highest=0; // saves highest reading for filtering
int16 lowest=0xFFFF; // saves lowest reading for filtering
int16 temporary=0; |
Where do you use "temperature"?
Code: |
SETUP_ADC_PORTS(sAN0|sAN1); // Select Analog channels on PIC
SETUP_ADC(ADC_CLOCK_DIV_8); // Select ADC conversion Clock
delay_ms(40); // give some time for charge capacitor to stabilize |
are you sure that your ADC clock is correct for your chip+crystal combination?
read the Datasheet: TAD
Code: | tlong = (int32)ADC_value*5000; //Convert the result in millivolts
tlong = tlong/1023; // 0..1023 -> 0-5000mV |
you could simply do
Code: | temp_result*=5000; //Convert the result in millivolts
temp_result/=1023; |
its already a 32bit var according to your declaration...
Compile, and TEST... print partial results to screen at different steps of the function... don't expect to get the right answer after you wrote a long function...
G. _________________ CCS PCM 5.078 & CCS PCH 5.093 |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19513
|
|
Posted: Thu Jan 03, 2013 10:05 am |
|
|
As one other comment, the 'temp_result', is the sum of 16 readings after the highest and lowest have been removed. If you are going to multiply by 5000, then don't!. Get rid of the division by 16, and multiply the sum by 625, and then divide by 2046. Only one division needed, and you keep more of the numeric accuracy.
Best Wishes |
|
|
sahu77
Joined: 08 Sep 2011 Posts: 202
|
|
Posted: Thu Jan 03, 2013 10:54 am |
|
|
Gabriel wrote: | Code: | temp_result-=temporary; // substract the ADC values for averaging (adc i\p) |
Code: | temp_result+=highest; // remove highest value
temp_result+=lowest; // remove lowest value |
check the function i posted (its even in your reply)... your math is inverted.
you probably havent compiled this yet, or printed the results to terminal..
Code: | temp_result/=16; // average by 16
adc_value = temp_result
tlong = (int32)ADC_value*5000; //Convert the result in millivolts
tlong = tlong/1023; // 0..1023 -> 0-5000mV |
is it ADC_value or adc_value?
be consistent...
Code: | int counter=0; // temporary counter
signed int16 temperature=0; // temporary adc_value variable
int16 highest=0; // saves highest reading for filtering
int16 lowest=0xFFFF; // saves lowest reading for filtering
int16 temporary=0; |
.
.
.
.
.
.
its already a 32bit var according to your declaration...
Compile, and TEST... print partial results to screen at diferent steps of the function... dont expect to get the right answer after you wrote a long function...
G. |
now correct ?
Code: | /***************************************************************************
Function getchreading
Calculate minivolts on selected channel
****************************************************************************/
int16 getchreading(int channel)
{
SETUP_ADC_PORTS(sAN0|sAN1); // Select Analog channels on PIC
SETUP_ADC(ADC_CLOCK_DIV_8); // Select ADC conversion Clock
delay_ms(40); // give some time for charge capicitor to stabilize
int counter=0; // temporary counter
signed int16 temp_result=0; // temporary adc_value variable
int16 highest=0; // saves highest reading for filtering
int16 lowest=0xFFFF; // saves lowest reading for filtering
int16 temporary=0;
int32 temp_result, adc_value, tlong;;
set_adc_channel(channel); // Select Channel
// Average ADC value
delay_us(15); // small delay to settle
counter=0; // clear counter
lowest=0xFFFF; // reset lowest
highest=0; // reset highest
while(counter<18) // Take 18 readings and average (16+highest+lowest)
{
temporary=READ_ADC(); // take an ADC reading
if(temporary<lowest) // check if smaller than lowest
lowest=temporary; // save value if smaller
if(temporary>highest) // check if larger than highest
highest=temporary; // save value if larger
temp_result-=temporary; // substract the ADC values for averaging (adc i\p)
counter++;
}
temp_result-=highest; // remove highest value
temp_result-=lowest; // remove lowest value
temp_result/=16; // average by 16
temp_result*=5000; //Convert the result in millivolts
temp_result/=1023;
SETUP_ADC(ADC_OFF); // turn off ADC module
return (int32) temp_result;
} |
i'm not sure that my ADC clock is correct for chip (16f676)+internal osc combination? _________________ sahu |
|
|
ezflyr
Joined: 25 Oct 2010 Posts: 1019 Location: Tewksbury, MA
|
|
Posted: Thu Jan 03, 2013 11:49 am |
|
|
Hi Sahu,
Quote: |
i'm not sure that my ADC clock is correct for chip (16f676)+internal osc combination? |
I know this is a truly radical suggestion, but have you considered actually
reading the Microchip datasheet for this information??
I wonder what designers and programmers did before the invention of
internet forums?
John |
|
|
bkamen
Joined: 07 Jan 2004 Posts: 1615 Location: Central Illinois, USA
|
|
Posted: Thu Jan 03, 2013 12:11 pm |
|
|
ezflyr wrote: | Hi Sahu,
I know this is a truly radical suggestion, but have you considered actually
reading the Microchip datasheet for this information??
I wonder what designers and programmers did before the invention of
internet forums?
|
No kidding.
Although, a mentor of mine outside of school back in my high school days used to say how schools don't teach how to process thought. (only memorization)
So it's really not surprising to see this more first hand with the advent of the internet forum.
And it's worse now -- you don't need to really "know" anything.. you can just ask Siri.
-Ben _________________ Dazed and confused? I don't think so. Just "plain lost" will do. :D |
|
|
Gabriel
Joined: 03 Aug 2009 Posts: 1067 Location: Panama
|
|
Posted: Thu Jan 03, 2013 12:14 pm |
|
|
Code: | int counter=0; // temporary counter
signed int16 temp_result=0; // temporary adc_value variable
int16 highest=0; // saves highest reading for filtering
int16 lowest=0xFFFF; // saves lowest reading for filtering
int16 temporary=0;
int32 temp_result, adc_value, tlong;; |
... well if you where actually trying to code and compile and test your work, you would notice the 2 repeated semicolons after tlong.
also you would notice that you have declared temp_result as:
Code: | signed int16 temp_result=0; // temporary adc_value variable
AND
int32 temp_result, adc_value, tlong;; |
Code: | temp_result-=temporary; // substract the ADC values for averaging (adc i\p) |
Still wrong... your removing 16 samples instead of ADDING 16 samples
*straps rocket back pack*
Nothing to do here.....
G. _________________ CCS PCM 5.078 & CCS PCH 5.093 |
|
|
|