Ruido específico al usar arduino ADC en modo de ejecución libre

1

Para hacer un osciloscopio en un entorno matlab, para la adquisición de datos en el lado arduino, cuando se utiliza el analogRead() incorporado, funciona bien, pero con una tasa de muestreo muy baja, se observa claramente el aliasing. Eso también, muestreo no uniforme. Por lo tanto, enumerar los inconvenientes:

  1. Velocidad de datos muy lenta, incluso si se envía con 115200 baudrate,
  2. Aliasing
  3. Muestreo no uniforme

Porlotanto,parasuperarloanterior,seusóADCenelmododeejecuciónlibre,con16comofactordepreescalado,yporlotantounatasademuestreode76.9KHz(contandocadaADCcomo13ciclosdereloj).Porlotanto,losdatossemuestreanuniformementeahora.Tambiénesbastanterápido,debidoalmuestreo,yseobserva.Elúnicoproblemaqueexisteahoraesquelasalidatieneunruidoespecífico.Losdatosquesemuestreansonunaformadeondadecorrientesinusoidalde50HzporelsensordecorrienteACS712.Superponelaformadeondadelacorrienteinstantáneaconunsesgode2.5V.Porlotanto,cuandolaseñalnoestápresente,seobservaunvoltajeconstantede2.5V,porlotanto,512,debidoalmapeoalrangode255..127.Peroenelcasodelmododefuncionamientolibre,juntocon127,191,63soloseobservan.Ytambiénsepuedeverquecasi127=63*2,y191=63*3.Ycuandoexistelaformadeondaactual,estámuydistorsionada,peroesperceptiblequenoeslaseñalanteriordesolo127,191,63.Enlagráficadeabajo,lacorrientesepasadesde33.5seg.

No puedo entender este ruido estructurado observado. ¿Cuál puede ser la razón? Una vez leí, los últimos dos bits de MSB se vuelven ruidosos a esta velocidad de muestreo, pero entonces, ¿cómo 127 saltaría a 191. ¿Por qué se agregan 63 restas en cada instante? Entiendo que la razón para el muestreo no uniforme ahora es debido a Serial.print() , cuyas interrupciones están obstruyendo las interrupciones ADC, pero no entiendo la razón detrás del ruido observado.

A continuación se muestra el código subido en arduino. Los datos en serie se leen desde matlab mediante la función fread() .

long t1=0,ts1=0,ts2=0;
int aval=0, val=0;

void setup() {

 TIMSK0 = 0x00;           // disable timer (causes anoying interrupts)
 DIDR0 = 0x3F;            // digital inputs disabled
 ADMUX = 0x40;            // measuring on ADC0, right adjust, AREF reference
 ADCSRA = 0xAC;           // AD-converter on, interrupt enabled, prescaler = 16
 ADCSRB = 0x00;           // AD channels MUX on, free running mode
 bitWrite(ADCSRA, 6, 1);  // Start the conversion by setting bit 6 (=ADSC) in ADCSRA
 sei(); 
 Serial.begin(115200); 
 t1=millis(); 
 }

ISR(ADC_vect)
{
 aval = ADCL;    
 aval += ADCH << 8; 
} 

void loop() {
val = map(aval, 0, 1023, 0, 255);
Serial.write(val);
delay(10);
}
    

1 respuesta

3

Parece que tienes varias cosas sucediendo. Aliasing es muy probable. Primero, estás enviando datos a 115200 baudios. Eso es en bits por segundo, por lo que con 10 bits por byte, se necesitan unos 200 uS para enviar un intte de 2 bytes. Eso es alrededor de 5K de ancho de banda. Usted dice que está muestreando a 76.9 K, muestras por segundo.

Luego, está haciendo un poco de matemática (map ()), razonablemente complicada, para un micro de 8 bits, en los datos que pueden tener un impacto en la respuesta de muestreo. Y tienes un retraso. Todo eso tendrá un impacto en la tasa de muestreo.

Además de eso, y probablemente más importante, está actualizando la variable 'aval' en su interrupción de ADC. 'aval' es un int de dos bytes, por lo tanto, en un procesador de 8 bits, se necesitan dos movimientos de memoria para guardar el valor. ¿Cómo garantiza que no recibe una interrupción entre los movimientos de bytes y que 'aval' sea la mitad de una lectura y la mitad de una lectura diferente?

Entonces estás ejecutando la función map () en esos datos. ¿Es re-entrante la función map ()? Si la función de mapa recupera los datos 'aval' varias veces en el lado de la función, es probable que los datos se actualicen por la interrupción durante ese tiempo.

Intentaría sincronizar la interrupción a su bucle principal para que el valor 'aval' no cambie mientras está operando en él. Me gustaría crear otro int y, al comienzo de su ciclo principal, deshabilitar interrupciones, copiar 'aval' a esa nueva variable, volver a habilitar las interrupciones y luego operar en la nueva variable.

Eso puede aclarar algunas cosas, pero creo que todavía tendrá un problema de ancho de banda entre el muestreo y las comunicaciones.

    
respondido por el JCM II

Lea otras preguntas en las etiquetas