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 support@ccsinfo.com

Average ADC result

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



Joined: 08 Sep 2011
Posts: 202

View user's profile Send private message

Average ADC result
PostPosted: Wed Jan 02, 2013 9:31 am     Reply with quote

how can read Average ADC result with high value & low value ?
_________________
sahu
temtronic



Joined: 01 Jul 2010
Posts: 9182
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Wed Jan 02, 2013 10:12 am     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Jan 02, 2013 10:23 am     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Jan 02, 2013 10:47 am     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Jan 02, 2013 10:54 am     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Jan 02, 2013 6:18 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Jan 03, 2013 6:45 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Jan 03, 2013 9:24 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Jan 03, 2013 9:58 am     Reply with quote

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: 19391

View user's profile Send private message

PostPosted: Thu Jan 03, 2013 10:05 am     Reply with quote

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. Smile

Best Wishes
sahu77



Joined: 08 Sep 2011
Posts: 202

View user's profile Send private message

PostPosted: Thu Jan 03, 2013 10:54 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Jan 03, 2013 11:49 am     Reply with quote

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: 1611
Location: Central Illinois, USA

View user's profile Send private message

PostPosted: Thu Jan 03, 2013 12:11 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Jan 03, 2013 12:14 pm     Reply with quote

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
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