Grandes errores en las lecturas de ATMEGA8 ADC

0

Estoy utilizando el ADC de ATMega8 para leer las formas de onda de carga y descarga de un condensador. Sin embargo, estoy obteniendo una gran cantidad de errores cuando veo los datos que obtengo en mi computadora portátil. Estoy enviando los datos muestreados a la computadora portátil a través de un convertidor de USB a TTL a 9600 bps. La frecuencia de muestreo es de 15000 muestras por segundo, por lo que probablemente hay muchas muestras que se pierden debido a la diferencia de velocidad. Estoy usando el reloj predeterminado de ATMEGA8. Los datos transmitidos en serie se reciben en MATLAB y se muestra el gráfico:

Laversiónampliadadeunodeestosciclosdedescargadecargasemuestraacontinuación:

Como puede ver, hay una gran cantidad de errores, pero podemos distinguir la forma de onda real. que esta causando este problema? ¿Cómo puedo corregir esto?

También, tengo un problema con las lecturas de ADC. He establecido la referencia del ADC SAR como el valor interno por defecto de 2.56 V. Como lo entiendo, se supone que el ADC de 8 bits me da 0 (Ox00) a 0 V y 255 (OxFF) a 5 V. Pero aquí obtengo 124 para 0 V y 255 para 5 V. ¿Por qué sucede esto? Como se muestra, multiplicar los valores obtenidos en el ADC por 5/255 no me da los valores de voltaje originales. El 'offset' de 2.5 V que se muestra se debe a este error de reconocer 0 V como 124. Pero no sé por qué sucede esto.

Se muestra el código C en el extremo del microcontrolador. El programa también genera dos pulsos que se utilizan para activar los ciclos de carga y descarga del condensador (los pulsos se envían a la puerta de dos interruptores MOS).

#define F_CPU 1000000UL

#include <avr/io.h>
#include <util/delay.h>

#define USART_BAUDRATE 9600 
#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)  //Calculating prescaler for serial communication

int main(void)
{
    uint32_t i;

    UCSRB |= (1 << RXEN) | (1 << TXEN);  //Enable serial transmission and reception
    UCSRC |= (1 << URSEL) | (1 << UCSZ0) | (1 << UCSZ1); //Set character size (8 bits). When URSEL is 1, we can write data to UBRRH register. 
        UBRRH = (BAUD_PRESCALE >> 8);  \Setting the prescale
        UBRRL = BAUD_PRESCALE;  //Set prescale value
//DDRD = 0xff;   \Set port D as output (for pulses)
ADMUX = (1<<REFS0) |(1<<ADLAR)|(1<<REFS1); \Set reference voltage to internal and left adjust result (out of 10 bit result, 8 bits are moved to ADCH register).
ADCSRA = (1<<ADEN)|(1<<ADFR); \Enable ADC in free running mode
//|(1<<ADPS2) |(1<<ADPS1) |(1<<ADPS0);  
//
ADCSRA|=(1<<ADSC); \Start conversion
DDRB = 0xff;    \Set port B as output (for pulses)
    while(1)
    {
    for (i = 0; i< 200; ++i)
        {
        PORTB = 0x01; \First bit of port B will be high pulse for duration of loop.

//      ADCSRA|=(1<<ADSC);
        while ((UCSRA & (1 << UDRE)) == 0) {}; \a while loop (with no body) that continues as long as the UDRE bit is set. UDRE is set when it is ready to send data
             UDR = ADCH;  \Read ADC data

//      PORTB = 0x01;
        }

    PORTB = 0x00;  \Set all ports off for a brief interval (for nonoverlapping of charge and discharge cycles)
    _delay_ms(5);

    for (i = 0; i<400; ++i)
        {
        PORTB = 0x02; \Setting second bit of port B high. To activate discharge cycle.

//      ADCSRA|=(1<<ADSC);
        while ((UCSRA & (1 << UDRE)) == 0) {}; \a while loop (with no body) that continues as long as the UDRE bit is set. UDRE is set when it is ready to send data
             UDR = ADCH; 

//      PORTB = 0x02;
        }  
    }
return 1;
}
    
pregunta Analon

2 respuestas

3
  

He establecido la referencia del SAR ADC como el valor interno por defecto de 2.56 V. Como lo entiendo, el ADC de 8 bits se supone que me da 0 (Ox00) a 0 V y 255 (OxFF) a 5 V.

No, ese no es el caso. un resultado de 0 representa \ $ V_ {in} = \ frac {ADC \ times 2.56V} {256} = 0 \ $ y un resultado de 255 representa \ $ V_ {in} = \ frac {ADC \ times 2.56V} {256} = 2.55V \ $

Por supuesto, en este caso, para obtener la representación de voltaje, simplemente puede dividir el resultado del ADC por 100 (255 se convierte en 2.55 V), o puede multiplicar por 10 para obtener el resultado en mV (255 se convierte en 2550 mV).

En el código que ha proporcionado, ha comentado la línea que establece el preescalador de reloj ADC, lo que significa que el reloj ADC está configurado a 1MHz y puede reducir la precisión.

//|(1<<ADPS2) |(1<<ADPS1) |(1<<ADPS0); 

También tenga en cuenta que el prescaler seleccionado en caso de que use la línea anterior es 128, lo que resultará en 1MHz / 128 = 7.8KHz, que es demasiado bajo. Debes intentar estar en el rango de 50KHz-200KHz. Puede utilizar un valor de 8 que resulta en 125 KHz.

(0<<ADPS2) | (1<<ADPS1) | (1<<ADPS0)

También cuando use el voltaje de referencia interno, debe agregar un condensador al pin AREF.

De acuerdo con la hoja de datos, el error para una velocidad de transmisión de 9600 cuando el AVR se ejecuta a 1MHz es demasiado alto, por lo que los datos transferidos pueden estar dañados. Trate de usar 4800.

    
respondido por el alexan_e
2
while ((UCSRA & (1 << UDRE)) == 0) {}; \a while loop (with no body) that continues as long as the UDRE bit is set. UDRE is set when ADC is ready to send data

Confunde el indicador U SART Data Register Empty con el indicador ADC Conversion Complete .

Lo mejor con respecto a la eficiencia de tiempo es:

  • no usa el modo de ejecución libre

  • comience a transmitir un byte a través de USART (serie)

  • iniciar la conversión de ADC
  • espera a que se complete la conversión de ADC
  • espere a que se complete la transmisión de USART (que asumo que toma más tiempo que la conversión ADC)
  • lee el valor de ADC
  • repetir hasta que sea falso

Marque esta prueba de concepto que lee el ADC en un bucle y lo convierte en PWM. El bucle espera la finalización de la conversión ADC. La finalización de la transmisión de USART ya está en su código original.

En el modo de ejecución libre, la conversión de ADC se reinicia cuando lee el registro de datos. Si vuelve a leer el registro de datos antes de que se complete la conversión, el resultado no está definido. Eso es lo que está viendo, algunos bits en su resultado están 'dañados'.

    
respondido por el jippie

Lea otras preguntas en las etiquetas