PrinceNai
Joined: 31 Oct 2016 Posts: 480 Location: Montenegro
|
Olympic average - 8bit ADC |
Posted: Mon Mar 27, 2023 3:45 am |
|
|
Below is the routine to calculate olympic average for 8 bit ADC readings (or any other 8 bit values, of course). Thanks to Asmboy, all the hard work was done by him and posted in this thread: https://www.ccsinfo.com/forum/viewtopic.php?t=50320&highlight=olympic
This is a simple adaptation of his code for 8 bit values. If you want to use it in its original form for 10 or 12 bit values, all you have to do is comment and uncomment a few lines as described in the code.
For production use remove the settings for a debugger.
Code: |
#include <18F46K22.h>
#device ADC = 8
//#device ADC = 10
#FUSES NOWDT, NOPUT , DEBUG //No Watch Dog Timer, noput for ICD compatibility
#device ICD=TRUE
#use delay(internal=32000000)
#use rs232(baud=19200, parity=N, UART2, bits=8, stream=DEBUG, errors)
//int16 MyADC = 0; // for 10 bit or 12bit ADC
int8 MyADC = 0; // for 8 bit ADC
// ****************************************************************************
// olympic++ adc de-noising routine for 8, 10 or 12 bit ADC values *
// NOTE: you must have selected the desired ADC channel before calling *
// reads 16x , sorts and tosses low 6 (or 4) && high 6 (or 4) readings *
// then averages the middle 4 or 8 *
// You must set #device ADC = 8 or #device ADC = 10 according to your needs *
// This code is only an 8 bit adaptation from the thread asmboy posted here: *
// https://www.ccsinfo.com/forum/viewtopic.php?t=50320&highlight=olympic *
// ****************************************************************************
//unsigned int16 adchlx(void){ // read ADC 16x - sort, keep middle 4, average, uncomment for 8 bit ADC
unsigned int8 adchlx(void){ // read ADC 16x - sort, keep middle 4, average, comment for 10 bit ADC
unsigned int8 i; unsigned int16 accum=0;
char b[16]; int1 didswap=1;
// unsigned int16 s; // un-comment for 10 bit ADC
unsigned int8 s; // comment for 10 bit ADC
unsigned int8 result; // comment out for 10 bit, not needed
// read ADC 16 times
for ( i = 0 ; i < 16; i++ ) {
b[i]= read_adc(); // ADC set for 8, 10 or 12 bits
delay_us(2); // optional, can be whatever, even commented out
} // end of for loop for multi sample
// now sort the readings lowest to highest
while(didswap){ // bubble sort
didswap=0;
for (i=0; i<15; i++){ // i 0-15
if(b[(i)]>b[(i+1)]){ // if low element greater than next -do swap
s=b[i]; // hold upper
b[i]=b[(1+i)];
b[(1+i)]=s;
didswap=1;
} // ~if
} // ~for
} // ~while
// It is up to you how many values you keep for averaging.
// This keeps only the middle 4 values. I've found it more stable than keeping 8 samples because the integer division
// defaults to the first lower whole integer value (for example, if you had 5 values of 57 and eleven of 58, it returned 57).
// For a pot reading it is rock stable. 8 bytes averaging code is commented out.
for (i=6; i<10; i++){ // sum middle 4 values
// for (i=4; i<12; i++){ // sum middle 8 values
accum +=b[i];
}
accum = accum >> 2; // divide by 4 for 4 values
// accum = accum >> 3; // divide by 8 for 8 values
result = make8(accum,0); // for 8 bit ADC discard upper 8 bits, return 8bit value. Comment this out for 10 bit ADC.
// return(accum); // uncomment for 10 bit, returns 16 bit value.
return(result); // 8 bit return value, comment for 10 bit ADC
}
// ************************************************************
void main()
{
setup_adc_ports(sAN0, VSS_VDD);
setup_adc(ADC_CLOCK_DIV_32 | ADC_TAD_MUL_20);
set_adc_channel(0); //read from ADC channel 0
while(TRUE)
{
MyADC = adchlx();
fprintf(DEBUG,"ADC value = %u \r\n", MyADC); // send the result out on UART2, debug info
delay_ms(500); // delay to prevent flooding the serial monitor
}
}
|
|
|