Hi Guys,
I am trying to average out the ADC value (ADCH). I am using Mega48. I have a DC voltage of about 1.25V at the ADC input pin. This is giving me an ADCh value of about 62H.
I want to average the ADC values to filter the noisy input. Here is what I am using to do that:
#include#include #include #include //Using 1.25 as the reference //I am getting 62 as the ADC value only ADCH which is about 1.215V #define USART_BAUDRATE 230400 #define BAUD_PRESCALE (((7372800/ (USART_BAUDRATE * 16UL))) - 1) //value to load into UBRR #define filter_strength 4 volatile unsigned char flag; volatile uint8_t sum = 0; volatile uint8_t filtered_value = 0; volatile uint8_t i; void USART0_init() { UCSR0B |= (1 << RXEN0) | (1 << TXEN0); // Turn on the transmission and reception circuitry UCSR0C |= (1 << UCSZ01) | (1 << UCSZ00); //Set to 8 bit no parity, 1 stop bit UBRR0L = BAUD_PRESCALE; // Load lower 8-bits of the baud rate value into the low byte of the UBRR register UBRR0H = (BAUD_PRESCALE >> 8); // Load upper 8-bits of the baud rate value into the high byte of the UBRR register // stdout = &mystdout; //Required for printf init } void USART_putchar(unsigned char c) { while ((UCSR0A & (1 << UDRE0)) == 0) {}; UDR0 = c; } void ADC_init() { ADCSRA |= (1 << ADPS1) | (1 << ADPS0) | (1 << ADATE); //using /8 prescalar ADMUX = (1 << REFS0) | (1 << MUX2) | (1 << MUX0) | (1 << ADLAR); // Set ADC reference to AVCC,select channel 5; left shift ADC value to use only ADCH DIDR0 = (1 << ADC5D); //turn off the digital driver ADCSRA |= (1 << ADEN); // Enable ADC ADCSRA |= (1 << ADIE); // Enable ADC Interrupt sei(); // Enable Global Interrupts ADCSRA |= (1 << ADSC); // Start A2D Conversions } void timer_init() { TCCR1B |= (1 << WGM12); TIMSK1 |= (1 << OCIE1A); sei(); OCR1A = 2000; TCCR1B |= (1 << CS12) | (0 << CS11) | (0 << CS10); } ISR(TIMER1_COMPA_vect) { PORTD ^= (1 <<PORTD7);//to indicate AVR is working } ISR(ADC_vect) { for(i=0;i<16;i++) { sum = sum + ADCH; filtered_value = sum >> (filter_strength); } flag = 1; } int main (void) { DDRC = 0x0F; DDRD = 0xC0; USART0_init(); ADC_init(); timer_init(); for(;;) { ADCSRA |= (1 << ADSC); if(flag==1) { USART_putchar(filtered_value); flag = 0; sum =0; } } }
I am trying to average out the ADCH value in the interrupt and then transmit it to the UART in main. I have made all the variables volatile.
Without the averaging the UART shows me 62H which works fine.
However with the averaging, the UART is showing me this:
0 15 0 0 14 0 0 0 0 13 0 0 15 15 0 0 0 0 1 0 15 0 0 14 0 1 0 0 0 1 1 15 0 3 0 0 15 15 15 14 15 1 0 0 1 0 0 15 0 1 0 15 15 0 15 13 0 0 0 14 0 0 15 2 0 0 0 14 0 0 0 0 15 15 0 15 0 2 0 0 0 1 1 1 15 15 0 0 0 1 15 0 0 0 0 0 2 14 0 0 0 0 0 0 0 0 14 0 0 1 15 0 0 15 0 2 1 0 0 0 1 14 0 15 0 15 14 0 0 15 1 0 1 0 15 0 15 0 0 0 0 0 0 0 1 0 0 0 15 14 0 0 0 0 1 0 14 15 0 0 1 15 15 0 0 15 15 14 0 0 12 0 14 15 0 0 0 14 15 15 0 14 0 0 15 1 0 0 0 15 0 1 0 0 0 14 0 0 0 0 0 13 0 0 15 0 0 1 0 0 0 15 4 0 0 15 0 0 15 15 1 1 0 0 15 0 0 0 0 14 0 0 2 0 15 0 0 15 0 0 0 0 0 14 0 0 15 0 14 0 0 0 14 15 0 0 0 1 15 0 0 0 15 15 0 2 0 0 1 0 0 0 2 0 0 0 1 14 0 0 1 0 0 2 0 0 0 0 1 1 0 0 0 0 1 15 0 0 0 0 0 0 0 1 0 0 0 0 0 1 1 0 2 0 0 0 0 0 0 1 0 15 0 15 0 0 0 0 0 15 0 0 0 0 1 15 1 0 1 1 14 0 0 0 2 1 0 15 0 0 14 0 0 0 0 1 0 1 1 0 1 13 13 0 0 0 15 15 14 15 1 0 15 15 2 0 14 0 0 0 0 14 0 0 14 15 0 14 0 0 0 0 0 15 15 0 0 15 0 0 0 13 0 0 14 1 0 15 0 0 15 1 0 0 0 0 15 2 15 0 0 1 0 0 15 15 1 0 0 15 1 0 0 14 1 14 0 0 1 2 14 0 14 0 0 1 0 0 14 0 15 0 15 0 0 1 0 15 0 0 0 0 15 0 0 0 0 0 0 0 2 0 1 0 1 0 15 0 14 1 0 0 1 15 0 0 0 0 15 0 15 15 0 0 0 15 15 0 1 0 2 0 1 0 15 15 0 0 0 1 2 0 1 0 1 0 1 0 1 0 1 0 1 14 15 1 1 0 1 0 1 0 15 0 15 13 0 0 0 0 15 0 0 1 0 0 1 0 0 0 0 1 10 0 0 14 0 0 13 15 0 15 0 15 0 0 0 1 1 0 0 0 2 15 14 0 15 1 0 0 15 0 0 0 14 2 0 15 0 0 0 1 0 0 4 0 14 0 0 0 0 0 0 0 15 1
I am summing 16 times and then dividing by 16 (with the right shift).
Could this be a float problem? filtered_value is defined as uint8_t. Do I have to convert the binary to decimal and then do the averaging? Wouldn't that slow down the ADC capture?
Thanks.