Me gustaría conectar un interruptor mecánico a un pin de interrupción en un procesador Arduino Uno donde la interrupción está configurada para interrupciones de CAMBIO (es decir, se activa en una señal positiva o negativa).
He encontrado numerosos enfoques para la implementación de circuitos antirrebote para señales positivas o negativas, pero no he encontrado sugerencias para circuitos que puedan contrarrestar señales positivas o negativas.
Esencialmente, quiero usar un solo pin de interrupción que pueda detectar la apertura o el cierre de un interruptor externo, y me gustaría eliminar el rebote de la entrada usando un enfoque de hardware.
Para ser un poco más específico, el interruptor en cuestión se abrirá y cerrará hasta 200 veces por segundo y me gustaría determinar la cantidad de tiempo que permanece cerrado cada vez que pasa por un ciclo de encendido/apagado. Es decir, no estoy hablando de un botón presionado por el usuario.
Para eliminar el rebote de cualquiera de los flancos de una señal cambiante, utilice la histéresis. Muchos algoritmos antirrebote asumen una señal activa alta o baja activa, pero necesita detectar ambas.
Aquí está la esencia del algoritmo de histéresis:
bool input_state = digitalRead(INPUT_PIN);
unsigned long current_ms = millis();
edge = rise = fall = false;
// Hysteresis:
// If there is no change, reset the debounce timer.
// Else, compare the time difference with the debounce delay.
if (input_state == output_state)
{
last_ms = current_ms;
}
else
{
if ((current_ms - last_ms) >= DEBOUNCE_DELAY_ms)
{
// Successfully debounced, so update the outputs.
is_debounced = true;
rise = input_state && !output_state;
fall = !input_state && output_state;
edge = rise || fall;
output_state = input_state;
}
else
{
is_debounced = false;
}
}
Esto podría llamarse desde una rutina de servicio de interrupción algo como esto:
ISR(TIMER0_COMPA_vect)
{
static Debouncer button1(BUTTON_PIN, DEBOUNCE_DELAY_ms);
static bool led_state = false;
button1.UpdateISR();
// Toggle the LED on either edge of the debounced signal.
if (button1.Edge())
{
led_state = !led_state;
digitalWrite(LED_PIN, led_state);
}
}
Aquí hay un enlace con el código completo del antirrebote de histéresis en GitHub que usa el millis()
temporizador, pero es posible que deba cambiarlo para usar el micros()
temporizador y posiblemente aumentar la frecuencia de interrupción para una mayor precisión en su aplicación. También necesita averiguar la longitud de DEBOUNCE_DELAY
. Use un osciloscopio para ver cómo se ve el ruido de rebote del interruptor.
Si se trata de un interruptor de bloqueo físico, generalmente uso este tipo de código en un bucle de 10 ms con filtrado RC en el pin (no es necesario). Por supuesto, puede usar una interrupción de cambio de pin, pero es un poco complicado, porque no puede perder/olvidarse de manejar ni siquiera un borde en la entrada. Por ejemplo, detecta un flanco ascendente en la rutina PCINT, luego comienza a activar el estado de rebote como contar algunos números de niveles positivos, pero mientras tanto puede apagar el botón para detectar el flanco negativo, es decir, cancelar el rebote positivo o al menos pensar en esta opción. Lo útil de PCINT cuando se maneja el interruptor de bloqueo es mantener el microcontrolador "inactivo" si no se produce una interrupción y si se produce una interrupción, habilite algo como mi rutina en main ().
if(SWITCHED) {
switched_on_count++;
switched_off_count = 0;
if(switched_on_count > 10) {
switched_on_count = 0;
if(BUTTON == OFF) {
BUTTON = ON;
}
}
} else {
switched_off_count++;
switched_on_count = 0;
if(switched_off_count > 10) {
switched_off_count = 0;
if(BUTTON == ON) {
BUTTON = OFF;
}
}
}
Una forma sencilla de hacer esto es con un algoritmo interactivo.
Es similar al algoritmo propuesto por @Michal Podmanický, sin embargo, no necesita mantener un contador para las posiciones ON y OFF. Simplemente usa una variable de iterador, que amortigua la entrada oscilante (es decir, el interruptor de rebote) y cambia el estado de lectura solo cuando se alcanza el umbral, ya sea cuando el iterador vuelve a 0 para un estado bajo, o cuando alcanza el umbral positivo para alto estado.
#define MAXIMUM (10) // set this value depending on how quicly your fct is called
// and how bouncy your hardware is
uint8_t iterator = 0; // starts low
bool debounce(bool input)
{
bool now_debounced_input;
if (input == 0)
{
if (iterator > 0)
iterator--;
}
else if (iterator < MAXIMUM)
iterator++;
if (iterator == 0)
now_debounced_input = 0;
else if (iterator >= MAXIMUM)
{
iterator = MAXIMUM; // Defensive code
now_debounced_input = 1;
}
return now_debounced_input ;
}
En términos generales, lo que necesita es obtener la salida lógica del interruptor a través de un filtro de paso bajo . Hay varias implementaciones posibles: hardware (filtro RC en un pin µC, otras más complejas); o software (las respuestas de JCSB y Michal P. por ejemplo). Los mejores dependerán de las especificaciones del circuito que estés diseñando. Si necesita muestrear el valor a 1 kHz, las implementaciones de hardware pueden ser preferibles para evitar la carga del software, especialmente si su µC no es rápido.
Es importante tener en cuenta que es posible que deba tener en cuenta el retraso inducido por el filtro de paso bajo si su aplicación necesita ser especialmente reactiva (aunque no debería ser un problema a 1 kHz).
También recomendaría usar un filtro de histéresis (un disparador Schmitt , por ejemplo) entre la salida del filtro LP y la entrada de su sistema para evitar demasiada variación del valor: las soluciones de JCSB y Michal P. intrínsecamente proporcionan esta función, lado del software.
Todo: decidí digitalizar la forma de onda del interruptor. Dado que puedo determinar el ciclo de trabajo y otras cosas en el procesamiento posterior. Agradezco los aportes de todos y planeo probar algunas de las sugerencias más adelante, ya que me gustaría comprender mejor la eliminación de rebotes de interruptores y el manejo de interrupciones. ¡Gracias de nuevo! -Jim
wesley lee
Tony Estuardo EE75
Sólo yo
jim luby
usuario136077
broma
bruce abbott
jsotola
keith
keith
keith