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

Para hacer un osciloscopio en un entorno matlab, para la adquisición de datos en el lado de arduino, cuando analogRead()se usa incorporado, funciona bien, pero con una tasa de muestreo muy baja, ese alias se observa claramente. Eso también, muestreo no uniforme. Así enumerando los inconvenientes:

  1. Tasa de datos muy lenta, incluso si, enviados con 115200 baudios,
  2. alias
  3. Muestreo no uniforme

Forma de onda observada, analogRead()

Por lo tanto, para superar lo anterior, se utilizó ADC en modo de ejecución libre, con 16 como factor de preescala, por lo tanto, una frecuencia de muestreo de 76,9 KHz (contando cada ADC como 13 ciclos de reloj). Por lo tanto, los datos se muestrean uniformemente ahora. También es bastante rápido, debido al muestreo, y se observa. El único problema que existe ahora es que la salida tiene un ruido específico. Los datos que se muestrean son una forma de onda de corriente sinusoidal de 50 Hz mediante el sensor de corriente ACS712. Superpone una forma de onda de corriente instantánea sobre una polarización de 2,5 V. Por lo tanto, cuando la señal no está presente, se observa un voltaje constante de 2.5 V, por lo tanto, 512, debido al mapeo al rango 255. 127. Pero en el caso del modo de funcionamiento libre, junto con 127, 191, 63 solo se observan . Y también se puede ver que casi 127 = 63*2 y 191 = 63*3. Y cuando existe una forma de onda actual, está muy distorsionada, pero es perceptible queForma de onda observada, modo de ejecución libre

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

A continuación se muestra el código cargado en arduino. Los datos en serie se leen de matlab por fread()función.

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);
}

Respuestas (1)

Parece que tienes varias cosas en marcha. La creación de alias es muy probable. Primero, está enviando datos a 115200 baudios. Eso es en bits por segundo, por lo que con 10 bits por byte, se necesitan alrededor de 200 uS para enviar un int de 2 bytes. Eso es alrededor de 5K de ancho de banda. Dice que está muestreando a 76,9 K, muestras por segundo.

Luego, está haciendo cálculos matemáticos razonablemente complicados (mapa()), 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 lo más importante, está actualizando la variable 'aval' en su interrupción ADC. 'aval' es un int de dos bytes, por lo que, en un procesador de 8 bits, se necesitan dos movimientos de memoria para guardar el valor. ¿Cómo garantiza que no reciba una interrupción entre movimientos de bytes y que 'aval' sea la mitad de una lectura y la mitad de una lectura diferente?

Entonces está realizando la función map () en esos datos. ¿La función map() es reentrante? Si la función map recupera los datos 'aval' varias veces dentro de la función, es probable que la interrupción actualice los datos durante ese tiempo.

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

Eso puede arreglar un poco las cosas, pero creo que aún tendrá un problema de ancho de banda entre el muestreo y las comunicaciones.