Contando el número de pulsaciones de botón por interrupción externa

Es un requisito que debo contar la cantidad de botones presionados por una interrupción externa o cualquier otra.

Entonces, cuando uso la interrupción externa para incrementar el contador en 1, a veces se pliega en 2 o 3 debido al rebote. ¿Alguien puede decirme cómo contar con precisión en este caso?

void Handle_PB() // my ISR called by pushbutton press falling edge
{
    pb++;
    if(pb>3)
    {  num1=1;
    }
    if(pb>4)
    {  num2=1;
       pb=0;
    }
} 

pb es el contador de pulsadores. y num1 y num2 son banderas.

Entonces, después de presionar el botón 4 veces, quiero hacer otra tarea. Simerly después de presionar el botón 5 veces, quiero hacer otra tarea. tan importante es contar un número exacto de pulsaciones de botón. Conozco el principio de rebote. Pero, ¿dónde puedo poner este código de retraso de rebote ya que está controlado por interrupciones?

Simplemente puede agregar, digamos, un retraso de 50 ms después del primer rebote si su programa está bien con tanto retraso. Esa no es una muy buena solución, pero podría funcionar.
¿Puede agregar un circuito antirrebote externo y configurar el GPIO para detección de flanco ascendente?
Creo que es mejor que hagas encuestas. Siempre lo he hecho verificando que un valor sea el mismo en dos encuestas seguidas (para cuando estoy haciendo interruptores de interfaz humana) y eso siempre funcionó perfectamente. Puede usar un temporizador para hacer dicho sondeo, registrar el valor y luego verificar en el bucle principal, o simplemente sondear dentro del bucle principal.
No puedo usar ningún circuito externo. Y tengo que hacerlo por interrupción externa ya que es un proyecto de tiempo crítico. No puedo pagar un ISR solo para sondear un botón.
¿Exactamente qué tan crítico es el tiempo de su proyecto? ¿La MCU tiene algún temporizador de hardware que pueda usar?
Lo que dices no tiene sentido. Si está utilizando una interrupción externa para esto, está utilizando un ISR. En su lugar , usaría una interrupción de temporizador .

Respuestas (3)

1) Es mejor, si puede lidiar con el rebote en el propio hardware. Si es posible, coloque un capacitor apropiado en el pin de interrupción a tierra.

2) En el software, puede tratar como: (Suponiendo que el rebote puede durar hasta 50 segundos)

void my_interrupt_handler()
{
 interrupt_time = currentmilliseconds();

 if (interrupt_time - last_interrupt_time > 50) 
 {
   press++;
   last_interrupt_time = interrupt_time;
 }

}

last_interrupt_time tiene un valor inicial de 0. El código incrementa el valor de prensa para la primera pulsación. Pero no se incrementará durante 50 ms, sin importar cuántas interrupciones de botón se produzcan debido al rebote. Esto funcionará de manera eficiente solo si el microcontrolador admite interrupciones dentro de las interrupciones; de lo contrario, tiene la posibilidad de perder la interrupción de desbordamiento del temporizador.

3) Otro método es simplemente agregar un retraso de 50 ms después de incrementar la presión . Funciona. Pero no es un buen método.

4) Otra idea, mediante el uso de una variable de bandera:

void my_interrupt_handler()
    {     
      if (flag == 0)
         { 
          press++;
          flag = 1 
         }
    }

flag es una variable volátil compartida entre main() e ISR. El código está escrito en main() de modo que reinicializa el indicador a 0 solo después de contar 50 ms. Así que esto es como deshabilitar las interrupciones de los botones durante 50 ms. De todos modos, los humanos no pueden presionar más rápido que eso.

"Siempre es mejor, si podemos lidiar con el rebote en el propio hardware". ¡Equivocado! En los casos en los que ya tiene un microcontrolador, tiene sentido que también maneje el antirrebote. Se necesita una pequeña fracción de la potencia de procesamiento de la mayoría de los micros modernos. Agregar hardware solo aumentaría el tamaño, el peso y el costo sin ningún beneficio.

Tienes que hacer lo que se llama antirrebote . Hay muchas maneras, y seguramente hay mucho escrito al respecto por ahí.

El método que suelo usar es no considerar válido un nuevo estado hasta que la entrada haya estado en ese estado durante 50 interrupciones de reloj consecutivas de 1 ms. 50 ms es más largo que el rebote de la mayoría de los interruptores, pero sigue siendo instantáneo en tiempo humano. Dicho de otra manera, un ser humano no notará un retraso de 50 ms entre que presiona un botón y ocurre alguna acción.

En casos excepcionales en los que el sistema tiene que reaccionar más rápido que el tiempo de eliminación de rebotes del interruptor mecánico, puede activar el primer cambio de estado y luego bloquear nuevos cambios de estado hasta que el cambio existente se haya asentado. Esto le brinda casi ninguna latencia, pero hace que el sistema sea susceptible a fallas breves. Tienes que decidir qué es realmente importante.

Una vez más, tenga en cuenta que los usuarios humanos pasan desapercibidos los retrasos de hasta unos 50 ms.

¿Puede decirme cómo implementar el rebote aquí porque uso la interrupción? Cualquier pico llama inmediatamente a mi ISR.
@litunbls, puede esperar dentro de la ISR (aunque generalmente es una mala práctica bloquear una ISR), las nuevas interrupciones no deberían activar la ISR nuevamente.
No estoy un poco confundido si retrasar 30-50 ms dentro de ISR es un método adecuado, ya que es una aplicación muy crítica en cuanto al tiempo.
@lit: Esperar en el ISR es una mala idea. Como dije, generalmente tengo una interrupción periódica de 1 ms. Esto suele ser útil por una variedad de razones. Una de las cosas que hace esta interrupción es contar si cada entrada del interruptor ha estado en el mismo estado durante 50 interrupciones consecutivas.
@litunbls, si es sensible al tiempo, entonces no tiene más remedio que sondear el estado del botón. Sin embargo, puede esperar hasta el primer flanco ascendente y luego configurar un temporizador para que se apague 50 ms más tarde para verificar el estado nuevamente. Si el estado sigue siendo el mismo, ¡genial! Se presiona el botón. Puede mantener una bandera en su botón presione ISR para indicar si ya está esperando o si necesita iniciar el temporizador, o puede desactivar el botón ISR cuando espera el temporizador para que no tenga que responder a las interrupciones que hace. no me importa

Es difícil proponer una solución sin saber qué tipo de MCU es ese. ¿Tienes algún temporizador o sys tick?

Tal vez algo como esto:

volatile unsigned long PBStart;

void Handle_PB() // my ISR called by pushbutton press falling edge
{
    if (getSysTickTimer() - PBStart > 50)   // Where 50 is some threshold like 50ms       
    {
        PBStart = 0;
    }

    if (PBStart == 0)   // Is ok to count
    { 
        PBStart = getSysTickTimer();

        pb++;
        if(pb>3)
        {  num1=1;
        }
        if(pb>4)
        {  num2=1;
           pb=0;
        }
    }
} 
Es similar a cuando realiza un sondeo con una interrupción de temporizador. No quiero ejecutar 2 ISR solo para contar la pulsación del botón. ¿Hay alguna forma de hacerlo con una sola interrupción externa activada por un botón que también se encargue del antirrebote?
¿Es una buena idea leer el pin consecutivamente tres veces dentro de la interrupción y si el OR lógico de los 3 resultados es 0, entonces incrementar el contador? ¿Alguien puede sugerir alguna otra idea fuera de la caja?
No necesitas dos ISR. getSysTickTimer() solo puede devolver el conteo del temporizador. Si tiene un temporizador de repuesto, simplemente configúrelo con un preescalador alto (por lo que es lento) y simplemente lea su valor (no se necesita ISR). Nuevamente, no sé de qué MCU estamos hablando. ¿Es ARM o AVR? 32 u 8 bits? Respecto a la lectura consecutiva puede que no sea ninguna solución. Imagen presionas el botón, vas al ISR, luego lees 10 veces el botón. Cuanto tiempo llevara? ¿Unos cientos de nanosegundos? Puede ser demasiado rápido para realizar la eliminación de rebotes. ¿Puedes usar algo como delay_ms() dentro de ISR? ¿Y luego leer el botón varias veces?
Necesita algunos recursos adicionales para realizar la eliminación de rebotes. Temporizador, o función de retardo, o cualquier cosa. Si no quiere, ¿quizás pueda usar hardware antirrebote con capacitor?