Procesamiento y visualización de señales en la frecuencia de conversión ADC. Mejorar fácilmente la precisión del ADC de Arduino

Continuemos nuestro conocimiento de la plataforma Arduino y en este artículo veremos las entradas analógicas.

El uso principal de las entradas analógicas en el tema Arduino es leer los valores de los sensores analógicos. Al mismo tiempo, no olvide mencionar que las entradas analógicas se pueden usar como puertos de entrada/salida digital discutidos en la lección anterior (más sobre esto al final del artículo).

Hay 6 de ellos en la placa Arduino UNO (A0-A5). Para otras tablas, la cantidad puede variar, consulte la especificación.

Gracias al integrado ADC(convertidor de analógico a digital), estas entradas pueden leer el voltaje que se les aplica. Los microcontroladores Atmega 328 utilizados en Arduino UNO contienen un ADC de seis canales con una resolución de 10 bits. Esto permite que la salida reciba valores de 0 a 1023 (1024 gradaciones en total).

// Leer desde la entrada analógica A0 lectura analogica(0);

Esta función devuelve un valor de 0 a 1023 proporcional al voltaje en la entrada analógica

Ejemplo en la práctica

Como primer ejemplo de trabajo con entradas analógicas, conectemos un potenciómetro.

Para nuestra tarea, los potenciómetros de una sola vuelta que se muestran en la imagen son perfectos. A pesar de diferencias externas tan significativas, no son muy diferentes. Por ejemplo, puedes usar cualquiera de ellos. Un potenciómetro grande con giro es sin duda más cómodo de usar, pero tiene patas gruesas que aflojan rápidamente los contactos de la placa. Si tiene un destornillador a mano, cuando trabaje con una placa de prueba, es mejor usar un potenciómetro cuadrado.

Para el experimento necesitamos:

Conversión de un valor de señal analógica a voltios

Para convertir el valor resultante a voltios, es suficiente calcular paso y lo multiplicamos por el valor resultante.

Para calcular el paso, divida el voltaje de referencia por 1024 gradaciones

5V / 1024 = 0,0049 voltios

Aquellos. Con el valor analógico recibido de 500, (500 * 0,0049) llegan 2,45 V al puerto del controlador.

ejemplo de código:

Paso flotante = 5.0F / 1024; vacío configuración () { De serie.begin(9600); // Establecer la velocidad del monitor de puerto) vacío bucle() (int analogValue = analogRead(0); // Establecer la variable analogValue para leer las lecturas float voltageValue = analogValue * Step; // Convertir a voltios (indicación * paso) De serie.println(valor de voltaje); // Envía el valor en voltios al puerto retraso (500); // Espera medio segundo }

Operación de entrada analógica más precisa

Para lograr lecturas más precisas desde la entrada analógica, se pueden utilizar 2 opciones:

. función analogReference()

Establece el voltaje de referencia con respecto al cual se realizan las mediciones analógicas.

analogReference(tipo);

Configuraciones posibles ( tipo):

POR DEFECTO : establecido por defecto. con esta configuración, la tensión de referencia se toma automáticamente como la tensión de alimentación de la placa Arduino. 5V (para plataformas de 5V) o 3,3V (para plataformas de 3,3V)

En plataformas Arduino listas para usar AREF No involucrado. En este caso, al configurar DEFAULT, se conecta un voltaje interno a la salida AVCC. La conexión es de baja impedancia y cualquier voltaje aplicado al pin en este punto puede dañar el chip ATmega..

INTERNO : referencia de voltaje incorporada 1,1 V en microcontroladores ATmega168 y ATmega328, y 2.56 EN en ATmega8.

Esto puede ser útil para una medición más precisa del voltaje que se encuentra en el rango a continuación 1,1 V o 2,56 V. El trabajo preciso de Bolle se logra gracias al paso más pequeño 5/1024 frente a 1,1/1024. Los valores iguales o superiores a 1,1 V (2,56 V) serán convertidos por el ADC a 1023.

EXTERNO : Referencia de tensión externa conectada al pin AREF.

Después de configurar la función, ambas fuentes internas se apagan. Ahora puede conectar un voltaje externo, que será la referencia para el ADC. Se recomienda conectar voltaje externo al pin AREF a través de una resistencia de 5 kΩ.

. Ajuste manual de la tensión de referencia

Relevante para medir voltaje extremadamente bajo

Las distorsiones al trabajar con entradas analógicas aparecen debido a que, por defecto, se toma como tensión de referencia 5V, mientras que los reguladores de tensión de la placa Arduino pueden desviarse ligeramente del valor de referencia y dar, por ejemplo, 4,85V. 4,85 / 1024 = 0,0047 (con un paso de referencia de 0,0049)

Si tiene un multímetro preciso a mano, simplemente puede medir el voltaje de suministro y convertirlo en el cálculo discutido anteriormente.

paso de flotación = 4,85F/1024; // Calcular paso Uref / por gradación

Uso de entradas analógicas como salidas digitales

Las entradas analógicas se pueden usar como puertos de entrada/salida digital que se analizaron en la lección anterior.

Para ello, para UNO, en el código deben escribirse como digitales del 14 al 19. Por ejemplo, para A0

// Inicializa el pin analógico 0 como salida pinMode(14, SALIDA); // Inicializa el pin analógico 0 como entrada pinMode(14, ENTRADA);

En esta lección, veremos los puertos analógicos Arduino A0-A5. Analicemos el principio de funcionamiento de los puertos analógicos, qué se puede conectar a ellos. Utilizando una placa de pruebas montaremos un circuito de luminaria regulable para que con la ayuda de un potenciómetro (resistencia variable) sea posible cambiar la luminosidad del LED. Considere la directiva #definir Y lectura analógica en el lenguaje IDE de Arduino.

El dispositivo y el principio de funcionamiento del potenciómetro.

Una resistencia variable (potenciómetro) al girar la perilla cambia la resistencia en el circuito eléctrico de cero a una resistencia nominal de 10 kOhm. El potenciómetro se compone de una superficie conductora: una resistencia constante plana con dos contactos y un colector de corriente que se desliza a lo largo de la superficie. El potenciómetro está diseñado para ajustar el voltaje en el circuito eléctrico.

Resistencia variable tiene una superficie conductora sólida porque la posición de ajuste del potenciómetro cambia constantemente. Una resistencia variable se usa para uso regular, por ejemplo, para cambiar el nivel de volumen.

Resistencia de corte Se utiliza para afinar el funcionamiento de los dispositivos electrónicos. La posición de ajuste, por regla general, no cambia durante toda la vida útil del dispositivo. Por lo tanto, mover el contacto deslizante se realiza con un destornillador y la resistencia de la capa conductora no es de gran importancia.

Entradas analógicas en Arduino

El microcontrolador Atmega de Arduino contiene un convertidor de analógico a digital (ADC) de seis canales. La resolución del convertidor es de 10 bits, lo que le permite recibir valores de 0 a 1023. El uso principal de las entradas analógicas de Arduino (A0 - A5 en Arduino UNO) es leer valores de sensores analógicos. Considere usar una entrada analógica para tomar lecturas de un potenciómetro.


El pequeño valor de la división de escala hace posible obtener los valores de casi cualquier cantidad física con gran precisión. Para leer la entrada analógica, utilice la función lectura analógica. Los puertos analógicos, como los Arduinos digitales, se pueden hacer usando el comando digitalRead, que se usa para leer datos de un botón y digitalWrite, puede conectar un LED.

Luminaria regulable

En esta lección, ensamblaremos el circuito eléctrico de una lámpara regulable. Usando un potenciómetro, podemos cambiar el brillo del LED conectado al pin 9. El potenciómetro se conecta con las patas extremas a los puertos 5V y GND, el valor del voltaje se toma de la pata central a la entrada analógica A0.

Para la lección necesitamos los siguientes detalles:

  • placa Arduino Uno / Arduino Nano / Arduino Mega;
  • tabla de pan;
  • potenciómetro;
  • 1 LED y resistencia de 220 Ohm;
  • cables macho-macho.

Ensamble el circuito eléctrico como se muestra. La pata central de la resistencia variable está conectada al puerto analógico A0 para tomar lecturas de voltaje. No importa cuál de las patas extremas conectar a los puertos 5V y GND, solo cambiará la dirección de rotación de la perilla del potenciómetro para aumentar el brillo del LED. Después de construir el circuito, conecte su Arduino a su computadora y cargue el siguiente boceto.

Boceto para Arduino y potenciómetro

// Asigne un nombre al pin con el LED (ing. "led")#definir LED_PIN 9 // Asignar un nombre al pin del potenciómetro#define POT_PIN A0 void setup() ( // se emitirá pin con LED pinMode(LED_PIN, SALIDA); // el pin con el potenciómetro será la entrada pinMode(POT_PIN, ENTRADA); // Inicie el monitor de puerto serie // descomentar // Serial.begin(9600);) bucle vacío () ( // declara que usaremos 2 variables - rotación y brillo // almacenaremos solo números enteros en variables (ing. "entero") rotación int, brillo; // la rotación es igual a los valores del potenciómetro en el rango de 0 a 1023 rotación = lectura analógica (POT_PIN); // el brillo variable será igual a la rotación dividida por 4 // el brillo solo puede ser un número entero, la parte fraccionaria se descartará // como resultado, la variable de brillo estará en el rango de 0 a 255 brillo = rotación / 4; // emite el voltaje calculado por la fórmula brillo = rotación / 4 escritura analógica (LED_PIN, brillo); // Enviar el valor de rotación al monitor del puerto serie // descomentar // Serial.println(rotación); // descomentar // retraso (1000); }

Explicaciones para el código:

Además de las señales digitales, Arduino puede utilizar tanto señales de entrada como de salida analógicas.

Una señal analógica es una señal que puede tomar cualquier número de valores, a diferencia de una señal digital que solo tiene dos valores: alto y bajo. Para medir el valor de las señales analógicas, el Arduino tiene un convertidor de analógico a digital (ADC) incorporado. El ADC convierte el voltaje analógico en un valor digital. Función que se utiliza para obtener el valor de una señal analógica: analogRead(pin) . Esta función convierte el valor de voltaje en el pin de entrada analógica y devuelve un valor digital de 0 a 0123, relativo al valor de referencia. Para la mayoría de Arduinos, el voltaje de referencia es 5V, 7V para Arduino Mini y Nano, y 15V para Arduino Mega. Solo toma un parámetro: el número de pin.

El Arduino no tiene un convertidor de digital a analógico (DAC) incorporado, pero puede usar una señal digital modulada por ancho de pulso (PWM) para implementar funciones de salida analógica. Función utilizada para generar una señal PWM: analogWrite(pin, value) . pin es el número de pin utilizado para la salida PWM. El valor es un número proporcional al ciclo de trabajo de la señal. Cuando value = 0 , la salida siempre es un cero lógico. Cuando value = 255 , la salida siempre es lógica. En la mayoría de las placas Arduino, las funciones PWM están disponibles en los pines 3, 5, 6, 9, 10 y 11. La frecuencia de la señal PWM en la mayoría de los pines es de aproximadamente 490 Hz. En placas Uno y similares, los pines 5 y 6 funcionan a aproximadamente 980 Hz. Los pines 3 y 11 del Leonardo también funcionan a 980 Hz.

Para mapear un valor de entrada analógica que va de 0 a 1023 a una salida PWM que va de 0 a 255, puede usar la función map(value, fromLow, fromHigh, toLow, toHigh). Esta función tiene cinco parámetros: el primero almacena el valor analógico, y los demás son 0, 1023, 0 y 255, respectivamente.

Experimento 1: control del brillo de los LED

En este experimento, controlaremos el brillo de un LED usando una señal PWM en un pin de salida analógica.

Componentes requeridos

  • 1 LED
  • 1 resistencia

Diagrama de conexión

Como se muestra en el siguiente diagrama, el LED está conectado al pin 2 del Arduino. Para cambiar el brillo del LED, el programa cambiará el ciclo de trabajo de la señal PWM en el pin 2.

Código de programa

constante int pwm = 2; // etiqueta el pin 2 como 'pwm' void setup() ( pinMode(pwm,OUTPUT); // establece el modo del pin 2 como salida) void loop() ( analogWrite(pwm,25); // establece el ciclo de trabajo en 25 delay(50); // 50ms de retraso analogWrite(pwm,50); delay(50); analogWrite(pwm,75); delay(50); analogWrite(pwm,100); delay(50); analogWrite (pwm,125 ); retraso (50); escritura analógica (pwm, 150); demora (50); escritura analógica (pwm, 175); demora (50); escritura analógica (pwm, 200); demora (50); escritura analógica (pwm, 225); retardo (50); escritura analógica (pwm, 250); )

Experimento 2: control del brillo del LED con un potenciómetro

En este experimento, controlaremos el brillo del LED usando un potenciómetro. Usaremos la función analogRead() para leer el voltaje y la función analogWrite() para generar una señal PWM cuyo ciclo de trabajo es proporcional al voltaje analógico.

Componentes requeridos

  • 1 potenciómetro
  • 1 LED
  • 1 resistencia

Diagrama de conexión

Ensamble el circuito como se muestra a continuación. A medida que gira la perilla del potenciómetro, el voltaje en el pin A0 cambiará. Después de eso, el programa cambiará el ciclo de trabajo de la señal PWM en el pin 2, cambiando el brillo del LED.


Código de programa

constante int pwm = 2; // etiqueta el pin 2 como variable 'pwm' const int adc = 0; // designar el pin 0 utilizado como // entrada analógica como variable 'adc' void setup() ( pinMode(pwm,OUTPUT); // establecer el modo pin 2 como salida ) void loop() ( int adc = analogRead (0); // lee el voltaje analógico y // almacena su valor en una // variable entera adc = map(adc, 0, 1023, 0, 255); /* ---------- function map - -- --------- La función anterior escala el valor de salida de un ADC, que tiene 10 bits de ancho y produce valores entre 0 y 1023, a valores entre 0 y 255 para la función analogWrite, que solo acepta valores en ese rango.* /analogWrite(pwm,adc) ; )

El propósito del trabajo: Consideración de las características de entrada y visualización de señales de banda ancha.
El cometido del trabajo: Construir un canal de entrada, procesamiento y visualización de señales a la máxima frecuencia de conversión del ADC del controlador Arduino.
Instrumentos y accesorios: controlador Arduino UNO, paquete Simulink MatLAB (R2012).

INTRODUCCIÓN

El desarrollo de herramientas de software para monitorear, analizar y procesar señales a nivel del controlador requiere una cantidad significativa de tiempo. Conectar el controlador a un entorno especializado de alto nivel (Fig. 1) puede reducir significativamente el tiempo de diseño de un algoritmo para el controlador, teniendo en cuenta las limitaciones de sus recursos.

MatLAB es un buen ejemplo de un poderoso entorno especializado para trabajar con señales. Para analizar señales, a menudo es necesario observar su espectro en la banda de frecuencias más amplia posible. Para hacer esto, el controlador debe recibir señales a la máxima frecuencia de conversión del ADC.

En este trabajo se describe en detalle la construcción del canal de trabajo “Arduino UNO - MatLAB” para el monitoreo y procesamiento de señales en tiempo real a la frecuencia límite de la conversión ADC. Una característica de este canal es que los relojes en tiempo real no son configurados por MatLAB, sino por el controlador Arduino. Tal construcción no requiere compilar el modelo de Simulink con la biblioteca en tiempo real (rtwin.tlc), lo que permite usar casi cualquier bloque de la biblioteca de Simulink en el modelo.

Arroz. 1. Comparación de herramientas de desarrollo de algoritmos. Para diseñar algoritmos a nivel de un entorno especializado, se requiere un canal de transmisión de datos entre el controlador y el entorno de diseño.

INFORMACIÓN GENERAL

Medios de acumulación, análisis, procesamiento y visualización de señales.
Este trabajo utiliza el entorno Simulink para recibir y mostrar datos del controlador Arduino.

Simulink es un entorno interactivo y un lenguaje de programación para el modelado de simulación que le permite crear modelos de procesos dinámicos mediante diagramas de bloques. Simulink está integrado en el entorno MatLAB. La integración le permite utilizar bibliotecas de bloques listas para usar, algoritmos matemáticos incorporados, potentes herramientas de procesamiento de datos y visualización gráfica para resolver toda la gama de tareas, desde el desarrollo del concepto del modelo hasta las pruebas, la verificación, la generación de código y la implementación de hardware.

La composición de los paquetes de extensión de la biblioteca Simulink en el ejemplo del paquete de procesamiento de señales digitales "DSP System Toolbox" se muestra en la Fig. 2.


Arroz. 2. Un ejemplo de un paquete adicional de extensión de Simulink para modelar sistemas de procesamiento de señales: DSP System Toolbox. El paquete utiliza los últimos algoritmos de análisis espectral. Se resaltan los contenidos de la sección Estimación del espectro de potencia: bloques para la estimación de la señal espectral.

transmisión de datos
El uso de dos búferes para la acumulación y transmisión de datos permite organizar la recopilación, el procesamiento y la visualización de datos sin interrupciones (para evitar la pérdida de datos, la velocidad del proceso posterior no debe ser inferior a la velocidad del proceso anterior ).

Un ejemplo del uso de tal organización puede ser el módulo E14-440 para entrada, salida y procesamiento multicanal de información analógica y digital, conectado a una computadora a través del bus USB.

Los datos de entrada se ingresan primero en la primera mitad del FIFO del búfer ADC. Una vez que se llena, los datos comienzan a transmitirse a la PC, mientras que la recopilación de datos en la segunda mitad del búfer FIFO no se detiene. Después de la acumulación de datos en la segunda mitad del búfer FIFO, la transferencia de datos a la PC comienza nuevamente y la recopilación de datos continúa en paralelo ya en la primera mitad.

CONSTRUYENDO UN OSCILOSCOPIO BASADO EN EL CONTROLADOR ARDUINO

Tasa máxima de adquisición de datos ADC
Usando la salida del resultado al monitor del editor Arduino a la frecuencia máxima (57600 bps), escribiremos un programa para contar las conversiones de ADC durante un período fijo.

Programa de medición de tasa de conversión ADC:



Configuración vacía () (
Serial.begin(57600); // 9600, 19200, 38400, 57600 y 115200 bit/s
}

Bucle vacío()(
time_start = milisegundos();
para (int i = 0; i< 1024; i++) {

}
fin_tiempo = milisegundos();

serial.println(período);


Arroz. 3. Tiempo (en ms) 1024 y 512 conversiones ADC. Tiempo medio de conversión de ADC: 0,1123 ms (como 115/1024).

Tiempo de escalado de datos ADC
Para convertir datos ADC de 10 bits a datos de 8 bits, use la función
mapa(valor, 0, 1023, 0, 255);
donde val es una variable int con 10 bits significativos.
El programa para medir el tiempo de conversión de ADC con escalado y escritura en la matriz:

Const int adc_5 = A5; // número de puerto ADC
tiempo_inicio largo sin firmar; // Inicio de la captura, ms
fin de tiempo largo sin firmar; // Fin de la captura, ms

Configuración vacía () (

}

Bucle vacío()(
time_start = milisegundos();
para (int i = 0; i< 1024; i++) {
int val = analogRead(adc_5);
}
fin_tiempo = milisegundos();
int periodo = time_end - time_start;
serial.println(período);
}


Arroz. 4. Tiempo (en ms) 1024 conversiones ADC, traducción 10 rublos. datos a 8 bits y escribir en la matriz. Período de conversión ADC con escalado: 0,1611 ms (como 165/1024).

Dado que el tiempo de conversión de ADC es de 0,13 ms, una conversión de datos de 10 bits a formato de bytes (escala) es de 0,0424 ms.

Velocidad de enlace serie
Para determinar la velocidad de transferencia de bytes, el código de carácter Serial.write(1) se pasa al canal serie en un bucle, que no se muestra en el monitor.

El bloque principal del programa para determinar la velocidad de transmisión:

Void loop()( //Haz cosas aquí
Serie.escribir(1);
tasa = tasa + 1;
if (hora > establecer_hora) (
establecer_tiempo = establecer_tiempo + 30; // reloj RT de 30ms
Serial println(tasa);
tasa=0;
}
}

Arroz. 5. Datos de prueba: el número de bytes transferidos al canal serie en 30 ms a una velocidad de 57600 bps.
La prueba mostró que la transferencia de 173 bytes toma 30 ms, en cambio, 1728 bits se pueden transferir en 30 ms a una velocidad de 57600 bps. Por lo tanto, se necesitan 10 bits para transferir un byte. Usando esta relación para el modo de transferencia
bits de datos: 8
paridad: ninguna
Bits de parada: 1
control de flujo: ninguno
es posible calcular el tiempo de transmisión de una matriz de datos a diferentes velocidades.
Transferir, por ejemplo, 256 bytes a 9600 baudios (bps) toma 267 ms, a 57600 baudios toma 44 ms; ya una velocidad de 115200 baudios - 22 ms (como 256 * 10/115200).

Tamaño de la matriz para la acumulación y transmisión de datos
La memoria de acceso aleatorio (SRAM) del Arduino UNO es de 2 KB. La prueba del programa para la lectura cíclica del ADC, el escalado de datos de 10 bits a datos de 8 bits, el reloj y la transferencia de datos byte por byte mostraron que el tamaño máximo de la matriz para acumular y enviar datos no debe exceder los 1800 bytes.

Los programas más complejos pueden requerir más SRAM adicional. Por lo tanto, la matriz para la acumulación y transmisión de datos ADC está limitada a 1024 bytes o 512 palabras.


Arroz. 6. Un trozo de cable conectado a la entrada analógica A5 del controlador Arduino para amplificar la captación observada de la red de 50 Hz.

tabla 1. Tiempos de operación del programa, teniendo en cuenta la inestabilidad de los ciclos.

Un ejemplo de configuración de un canal de visualización de 256 valores escalados de ADC a la velocidad máxima de adquisición y transmisión de datos.
Código de programa del controlador Arduino:
const int adc_5 = A5; // número de puerto ADC
byteadc_bytes; // Búfer para datos ADC escalados

Configuración vacía () (

}

Bucle vacío()(

// captura de datos ADC
para (int i = 0; i< 256; i++) {
int val = analogRead(adc_5);
adc_bytes[i] = mapa(valor, 0, 1023, 0, 255);
}


para (int i = 0; i< 256; i++) {
Serial.write(adc_bytes[i]);
}

Si (hora > establecer_hora) (
establecer_tiempo = establecer_tiempo + 70; // el reloj RT es de 70 ms
}
}


Arroz. 7. Determinación del número de puerto en el entorno Arduino.


Arroz. 8. Modelo Simulink para recibir datos del controlador ADC, escalar el vector de datos a lo largo del tiempo, mostrar datos en tiempo real y almacenar el flujo de datos en la memoria del espacio de trabajo.


Arroz. 9. Parámetros del puerto COM en el entorno Simulink (Bloque modelo: Configuración en serie)


Arroz. 10. Parámetros de los bloques de Simulink del modelo y modo de simulación.

El modelo se inicia presionando el botón Iniciar simulación:

Arroz. 11. Botón de inicio del modelo.


Arroz. 12. Vista de la captación de red (la conexión se muestra en la Fig. 6) con marcos superpuestos (ventana izquierda) y en un marco separado (ventana derecha). El motivo del cambio de señal cuando se superponen fotogramas es la falta de sincronización de la pantalla. Nota: Simulink tiene suficientes instalaciones para construir un canal de temporización.

EJEMPLOS DE RESULTADOS COMPROBADOS Y OPCIONES DE AUTOEVALUACIÓN

Ejercicio 1. Acumulación, transmisión y visualización de datos escalados (ver ejemplo y tabla de tiempos en la página 8).
1. Escriba un programa para que el controlador Arduino UNO recorra las lecturas del ADC, escale, escriba datos en una matriz de 1024 bytes y transfiera la matriz a un canal serie. El programa debe ejecutarse a la máxima velocidad. El carácter A es el encabezado de la matriz transferida.

Ejemplo de programa:

Const int adc_5 = A5; // número de puerto ADC
set_time largo sin firmar; // Hora del próximo reloj
byteadc_bytes; // Búfer para datos ADC

Configuración vacía () (
Serie.begin(115200); // bit/s
}

Bucle vacío()(
mucho tiempo sin firmar = millis(); // Hora actual en ms

// captura de datos ADC
para (int i = 0; i< 1024; i++) {
int val = analogRead(adc_5);
adc_bytes[i] = mapa(valor, 0, 1023, 0, 255);
}

// enviar datos ADC al puerto serie
Serial.print("A"); // "A" es el encabezado
para (int i = 0; i< 1024; i++) {
Serial.write(adc_bytes[i]);
}

Si (hora > establecer_hora) (
establecer_tiempo = establecer_tiempo + 270; // el reloj RT es de 270 ms
}
}

2. En el entorno de MatLAB, cree un programa a partir de bloques de Simulink para recibir y mostrar datos del controlador en tiempo real. La velocidad, el tamaño del paquete, el período de datos recibidos y el ciclo del modelo deben corresponder a los parámetros correspondientes del controlador. Escala el tiempo de los datos mostrados.


Arroz. 13. Modelo Simulink para recibir datos a la máxima frecuencia: 115200 baudios. La concatenación vectorial se utiliza para escalar la señal a lo largo de la escala de tiempo del cuadro.

3. Verifique la calidad del canal "Entrada ADC - Pantalla MatLAB", por ejemplo, por el período de captación de 50 Hz de la red en la entrada ADC. Para aumentar la amplitud de captación, conecte un trozo de cable a la entrada del ADC (vea la Fig. 6). La amplitud de captación depende de la distancia entre el cable y su mano.


Arroz. 14. Superposición de 4 cuadros al escanear una frecuencia de 50Hz en la entrada del ADC del controlador Arduino.


Arroz. 15. Frecuencia de red a la entrada del controlador ADC, 4 cuadros.

Tarea 2. Acumulación, transmisión y visualización de datos ADC de 10 bits.
1. Para el controlador Arduino UNO, escriba un programa para recorrer el ADC, escribir datos en una matriz de 512 palabras y enviar los datos de la matriz byte por byte al enlace serial. El programa debe ejecutarse a la máxima velocidad.

Ejemplo de programa:

Const int adc_5 = A5; // número de puerto ADC
set_time largo sin firmar; // Hora del próximo reloj en ms
palabraadc_int; // Búfer para datos ADC
valor int;
byte val_Lo, val_Hi;

Configuración vacía () (
Serie.begin(115200); // bit/s
}

Bucle vacío()(
mucho tiempo sin firmar = millis();

// captura de datos ADC
para (int i = 0; i< 512; i++) {
adc_int[i] = analogRead(adc_5);
}

// enviar datos ADC al puerto serie
// primero bytes bajos luego bytes altos
Serial.print("A"); // "A" es el encabezado
para (int i = 0; i< 512; i++) {
val = adc_int[i];
val_Lo = (val<< 1) & 0xFE;
Serial.write(val_Lo); // byte bajo
}
para (int i = 0; i< 512; i++) {
val = adc_int[i];
val_Hi = (val >> 6) & 0xE;
Serial.write(val_Hola); // Hola byte
}

Si (hora > establecer_hora) (
establecer_tiempo = establecer_tiempo + 160; // el reloj RT es de 160 ms
}
}

2. Escriba un programa Simulink para recibir la recuperación y mostrar los datos del controlador ADC. La velocidad, el tamaño del paquete y el período de los datos recibidos deben corresponder a los parámetros correspondientes del controlador. Escala el tiempo de los datos mostrados.


Arroz. 16. Programa Simulink para recibir, restaurar y mostrar la matriz de datos del ADC del controlador Arduino UNO.
3. Registre el ruido de la red eléctrica de 50 Hz.


Arroz. 17. Superposición de 15 fotogramas al escanear una captación de red de 50 Hz en la entrada del controlador ADC. Duración del programa: 160 ms. Tiempo para llenar la matriz con datos ADC: 58 ms. Tiempo de transferencia 512x2 bytes a 115200 baudios: 89 ms.


Arroz. 18. Últimos 15 fotogramas. Tiempo de 3,5 ciclos de señal de 50 Hz: 70 ms.

Tarea 3. Procesamiento de señales por programa m MatLAB
1. Guarde los datos en tiempo real en el espacio de trabajo de la memoria MatLAB, por ejemplo, utilizando el bloque simout (consulte la Fig. 13).
2. Copie los datos guardados en el directorio de trabajo, por ejemplo:
guardar("simout_50Hz","simout");
3. Desarrolle un programa m de MatLAB para mostrar la señal ADC archivada del controlador.

Ejemplo de código:

Limpiar todo
carga("simout_50Hz");


tamaño_fotograma = tamaño(simout.Data,1);
muestreo = d_frame/(size_frame + 163*4); %dt
data_size = size(simout.Data,1)*size(simout.Data,2)*size(simout.Data,3);

% tiempo = (0:tamaño_datos-1)*muestreo;
tiempo = ;
for i = 1:longitud(simout.Tiempo)
tiempo = ;
fin

adc = uint8();
para i = 1:tamaño(simout.Data,3)
anuncio = ;
fin

% frame_num = longitud (simout.Time) % o tamaño (adc,3) % es 54 fotogramas

Si 1%
cifras
plot(tiempo, adc, "b")
cuadrícula activa
xlabel("Tiempo, s");


fin


Arroz. 19. Cambio fotograma a fotograma de la interferencia de 50 Hz en la entrada del ADC del controlador Arduino UNO: 24 fotogramas por 0,27 seg.

4. Desarrolle un programa m para calcular los parámetros de la señal, por ejemplo, el período en un marco dado.

Ejemplo de código:

Limpiar todo
carga("simout_50Hz");

D_frame = simout.Tiempo(2)-simout.Tiempo(1);
muestreo = d_frame/((256 + 176)*4); %dt
data_size = size(simout.Data,1)*size(simout.Data,2)*size(simout.Data,3); %<256 x 1 x 54>

%Número de cuadro
yo = 5;
tiempo = (0:1023)*muestreo+simout.Tiempo(i);
adc = simout.Data(:,:,i)";
si 1%
cifras
plot(tiempo, adc, "b")
cuadrícula activa
xlabel("Tiempo, s");
ylabel("ADC, bit");
title ("Marco ADC de 8 bits contra el tiempo");
fin
% período
nivel_comp = 60;
j = 1;
para i = 2:longitud(adc)
if (adc(i) >= nivel_comp) && (adc(i-1)< comp_level)
numero_celda(j) = i;
j = j + 1;
fin
fin
s_período = diff(tiempo(núm_celda));


Arroz. 20. Cambio continuo y puntual de la señal en el cuadro seleccionado. Cuadro de tiempo 5: 1,08… 1,24 seg. Tamaño del vector: 1024 bytes. Por lo tanto, el tiempo de una lectura y escalado de la señal ADC: 0,156 ms.


Arroz. 21. Período de activación de la red 5 tramas: 19,2 ... 19,4 ms.

Tarea 4. Construyendo el espectro de la señal en tiempo real.
1. Para observar el espectro de frecuencia de la señal, conecte el bloque de transformada rápida de Fourier (Spectrum Scope: FFT) de la sección de la biblioteca Simulink > DSP System Toolbox > Sinks a la señal del modelo que se muestra.


Arroz. 22. Modelo con un espectroscopio.


Arroz. 23. Espectro de orientación de la red. La señal de cuadro incluye 1024 amplitudes y 163x4 valores cero.

2. Seleccione el armónico fundamental de la señal: 50 Hz.


Arroz. 24. Señal armónica a una frecuencia de 50 Hz.

3. Conecte el bloque Spectrum Scope: FFT a la señal sin escalar (en el tiempo).


Arroz. 25. Traslado del punto de conexión del espectrógrafo. La entrada es una señal sin escalar con una zona más pequeña de valores cero al final de la matriz (vector).

4. Configure el bloque. Seleccione el tipo de espectro mostrado: Tipo de espectro.


Arroz. 26. Parámetros del espectrómetro de una señal sin escalar de 1024 amplitudes.

Tarea 5. Creación de un canal para transmisión de alta velocidad y procesamiento en tiempo real de datos de 8p sin saltos de datos.
1. Escriba para el controlador Arduino UNO un programa para lectura cíclica de lecturas ADC, escalando y transfiriendo 2048 bytes con un encabezado al canal serial. El programa debe leer las lecturas del ADC a una frecuencia constante sin interrupciones.

Ejemplo de programa:
const int adc_5 = A5; // número de puerto ADC

Configuración vacía () (
Serie.begin(115200); // bit/s
}

Bucle vacío()(
para (int i = 0; i< 2048; i++) {
if (i == 0) Serial.print("A"); // "A" es el encabezado
int val = analogRead(adc_5);
byte adc_byte = map(val, 0, 1023, 0, 255);
Serie.escribir(adc_byte);
}
}

2. Configure el modelo Simulink (MatLAB) para recibir datos del controlador.


Arroz. 27. Un ejemplo de un modelo para mostrar un flujo de datos continuo. Un marco contiene 2048 bytes.

3. Ajuste el tiempo de simulación del modelo (Menú > Simulación > Parámetros de configuración > Solucionador > Tamaño de paso fijo) y el reloj de bloque Recepción en serie > Tiempo de muestra de bloque (consulte la Fig. 10) durante el período de red de 50 Hz.
Tiempo de trama estimado según la Tabla 1: 254 ms (para 1024 bytes) => 508 ms para 2048 bytes En realidad, el tiempo de trama del programa (en el que se realizan alternativamente la lectura y la transmisión del ADC) es de 375 ms.


Arroz. 28. Ámbito vectorial del trazador de tramas. Hay 18,75 períodos de ondas de 50 Hz en el cuadro. Por lo tanto, el tiempo de trama debe ser de 375 ms, y el período de conversión, escalado y transferencia de datos de ADC: 0,1831 ms.

4. En la ventana de comandos de MatLAB, escriba el comando para generar una señal de 5 cuadros.
señal = ;

5. Trace los primeros 5 fotogramas de la señal.


Arroz. 29. Cinco marcos de entrada del modelo.

6. Considere la calidad de los cortes de marcos.


Arroz. 30. Juntas de cinco marcos. Hay distorsiones notables en el primer byte de cada cuadro. Al reemplazar los primeros bytes con valores promedio entre los puntos más cercanos, la distorsión se puede reducir significativamente.

7. Conectar un analizador de espectro a la señal de entrada del modelo. Mira el espectro de la señal en tiempo real.

Arroz. 31. Modelo de visualización del espectro de la señal de entrada (ADC Arduino UNO) en tiempo real.


Arroz. 32. El espectro de la captación de la red en la entrada del ADC del controlador Arduino.

8. Conecte el osciloscopio Time Scope desde la biblioteca Simulink > DSP System Toolbox > Sinks a la señal de entrada del modelo.

Arroz. 33. Osciloscopio en el modelo para mostrar la señal de entrada del controlador Arduino.

9. Configure el osciloscopio para mostrar el contenido del cuadro actual y la frecuencia de la señal.


Arroz. 34. Configuración del osciloscopio Time Scope > Menú > Ver > Propiedades.

10. Ejecute el modelo y observe la estabilidad de los parámetros de la señal.


Arroz. 35. Visualización de la señal y sus parámetros en tiempo real sobre el osciloscopio del modelo Simulink.

La última versión del canal del controlador Arduino - MatLAB, en comparación con las opciones anteriores, tiene las siguientes ventajas.
la memoria del controlador no se utiliza para la acumulación de datos ADC;
proporciona un pequeño ciclo de conversión de ADC con escalado, que es ligeramente mayor que el ciclo de conversión de ADC con escalado en ausencia de transmisión;
no se requiere una escala de tiempo de la señal en el modelo de Simulink;
el modelo contiene menos bloques;
tamaño de vector y tiempo de marco virtualmente ilimitados.

Tarea 6. Aumente la frecuencia de muestreo de la señal ADC.

La frecuencia de muestreo de Arduino ADC se puede aumentar a 15 kHz en modo de 10 bits y hasta 77 kHz en modo de 8 bits al reemplazar las funciones de la biblioteca con una versión más rápida del uso de registros de microcontrolador.
La función de usuario se puede crear en el programa *.ino o en el archivo del sistema del controlador
...\arduino-1.0.6\hardware\arduino\cores\arduino\ cableado_analog.c registrándolo en
...\arduino-1.0.6\hardware\arduino\cores\arduino\ Arduino.h

Para construir un Arduino de canal de alta velocidad de 8 bits - MatLAB, debe hacer lo siguiente.
1. Escriba un programa para determinar el tiempo de llenado de la matriz ADC con datos y mostrar el resultado en la ventana "Serial Monitor". El tamaño de la matriz debe ser lo suficientemente grande, por ejemplo, la mitad del tamaño de SRAM. Para aumentar la precisión, es necesario medir el tiempo de llenado múltiple de la matriz.
Ejemplo de programa:

configuración vacía()(
Serial.begin(57600); // bit/s

ADCSRA = (1<< ADEN) // Включение АЦП
|(1 << ADPS2); // Установка предделителя преобразователя на 8
ADMUX = (1<< ADLAR) | (1 << REFS0) // Подключение внешнего ИОН
|(1 << MUX2) |(0 << MUX1) |(1 << MUX0); // подключение АЦП A5 == 101
}

Bucle vacío()(
unsigned long time_start = millis();
para (int j = 0; j< 100; j++) {
para (int i = 0; i< 1024; i++) {
ADCSRA |= (1<< ADSC); // Запуск преобразования АЦП
while ((ADCSRA & (1<< ADIF)) == 0);//Ожидание флага окончания преобразования
adc_bytes[i] = ADCH; // Leer el valor recibido
}
}
unsigned long time_end = millis();
unsigned int dt = time_end - time_start;
Serial.println(dt);
}

Cien llena una matriz de 1024 bytes completada en 1542ms.

2. Complete la matriz llenando la matriz con datos ADC una vez y luego transfiriendo toda la matriz al puerto serie a la máxima velocidad.
Ejemplo de programa:

byte adc_bytes; // Reserva de matriz para datos ADC

Configuración vacía () (
Serie.begin(115200); // bit/s
ADCSRA = (1<< ADEN) // Включение АЦП
|(1 << ADPS2); // Установка предделителя преобразователя на 8
ADMUX = (1<< ADLAR) | (1 << REFS0) // Подключение внешнего ИОН
|(1 << MUX2) |(0 << MUX1) |(1 << MUX0); // подключение АЦП A5 == 101
}

Bucle vacío()(
para (int i = 0; i< 1024; i++) {
ADCSRA |= (1<< ADSC); // Запуск преобразования АЦП
while ((ADCSRA & (1<< ADIF)) == 0); //Ожидание флага окончания преобразования
adc_bytes[i] = ADCH; // Leer el valor recibido
}
// enviar datos ADC al puerto serie
Serial.print("A"); // "A" es el encabezado
para (int i = 0; i< 1024; i++) {
Serial.write(adc_bytes[i]);
}
}
3. En el modelo Simulink (Fig. 36) en el formato 0.01542, escriba el valor experimental del tiempo de escritura en la matriz, es decir, en la línea "Block sample time" del bloque "Serial Receive" y en la barra de menú > simulación > Parámetros de configuración > Tamaño de paso fijo (tiempo de muestra fundamental).


Arroz. 36. Modelo de Simulink para recibir y mostrar datos desde un puerto COM.

4. Conecte una señal de prueba a la entrada ADC. Ejecute el programa Arduino y luego el modelo Simulink (MatLAB). Compare los parámetros de señal conocidos con los parámetros de señal observados. Puede verificar el funcionamiento de la ruta mostrando los voltajes de salida conectados alternativamente de la placa Arduino: 0V; 3.3V y 5V.


Arroz. 37. Visualización en tiempo real de la captación de red de 50 Hz. El marco incluye 1024 puntos. Tiempo de trama 15,42 ms. Frecuencia de muestreo 66 kHz (como 1/(0,01542_seg/1024)). La señal mostrada tiene discontinuidades: el proceso de grabación se interrumpe por la transmisión de una trama al enlace serie.


Arroz. 38. Visualización en tiempo real de una señal de diente de sierra de 0...3,3 V generada en un controlador Teensy 3.1 con un DAC de 12 bits y conectado al sexto ADC (A5) del controlador Arduino.


Arroz. 39. Señal del controlador Teensy 3.1 500 Hz. El error de reloj (15,42 ms) del modelo de Simulink sin ajuste adicional es inferior al 1 % (como 100 %*(504,72 Hz - 500 Hz)/500 Hz). El error se puede reducir ajustando el ciclo RT, como se muestra en el paso 3 de esta tarea.

PREGUNTAS DE CONTROL

1. Compare los períodos de conversión de ADC de la primera y la última referencia.
2. ¿Por qué se recomienda tomar una muestra que sea múltiplo de dos para construir el espectro de la señal?
3. ¿Cuál es la latencia para transmitir 1024 bytes a 115200 bps con la siguiente configuración de transferencia?
bits de datos: 8
paridad: ninguna
Bits de parada: 1
control de flujo: ninguno

Entradas analógicas de la placa Arduino.

La placa Arduino UNO contiene 6 entradas analógicas para medir señales de voltaje. Sería más correcto decir que 6 salidas de la placa pueden operar tanto en modo de salidas discretas como de entradas analógicas.

Estos pines están numerados del 14 al 19. Inicialmente se configuran como entradas analógicas y pueden denominarse A0-A5. En cualquier momento, se pueden configurar para el modo de salidas discretas.

pinMode(A3, SALIDA); // configurar el modo de salida discreta para A3
escritura digital (A3, BAJO); // configuración de salida A3 baja

Para volver al modo de entrada analógica:

pinMode(A3, ENTRADA); // configurar el modo de entrada analógica para A3

Entradas analógicas y resistencias pull-up.

Las resistencias pull-up están conectadas a los pines de entrada analógica, así como a los pines digitales. La inclusión de estas resistencias se realiza mediante el comando

escritura digital (A3, ALTO); // encienda la resistencia pull-up a la entrada A3

El comando debe aplicarse a una salida configurada en modo entrada.

Debe recordarse que la resistencia puede afectar el nivel de la señal analógica de entrada. La corriente de la fuente de alimentación de 5 V, a través de la resistencia pull-up, provocará una caída de voltaje en la resistencia interna de la fuente de señal. Entonces es mejor apagar la resistencia.

Placa convertidora de analógico a digital Arduino.

La medición del voltaje real en las entradas se realiza mediante un convertidor de analógico a digital (ADC) con un interruptor para 6 canales. El ADC tiene una resolución de 10 bits, que corresponde al código de salida del convertidor 0...1023. El error de medición no es más de 2 unidades del dígito menos significativo.

Para mantener la máxima precisión (10 dígitos), es necesario que la resistencia interna de la fuente de señal no supere los 10 kΩ. Este requisito es especialmente importante cuando se utilizan divisores de resistencia conectados a las entradas analógicas de la placa. La resistencia de las resistencias divisoras no puede ser demasiado grande.

Funciones de software de entrada analógica.

int analogRead(puerto)

Lee el valor de voltaje en la entrada analógica especificada. Un voltaje de entrada que va de 0 al nivel de referencia de voltaje (a menudo 5 V) se convierte en un código de 0 a 1023.

Con una tensión de referencia de 5 V, la resolución es de 5 V/1024 = 4,88 mV.

Se tarda unos 100 µs en convertir.

int código de entrada; // código de voltaje de entrada
Voltaje de entrada flotante; // tensión de entrada en V

inputCod=analogRead(A3); // lectura de voltaje en la entrada A3
inputVoltage= ((float)inputCod * 5. / 1024.); // código de conversión a voltaje (V)

void analogReference(tipo)

Establece el voltaje de referencia para el ADC. Define el voltaje máximo de entrada analógica que el ADC puede convertir correctamente. El valor del voltaje de referencia también determina el coeficiente para convertir el código en voltaje:

Voltaje de entrada = código ADC * voltaje de referencia / 1024.

El argumento de tipo puede tomar los siguientes valores:

  • POR DEFECTO - la tensión de referencia es igual a la tensión de alimentación del controlador (5 V o 3,3 V). Para Arduino UNO R3 - 5V.
  • INTERNO - tensión de referencia interna 1,1 V para placas con controladores ATmega168 y ATmega328, para ATmega8 - 2,56 V.
  • INTERNAL1V1 - Tensión de referencia interna de 1,1 V para controladores Arduino Mega.
  • INTERNAL2V56 - Tensión de referencia interna de 2,56 V para controladores Arduino Mega.
  • EXTERNA – fuente de tensión de referencia externa, conectada a la entrada AREF.

referenciaanalógica(INTERNA); // el voltaje de referencia es de 1,1 V

Voltímetro de dos canales en Arduino.

Como ejemplo del uso de funciones de entrada analógica, creemos un proyecto de voltímetro digital simple en Arduino. El dispositivo debe medir voltajes en dos entradas analógicas de la placa y transferir los valores medidos a una computadora a través de un puerto serie. Usando el ejemplo de este proyecto, mostraré los principios de la creación de sistemas simples para medir y recopilar información.

Decidimos que el voltímetro debe medir el voltaje en el rango de al menos 0 ... 20 V y desarrollar un circuito para conectar las entradas del voltímetro a la placa Arduino UNO.

Si configuramos el voltaje de referencia a 5 V, entonces las entradas analógicas de la placa medirán el voltaje en el rango de 0 ... 5 V. Y necesitamos al menos 0 ... 20 V. Entonces necesitamos usar un divisor de voltaje.

El voltaje en la entrada y salida del divisor están relacionados por la relación:

Usalida = (Uentrada / (R1 + R2)) * R2

Relación de transmisión:

K = Usalida / Uentrada = R2 / (R1 + R2)

Necesitamos una ganancia de 1/4 (20V * 1/4 = 5V).

Para mantener la máxima precisión (10 dígitos), es necesario que la resistencia interna de la fuente de señal no supere los 10 kΩ. Por lo tanto, elegimos la resistencia R2 igual a 4,22 kOhm. Calculamos la resistencia de la resistencia R1.

0,25 = 4,22 / (R1 + 4,22)
R1 \u003d 4.22 / 0.25 - 4.22 \u003d 12.66 kOhm

Encontré resistencias con una resistencia de 15 kOhm con la calificación más cercana. Con resistencias R1 = 15 kΩ y R2 = 4,22:

5 / (4,22 / (15 + 4,22)) = 22,77 V.

El circuito del voltímetro basado en Arduino se verá así.

Dos divisores de voltaje están conectados a las entradas analógicas A0 y A1. Los condensadores C1 y C2, junto con las resistencias divisoras, forman filtros de paso bajo que eliminan el ruido de alta frecuencia de las señales.

Ensamblé este circuito en una placa de pruebas.

Conecté la primera entrada del voltímetro a una fuente de alimentación regulada y la segunda a la fuente de 3,3 V de la placa Arduino. Para controlar el voltaje, conecté un voltímetro a la primera entrada. Queda por escribir el programa.

Un programa para medir voltaje usando una placa Arduino.

El algoritmo es simple. Necesario:

  • lea el código ADC dos veces por segundo;
  • convertirlo a voltaje;
  • enviar los valores medidos a través del puerto serie a la computadora;
  • El programa de monitor de puerto Arduino IDE muestra los valores de voltaje obtenidos en la pantalla de la computadora.

Voy a dar el boceto del programa en su totalidad.

// programa de medida de tensión
// en las entradas analógicas A0 y A1

#incluir

período de medición tiempo
#define R1 15. // resistencia R1
#definir R2 4.22 // resistencia R2


flotante u1, u2; // voltajes medidos

configuración vacía()(
Serial.begin(9600); //

MsTimer2::start(); // habilitar interrupción
}

bucle vacío() (

// periodo 500ms
if (timeCount >= MEDIDA_PERIODO) (
cuentatiempo=0;

//

// lectura del código del canal 2 y conversión a voltaje
u2= ((float)analogRead(A1)) * 5. / 1024. / R2 * (R1 + R2);

// transferencia de datos a través del puerto serie
Serial.print("U1 = "); Impresión en serie (u1, 2);
Serie.imprimir(" U2 = "); Serial.println(u2, 2);
}
}

// procesamiento de interrupción 1 ms
interrupción del temporizador vacío () (
cuentatiempo++;
}

Permítanme explicar la línea en la que el código ADC se convierte en voltaje:

// lectura del código del canal 1 y conversión a voltaje
u1= ((float)analogRead(A0)) * 5. / 1024. / R2 * (R1 + R2);

  • Se lee el código ADC: analogRead(A0) .
  • Convertido explícitamente a formato de coma flotante: (float) .
  • Convertido a voltaje en la entrada analógica: * 5. / 1024. El punto al final de los números indica que se trata de un número de coma flotante.
  • Se tiene en cuenta la relación divisoria: / R2 * (R1 + R2) .

Carguemos el programa en la placa, iniciemos el monitor del puerto serie.

Dos barras en ejecución muestran los valores de los voltajes medidos. Todo está funcionando.

Medición del valor medio de la señal.

Conectemos el primer canal de nuestro voltímetro a una fuente de voltaje con un alto nivel de ondulación. Veremos tal imagen en el monitor.

Los valores de voltaje del primer canal en la pantalla del monitor se contraen y saltan todo el tiempo. Y las lecturas del voltímetro de control son bastante estables. Esto se debe a que el voltímetro de referencia mide el valor promedio de la señal, mientras que la placa Arduino lee muestras individuales cada 500 ms. Naturalmente, el momento de leer el ADC cae en diferentes puntos de la señal. Y a un nivel alto de pulsaciones, la amplitud en estos puntos es diferente.

Además, si la señal se lee en muestras raras separadas, cualquier ruido de impulso puede introducir un error significativo en la medición.

La solución es tomar varias muestras frecuentes y promediar el valor medido. Para esto:

  • en el controlador de interrupciones, leemos el código ADC y lo sumamos con las muestras anteriores;
  • contar el tiempo promedio (el número de muestras promedio);
  • cuando se alcanza el número especificado de muestras, guardamos el valor total de los códigos ADC;
  • para obtener el valor promedio, dividimos la suma de los códigos ADC por el número de muestras promedio.

Una tarea de un libro de texto de matemáticas de octavo grado. Aquí hay un boceto del programa, un voltímetro de valor promedio de dos canales.

// programa de medicion de media tension
// en las entradas analógicas A0 y A1

#incluir

#define MEDIDA_PERIODO 500 // período de medición tiempo
#define R1 15. // resistencia R1
#definir R2 4.22 // resistencia R2

int cuentatiempo; // contador de tiempo
larga sumaU1, sumaU2; // variables para sumar códigos ADC
larga disponibilidadU1, disponibilidadU2; // suma de códigos ADC (promedio * 500)
bandera booleana Listo; // señal de disponibilidad de los datos de medición

configuración vacía()(
Serial.begin(9600); // inicializa el puerto, velocidad 9600
MsTimer2::set(1, InterrupciónTemporizador); // interrupciones del temporizador, período 1 ms
MsTimer2::start(); // habilitar interrupción
}

bucle vacío() (

if (banderaListo == verdadero) (
banderaListo=falso;
// conversión a voltaje y transferencia a una computadora
Serial.print("U1 = ");
Serial.print((float)avarageU1 / 500. * 5. / 1024. / R2 * (R1 + R2), 2);
Serie.imprimir(" U2 = ");
Serial.println((float)avarageU2 / 500. * 5. / 1024. / R2 * (R1 + R2), 2);
}
}

// procesamiento de interrupción 1 ms
interrupción del temporizador vacío () (

cuentatiempo++; // +1 contador de muestras promedio
sumaU1+= lecturaanalógica(A0); // suma de códigos ADC
sumU2+= lecturaanalógica(A1); // suma de códigos ADC

// comprobar el número de muestras de promedio
if (timeCount >= MEDIDA_PERIODO) (
cuentatiempo=0;
disponibilidadU1=sumU1; // sobrecarga del valor medio
promedioU2=sumaU2; // sobrecarga del valor medio
sumaU1= 0;
sumaU2=0;
banderaListo=verdadero; // el resultado de la medición del signo está listo
}
}

/500, el número de muestras, se agregó a la fórmula para convertir el código ADC en voltaje. Cargue, ejecute el monitor de puerto (Cntr + Shift + M).

Ahora, incluso con un nivel significativo de ondulación, las lecturas cambian en centésimas. Esto es solo porque el voltaje no está estabilizado.

El número de muestras debe elegirse teniendo en cuenta:

  • el número de muestras determina el tiempo de medición;
  • cuanto mayor sea el número de muestras, menor será la influencia de la interferencia.

La principal fuente de interferencia en las señales analógicas es la red de 50 Hz. Por lo tanto, es deseable elegir un tiempo promedio que sea un múltiplo de 10 ms, el tiempo de medio ciclo de la red con una frecuencia de 50 Hz.

Optimización de cálculos.

Los cálculos de punto flotante simplemente devoran los recursos de un microcontrolador de 8 bits. Cualquier operación de punto flotante requiere desnormalización de mantisa, operación de punto fijo, normalización de mantisa, corrección de exponente... Y todas las operaciones con números de 32 bits. Por lo tanto, es necesario minimizar el uso de cálculos de punto flotante. Te diré cómo hacer esto en las próximas lecciones, pero al menos optimicemos nuestros cálculos. El efecto será significativo.

En nuestro programa, la conversión del código ADC en voltaje se escribe de la siguiente manera:

(flotante)promedioU1 / 500. * 5. / 1024. / R2 * (R1 + R2)

¿Cuántos cálculos hay, y todos son de coma flotante? Pero la mayoría de los cálculos son operaciones con constantes. Parte de línea:

/ 500. * 5. / 1024. / R2 * (R1 + R2)

(flotante)promedioU1 * 0.00004447756

Los propios compiladores inteligentes reconocen los cálculos con constantes y los calculan en el momento de la compilación. Tenía una pregunta qué tan inteligente es el compilador de Andruino. Decidió comprobar.

Escribí un programa corto. Realiza un ciclo de 10.000 pasadas y luego transmite a la computadora el tiempo de ejecución de estos 10.000 ciclos. Aquellos. le permite ver el tiempo de ejecución de las operaciones colocadas en el cuerpo del bucle.

// verificación de optimización de cálculo

intx= 876;
flotar y;
cuenta int sin firmar;
unsigned long timeCurrent, timePrev;

configuración vacía()(
Serial.begin(9600);
}

bucle vacío() (
contar++;
// y= (flotante)x / 500. * 5. / 1024. / 4.22 * (15. + 4.22);
// y= (flotante)x * 0.00004447756 ;

si (cuenta >= 10000) (
cuenta=0;
tiempoActual=millis();
Serial.println(horaActual - horaAnterior);
tiempoAnterior=tiempoActual;
}
}

En la primera variante, cuando las operaciones de punto flotante se comentan y no se ejecutan en el ciclo, el programa dio un resultado de 34 ms.

Aquellos. 10.000 ciclos vacíos se completan en 34ms.

Luego abrí la línea:

y= (flotante)x / 500. * 5. / 1024. / 4.22 * (15. + 4.22);

repite nuestros cálculos. Resultado 10.000 pasadas en 922 ms o

(922 - 34) / 10.000 = 88,8 µs.

Aquellos. esta línea de cálculos de coma flotante tarda 89 µs en completarse. Pensé que habría más.

Ahora cerré esta línea con un comentario y abrí la siguiente, multiplicada por una constante precalculada:

y= (flotante)x * 0.00004447756 ;

Resultado 10.000 pases en 166 ms o

(166 - 34) / 10.000 = 13,2 µs.

Resultado increíble. Ahorramos 75,6 µs por línea. Lo completó casi 7 veces más rápido. Tenemos 2 líneas de este tipo, pero puede haber muchas más en el programa.

Conclusión: los cálculos con constantes deben ser realizados por usted mismo en una calculadora y utilizados en programas como coeficientes listos para usar. El compilador Arduino no los calculará en la etapa de compilación. En nuestro caso, deberíamos hacer esto:

#define ADC_U_COEFF 0.00004447756 // Código ADC a factor de conversión de voltaje

Serial.print((float)avarageU1 * ADC_U_COEFF, 2);

La opción de velocidad óptima es transferir el código ADC a la computadora y con él todos los cálculos de coma flotante. En este caso, un programa especializado debería recibir datos en la computadora. El monitor de puerto del IDE de Arduino no funcionará.

Hablaré sobre otras formas de optimizar los programas de Arduino en lecciones futuras según sea necesario. Pero sin resolver este problema, es imposible desarrollar programas complejos en un microcontrolador de 8 bits.

Hay otro tutorial en el sitio.




Arriba