Electrical Engineering Stack Exchange is a question and answer site for electronics and electrical engineering professionals, students, and enthusiasts. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

This question already has an answer here:

For the need of more accuracy in my adc value, I have to average the adc value for particular time, what are the types of techniques handled in the averaging Can anyone help me with the example C programs for different types of averaging techniques PIC 16f877A.

share|improve this question

marked as duplicate by Olin Lathrop, Joe Hass, placeholder, Dave Tweed May 8 '14 at 14:16

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

First of all, if your input is noisy, you can simply take a number of readings inside a tight loop, say 10, and use the average value from that as your reading.

To average over a period of time, you want to use a rolling average, such as implemented by the following code. Readings are added to an array, and then the average of all the readings is computed and returned. I did not include the initialization of the ADC module, and the ADC channel is hard-coded as 0.

Because of the limited register size of the PIC16, I am using #if statements to select the smallest variable sizes possible (i.e. unsigned char index if array is less than 256).

#define MAX_ADC_VALUES  20
#define ADC_CHANNEL  0

unsigned short adcValues [MAX_ADC_VALUES];   // array of ADC readings
#if MAX_ADC_VALUES < 256
unsigned char adcValueIndex = 0;       // current index into array
unsigned short adcValueIndex = 0; 
unsigned char fullArray = 0;       // set to 1 after we have filled array

// call this on a periodic basis
unsigned short getAveragedAdcReading()
#if MAX_ADC_VALUES < 256
unsigned char i; 
unsigned short i; 
unsigned short adcReading;         // latest reading from ADC
unsigned short adcAverage;         // 10-bit ADC; sum of 65 readings just fit in an unsigned  short
unsigned long adcAverage;      

    // if your input is noisy, then add a loop here to take several readings in a row and average
    ADCON0bits.CHS = ADC_CHANNEL;  // channel set here
    ADCON0bits.GO = 1;             // start ADC conversion
    while (ADCON0bits.nDONE);      // wait till ADC conversion is over

    adcReading = (ADRESH<<8) + ADRESL ;   //merge the MSB and LSB of the result
    adcValues[adcValueIndex++] = adcReading;    // overwrite oldest reading with newest one

    adcAverage = 0;
    for (i=0; i < MAX_ADC_VALUES; i++)
        adcAverage += adcValues[i];
    if (fullArray)
        adcAverage /= MAX_ADC_VALUES;          // get average of MAX_ADC_VALUES readings
        adcAverage /= adcValueIndex;          // use this if array not filled yet

    if (adcValueIndex >= MAX_ADC_VALUES)
        adcValueIndex= 0;          // if at end of array, loop around
        fullArray = 1;             // we have now filled array, can divide by MAX_ADC_VALUES from now on            

    return (unsigned short)adcAverage;    // cast only needed if adcAverage is unsigned long
share|improve this answer
You could handle this as a running sum by subtracting the value that falls out of the array and adding the new value. Also, this becomes much more sleek if the array size is a power of two, and the divides would be replaced by shifts. Neither of these tweaks, of course, are as good for teaching the basic concept. – Scott Seidman May 8 '14 at 11:06

Have a look at this book: The Scientist and Engineer's Guide to Digital Signal Processing

It is available completely free of charge online on: http://www.dspguide.com/pdfbook.htm

You should take a look at Chapter 15: Moving Average Filters. It is a very simple, yet powerful technique to increase the accuracy of your ADC.

share|improve this answer

Not the answer you're looking for? Browse other questions tagged or ask your own question.