Comportamiento extraño del ADC (ATmega)

Estoy construyendo un osciloscopio de hobby en ATmega16. Estoy probando ADC generando una onda cuadrada a 2 kHz con pequeña amplitud y aplicándola al pin ADC a través de una entrada capacitiva con un divisor de voltaje para cambiar el nivel cero.

esquemático

Así es como se ve la señal después de ser muestreada por ADC:esquemático

Se ve bien, pero después de que empiezo a cambiar el nivel cero ajustando el potenciómetro, obtengo estos picos extraños:esquemático

Después de cambiar el nivel un poco más alto, se ve bien de nuevo:esquemático

Y luego el patrón se repite:esquemático esquemático esquemático

En general, obtengo 3 rangos donde aparecen los picos.

algo de información

  • AVR está funcionando a 16MHz
  • ADC utiliza un voltaje de referencia interno de 2,56
  • ADC está en modo de ejecución libre a 125 kHz (prescaler = 128)
  • Transfiero datos a través de CP210 a una tableta Android que se utiliza para el trazado en tiempo real. El circuito también se alimenta desde la tableta. Obtengo los mismos resultados cuando el circuito está conectado a la PC.
  • La tasa de baudios USART es 500000b/s (UBRR=1)
  • AVcc y AREF no están conectados. También intenté conectar AVcc a Vcc y agregar un límite de .1uF entre Gnd y AVcc, pero esto no tuvo ningún efecto.

Algo más de información

  • este ruido no proviene del generador (probado con osciloscopio analógico)
  • este ruido no viene del potenciometro
  • LFUSE = 0xFF, HFUSE = 0x89.

Rutina de inicialización de ADC

ADMUX = (1 << REFS0); // AVCC with external capacitor at AREF pin
ADCSRA = (1 << ADEN)
        | (1 << ADIE)
        | (1 << ADATE) 
        | (1 << ADPS0)
        | (1 << ADPS1)
        | (1 << ADPS2); // Division factor = 128
MCUCR |= 1 << SM0;
MCUCR |= 1 << SE; // Sleep-mode enabled
ADCSRA |= (1 << ADSC);

Rutina de transferencia de datos ADC

volatile uint8_t adcLow;
volatile uint8_t adcHigh;

int main(void) {
    ....
    while (1) {
        if (ADCSRA != 0x00) {
            USARTSendByte(adcLow);
            USARTSendByte(adcHigh);
        }
    }
}

ISR(ADC_vect) {
    adcLow = ADCL;
    adcHigh = ADCH;
}
¿Has probado a usar otra olla?
Sí tengo. La olla no causa el problema.
¿Es un único punto de datos en sus datos o hay múltiples puntos de datos que componen ese pico? O dicho de otra manera: ¿Es solo una sola medida la que causa el pico? Además: ¿Eso también sucede cuando muestreas con una velocidad más baja?
Cuando use avr-gcc, puede usar el siguiente atajo:uint16_t adcValue = ADC;
No tengo un generador en este momento, así que tendré que probarlo mañana. No es posible muestrear a una velocidad más baja porque el preescalador es 128 (que es el valor más alto posible). Sin embargo, intenté usar una tasa de baudios de usart más lenta, pero no ayudó.
@jippie gracias por la sugerencia, pero estaba dividiendo los resultados de ADC intencionalmente, porque solo puedo enviar un byte a la vez a través de usart.
Creo que es mejor establecer su propia bandera en el ISR que depender de ADCSRA, creo que está experimentando una condición de ejecución con ADSC y ADIF. O pruebe un bit en particular en el registro.

Respuestas (1)

Los picos claramente se recortan a valores muy particulares (probablemente una potencia de dos) o está utilizando números enteros con signo que son demasiado pequeños para contener el valor total.

No proporcionó el código fuente completo, así que supongo que aquí. Probablemente intente ajustar el valor medido a un número entero demasiado pequeño. Haz un volcado de los valores que obtengas y encuentra los picos en ellos. Luego observe la representación binaria de estos números y vea si puede encontrar algo en común.

Con una estimación rápida, la distancia entre dos picos es de aproximadamente 1,28 V, un poco coincidentemente demasiado cerca del tamaño de un número entero de 8 bits con signo.

Aconsejo usar definiciones de tipo como int8_t[-128:127], uint8_t[0:255], int16_t[-32768:32767], uint16_t[0:65535], int32_t[-2147483648:2147483647] y uint32_t[0:4294967295], que muestra claramente cómo grande es la variable.

Lo siento, actualicé mi pregunta con el código fuente. adcLowy adcHighson del uint8_ttipo por lo que el tamaño es suficiente para contener valores ADC.
¿Mordido por el error de tipeo entonces?
Este podría ser el caso. Estoy convirtiendo valores recibidos como este: int value = (buffer[i + 1] << 8 | (buffer[i] & 0xFF))en Java.
Tenía razón en que estos picos están relacionados con el software. Acabo de descubrir que ocurren debido a un error de transmisión. aqui hice otra pregunta
Espera... ¿no son uint8_t [0, 255] e int8_t [-128, 127]? ¿No estaba la U haciendo el tipo sin firmar?
@geoh ups, vamos a corregir eso. Buena atrapada.