Para leer una entrada digital o analógica de forma fiable en un PLC Arduino, fíltrala por software. La librería Filter de Industrial Shields tiene dos clases: DigitalFilter<T> acepta un nuevo estado de la entrada solo cuando se ha mantenido estable durante T milisegundos (antirrebote), y AnalogFilter<N, T> devuelve la media de las últimas N muestras, tomando una muestra cada T milisegundos.
Este post explica por qué una entrada necesita un filtro, cómo funciona cada clase y cómo usarla con dos ejemplos para el PLC M-Duino: un filtro digital en la entrada I0.8 y un filtro analógico en la entrada I0.10.
¿Por qué filtrar una entrada digital o analógica?
Cuando una entrada digital cambia de HIGH a LOW, o de LOW a HIGH, la señal no cambia de forma limpia. Los contactos mecánicos, como pulsadores, relés y finales de carrera, rebotan, y el PLC puede leer varios cambios en pocos milisegundos. Si el programa cuenta pulsos o reacciona a cada cambio, estos rebotes se leen como valores erróneos y provocan errores.
Las entradas analógicas tienen un problema parecido: el ruido eléctrico y las pequeñas variaciones del sensor hacen que la lectura salte de un valor a otro. La media de varias muestras da un valor más estable.
| Clase | Qué hace | Parámetros |
|---|---|---|
DigitalFilter<T> | Antirrebote. La salida solo cambia cuando la entrada mantiene el nuevo estado durante T ms. | T: tiempo de filtrado en ms |
AnalogFilter<N, T> | Media móvil de las últimas N muestras. | N: número de muestras. T: periodo de muestreo en ms (con 0 toma muestras lo más rápido posible) |
Requisitos
- Un PLC Arduino de Industrial Shields. Los ejemplos usan las entradas I0.8 e I0.10, disponibles en el M-Duino 21, el M-Duino 42 y el M-Duino 58. En un Ardbox Analog u otro modelo, cambia los pines por entradas de tu PLC.
- Las placas de Industrial Shields instaladas en el Arduino IDE: cómo instalar las placas de Industrial Shields.
- La librería Filter en GitHub. Descárgala como archivo ZIP y añádela desde el menú del Arduino IDE Programa > Incluir biblioteca > Añadir biblioteca .ZIP.
La librería Filter formaba parte de la librería Tools40. Desde la versión 1.0.0 (enero de 2024) es una librería independiente, con licencia LGPL, y funciona en todas las arquitecturas.
Ejemplo 1: filtro digital en la entrada I0.8
El parámetro de plantilla de DigitalFilter es el tiempo de filtrado en milisegundos. En este ejemplo es de 500 ms.
#include <Filter.h>
// Digital filter (debounce)
// Filtering time: 500 ms. A new state is accepted only
// after it has stayed stable for 500 ms
DigitalFilter<500> filter;
void setup() {
// Init Serial port
Serial.begin(9600L);
pinMode(I0_8, INPUT);
}
void loop() {
// Read pin value
int value = digitalRead(I0_8);
// Filter it
int filtered = filter.update(value);
// Print the filtered value
Serial.println(filtered);
}
Cómo funciona: mientras la entrada tiene el mismo valor que la salida filtrada, la librería reinicia su temporizador. Cuando la entrada cambia, la salida mantiene el valor anterior. El nuevo valor solo se acepta si la entrada se mantiene en él durante 500 ms. Los rebotes y los pulsos de menos de 500 ms se ignoran, y un cambio real aparece en la salida 500 ms después del último rebote. Funciona igual de HIGH a LOW y de LOW a HIGH.
Elige el tiempo de filtrado según tu señal: un tiempo más corto reacciona antes, y uno más largo rechaza perturbaciones más largas.
Ejemplo 2: filtro analógico en la entrada I0.10
Para una entrada analógica, define el número de muestras y el periodo de muestreo en milisegundos:
#include <Filter.h>
// Analog filter (moving average)
// Number of samples: 10
// Sample period: 5 ms (with 0, samples are taken as fast as possible)
AnalogFilter<10, 5> filter;
void setup() {
// Init Serial port
Serial.begin(9600L);
pinMode(I0_10, INPUT);
}
void loop() {
// Read pin value
int value = analogRead(I0_10);
// Filter it
int filtered = filter.update(value);
// Print the filtered value
Serial.println(filtered);
}
Con AnalogFilter<10, 5> el filtro guarda las últimas 10 muestras, una cada 5 ms, y update() devuelve su media. La media cubre los últimos 50 ms de la señal. Más muestras o un periodo más largo dan un valor más suave que sigue los cambios más despacio.
El filtro empieza con todas las muestras a 0. Para empezar desde otro valor, pásalo al constructor, por ejemplo AnalogFilter<10, 5> filter(512);.
Llama a update() en cada loop y evita delay() en el programa: los dos filtros usan millis() para medir el tiempo. Crea un objeto filtro para cada entrada que quieras filtrar.
Los dos ejemplos compilan para el M-Duino 21+ y el M-Duino 58+ con el paquete de placas AVR de Industrial Shields 1.2.1.
Preguntas frecuentes sobre filtros de entradas en un PLC Arduino
¿El filtro digital añade retardo?
Sí. Un cambio real llega a la salida después del tiempo de filtrado, 500 ms en el ejemplo. Usa un tiempo más corto si el programa debe reaccionar antes.
¿Puedo filtrar varias entradas?
Sí. Cada objeto filtro guarda su propio estado, así que crea un objeto para cada entrada.
¿Filter es lo mismo que la librería Tools40?
Las clases de filtro vienen de Tools40. Ahora están en la librería independiente Filter, con las mismas clases DigitalFilter y AnalogFilter.