Eliminar rebotes en interruptores

Hay vistos varios ejemplos puntuales empleando distintas técnicas diferentes en software tratando de no mal gastar elementos físicos que sin conocimientos puede ser un dolor de cabeza.
Ahora bien de todas las soluciones propuestas para software sucede que para el principiante también es un dolor de cabeza.

Voy a dejar varias alternativas y las iremos evaluando:
#1:
Código:
while(!input(PIN_B4));
En este caso el problema es que solo toma un rebote y se quedaría en ese bucle hasta tanto se presione/suelte el pulsador. Poco conveniente para interrupciones distantes.

#2:
Código:
boton[0]=input(PIN_a0);
     delay_ms(250);
     boton[0]=input(PIN_a0);
Este caso se emplea, por ejemplo en el PIN RA0, con un retardo preguntando luego de un instante en que estado esta el pulsador.

Ejemplo: si estoy en 1, espero (aquí suceden los rebotes de alternancia entre 1/0/1..) luego de un delay pregunto de nuevo por el pulsador, si continua en 1 es porque lo estoy pulsando y con mas retardo se puede preguntar si ya esta en 0 lo que pone en evidencia que se presiono el pulsador (es como el mouse cdo espera a que soltemos el botón al hacer click para generar el evento)
En ese caso empleo un retardo lo que puede generar conflictos en tareas en tiempo real: procesos de filtrado, audio, muestreos en Conv. A/D.

Aparentemente a velocidades de 4MHz no se producen problemas con las INTERRUPCIONES debido a que estas toman el primer cambio de estado, ahora bien si lo analizamos minuciosamente podrías tomar el rebote como muchos cambios y si la interrupción se ejecutase a esas velocidades es posible que se atienda la int tantas veces como rebotes haya.
Pero no es conveniente poner delay en INT's ya que detienen el main. Habrá que recurrir a otro algoritmo.
Soy todo oídos a mejores soluciones propuestas :apreton:
 
Última edición por un moderador:
Pero no es conveniente poner delay en INT's ya que detienen el main. Habrá que recurrir a otro algoritmo.
Soy todo oídos a mejores soluciones propuestas :apreton:
Hace algún tiempo, buscando una buena solución para el problema de los rebotes en los pulsadores, encontré una librería escrita en C para PIC C Compiler.
Esta librería surge de una instrucción de PICBasic "BUTTON Pin,Down,Delay,Rate,BVar,Action,Label" que sirve muy bien para este propósito y lo que hace esta librería es muy similar, pues fue realizada para imitar a la instrucción de PICBasic, pero sin el salto a otra subrutina "Label".
El autor, del cual ya no recuerdo su nombre ni el sitio, describe detalladamente las funciones que usó para crear la rutina button, y también los parámetros a usar.

Adjunto esta librería que es de libre distribución y un ejemplo sencillo de su uso.

Suerte.
 

Adjuntos

  • Librería Button.rar
    16.1 KB · Visitas: 90
Hola, estoy creando una función antirrebotes para pulsadores en el PIC C Compiler.
Ya es funcional en el simulador con el pin_b2 pero tengo un problema pues no logro asociar esta función de manera general con cualquier pin de PIC. ¿Como podría solucionar esto?
Tengo entendido que hay que buscar un parámetro para la función para que se comporte de manera general.
Adjunto el código y la simulación.


Código:
#include <18F4550.h>
#fuses intxt, nomclr
#use delay(clock=1000000)
#include <lcd.c>
#use fast_io(b)

short estado;

short antirrebotes()
{
   short estadoActualPin, estadoAnteriorPin;
   int contador;
   do
   {
      estadoActualPin=input(pin_b2);
      if(estadoActualPin!=estadoAnteriorPin)
      {
         contador=0;
         estadoAnteriorPin=estadoActualPin;
      }
      else
      {
         contador++;
      }
      delay_ms(1);
   }
   while(contador<10);
   estado=estadoActualPin;
   return(estado);
}

void main()
{
   short estadoActualBoton, estadoAnteriorBoton;
   int pulsaciones;
   set_tris_b(0xFF);
   lcd_init();
   while(true)
   {
      estadoActualBoton=input(pin_b2);
      {
         if(estadoActualBoton!=estadoAnteriorBoton)
         {
            antirrebotes();
            if(estado==1)
            {
               pulsaciones++;
               printf(lcd_putc, "\f%u",pulsaciones);
            }
         }
      }
      estadoAnteriorBoton=estadoActualBoton;
   }
}
 

Adjuntos

  • Antirrebotes.rar
    45.5 KB · Visitas: 6
Probablemente algo como esto, aunque no me gustan muchas cosas...para empezar que no sepas lo que es un parámetro de una función en C.

Código:
short antirrebotes( int8 pinSinRebote )
{
   short estado, estadoActualPin, estadoAnteriorPin;
   int contador;
   do
   {
      estadoActualPin=input( pinSinRebote );
      if(estadoActualPin != estadoAnteriorPin)
      {
         contador=0;
         estadoAnteriorPin=estadoActualPin;
      }
      else
      {
         contador++;
      }
      delay_ms(1);
   }
   while( contador<10 );
   estado = estadoActualPin;
   return estado;
}
 
Es que desconozco el contexto de aplicacion, pero usando variables locales me aseguro que sea reentrante por si la emplea en una interrupcion...aunque el delay molesta.
 
estas usando fast_io() en el puerto B, lo que debes hacer es decir que pin del puerto vas a usar, en el ejemplo usas input(pin_b2), el pin 2 del puerto B como entrada.
en input(); debes de poner el puerto que quieras usar, ej. input(pin_b0), input(pin_b1), input(pin_b2), etc.
 
estas usando fast_io() en el puerto B, lo que debes hacer es decir que pin del puerto vas a usar, en el ejemplo usas input(pin_b2), el pin 2 del puerto B como entrada.
en input(); debes de poner el puerto que quieras usar, ej. input(pin_b0), input(pin_b1), input(pin_b2), etc.
Agradezco su apunte, aunque ya tengo claro eso. Lo que quiero es hacer una función antirrebote para evitar la redundancia de código.
Supongamos que vamos a utilizar 10 pulsadores entonces ya podrá imaginar el larguero de código.
El problema es que no logro asociar cualquier pin a la función.
 
Entonces probá con esto:

Código:
short antirrebotes( const int8 pinSinRebote )
{
   short estado, estadoActualPin, estadoAnteriorPin;
   int contador;
   do
   {
      estadoActualPin=input( pinSinRebote );
      if(estadoActualPin != estadoAnteriorPin)
      {
         contador=0;
         estadoAnteriorPin=estadoActualPin;
      }
      else
      {
         contador++;
      }
      delay_ms(1);
   }
   while( contador<10 );
   estado = estadoActualPin;
   return estado;
}

Y si no vá, tirá el compilador a la basura.
 
Entonces probá con esto... Y si no vá, tirá el compilador a la basura.

Desinstale la versión dinosaurio del PICC de CCS que tenia cuando aun estudiaba electrónica (era la 3.pico) y me conseguí la versión 5.078. Salio a la primera :cool::cool:.
Gracias por sus aportes. Ahora voy a mejorar la función con el timer0 o timer1 para no usar el delay, que en cierta manera se comporta como modo "marrano" (expresión de TriloByte).
 
Buen aporte. Está bueno el código, aunque ahora la normal ejecución del programa. Depende del contexto puede servir o no, porque el código hace algo como "no hago nada mientras no suelte el dedo del pulsador".
 
Gracias por sus aportes. Ahora voy a mejorar la función con el timer0 o timer1 para no usar el delay, que en cierta manera se comporta como modo "marrano" (expresión de TriloByte).
En realidad es sencillo pero a ver cuantos gruñidos salen antes de llegar a la solución optima
 
Última edición:
En realidad es sencillo pero a ver cuantos gruñidos salen antes de llegar a la solución optima
Tienes razón. Lo haré así: una vez se llama a la función antirrebotes se carga un timer con 10ms, si los estados actual y anterior son diferentes entonces se vuelve a recargar el timer con los mismos 10ms. Esto lo hara mientras la lectura del timer sea menor o igual a la carga de los 10ms.
 
Si te pones a esperar en un bucle a que el timer se desborde seria lo mismo que usar un delay de 10ms, claro siempre depende como esta estructurado el código, sera interesante ver implementada las solución que propones
 
Bueno yo quiero hacer una pequeña reflexion desde mi punto de vista y con mi justo conocimiento, que es pequeño, el tema de los antirrebotes, por lo que llevo leido da para mucho pero realmente es tan tan imprescindible y me explico, como bien pone yorsk2004 lo quiere para evitar el rebote en unos pulsadores, pero salvo que me equiboque, cuando entramos en una funcion especifica para modificar algun valor, lo que hacemos es pulsar teclas en concreto, si en ese momento hay alguna otra funcion en marcha, esta sigue funcionando, ejemplo: un motor activado, por lo que hacemos la modificacion que necesitamos y luego salimos de dicha funcion siguiendo el programa con su rutina normal.

Si dentro de esa funcion ponemos algun delay ¿hasta que punto es tan importante evitar el delay para hacer el antirrebote?, digo esto por que con un delay de unos 250 milis se elimina el rebote y con poner eso se puede ahorrar codigo y como va a ser poco tiempo no deveria importar mucho, pienso yo.

Segun comentais es mejor usar ese tiempo en hacer algunas comprobaciones en vez de poner un delay, pero claro como hacemos para hacer esos calculos, sabemos que con unos 200milis, mas-menos, evitamos el rebote, pero cuantas comprobaciones se puden colocar para que pase ese mismo tiempo y de paso evitar el rebote? o dicho de otra manera cuanto tarda mas-menos una instruccion? o mejor dicho ¿tiene sentido crear instrucciones, con lo que aumentamos el codigo, solo para evitar unos simples delays?.

Ya de paso una pregunta, en los codigos que mirado por hay, codigos sencillos, no veo que creen funciones especificas para evitar rebotes, quiere esto decir que tal vez lo que se suele hacer es mas incrementar componentes, llamensen condensadores y reistencias, para evitar incrementar sofware?.
 
Atrás
Arriba