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?
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.
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.
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;
}
}
}
dirac16
tyler
dibosco
litun bls
bruce abbott
dibosco