Saltar al contenido principal
LibreTexts Español

8.2: Desrebotar

  • Page ID
    83163
  • \( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \) \( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)\(\newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\) \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\) \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\) \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\) \( \newcommand{\Span}{\mathrm{span}}\) \(\newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\) \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\) \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\) \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\) \( \newcommand{\Span}{\mathrm{span}}\)\(\newcommand{\AA}{\unicode[.8,0]{x212B}}\)

    Los interruptores mecánicos del mundo real no se comportan idealmente. Cuando se lanza un interruptor, los contactos mecánicos rebotan después del cierre inicial, lo que resulta en una serie de contactos de ruptura. Esto podría durar 10 milisegundos o más dependiendo del diseño del switch. Ejemplos de rebote del interruptor se muestran en la Figura\(\PageIndex{1}\). El problema es que el microcontrolador puede leer el pin de entrada en una fracción de milisegundo, y por lo tanto, parece como si el interruptor se estuviera encendiendo y apagando muy rápidamente durante este tramo de varios milisegundos. En algunas aplicaciones esto no es un problema, por ejemplo, cuando se activa un LED según la posición del interruptor (es decir, “arriba” o “deprimido” enciende el LED). En esta instancia, el rebote o parloteo de la señal y el LED no serán notados por el ojo humano. Por el contrario, podríamos programar un interruptor de botón para que múltiples pulsaciones aumenten un nivel como brillo o volumen. En este caso, la charla podría hacer que se salten una serie de niveles produciendo una respuesta inconsistente y peculiar a la entrada del usuario.

    clipboard_e23185678dc634b5fc26f3cd2f02ad0c2.pngclipboard_e8212448e13feea45bf0b18b0c265e7fd.png

    Figura\(\PageIndex{1}\): Rebote del interruptor

    Hay dos formas básicas de “desrebotar” los interruptores. El primero involucra software y el segundo involucra hardware. Veamos primero una solución de software.

    La clave para un debounce de software es extender el tiempo que se está examinando el switch. En otras palabras, queremos examinar el estado a lo largo de un periodo de tiempo lo suficientemente largo como para que el rebote se asiente. Por ejemplo, si observamos que el estado no ha cambiado en el transcurso de, digamos, diez milisegundos, podemos asumir con seguridad que no estamos tratando de leer la entrada durante un rebote. Considera la variante de código a continuación. Se parece mucho a la versión tres pero hay una nueva función agregada, get_state (). Aquí es donde está toda la acción.

    /* Read Digital Input V4. Monitors Arduino pin 8 and sends value to the 
    Serial Monitor, generic form, only reports state changes, with software 
    debounce */
    
    // new function prototype
    int get_state(void);
    
    // Arduino pin 8 is port bit B.0
    #define BITMASK 0x01
    
    int priorstate=0;
    
    void setup()
    {
          Serial.begin(9600);
    
          DDRB &= (~BITMASK);     // initialize the pin as an input.
          PORTB |= BITMASK;       // enable pull-up
    }
    void loop()
    {
          int state;
    
          state = get_state();
    
          if( state != priorstate )
          {
                Serial.println(state);
                priorstate = state;
          }
    }
    
    int get_state(void)
    {
          int priorstate, state, count=0, i=0;
    
          priorstate = PINB & BITMASK;
    
          while( i < 30 )
          {
                state = PINB & BITMASK;
    
                if( state == priorstate )
                      count++;
                else
                {
                      count = 0;
                      priorstate = state;
                }
               
                if( count >= 10 )
                      break;
    
                delay(1);
                i++;
          }
          return( state );
    }
    

    La idea detrás de esta nueva función es verificar continuamente el pin y no regresar hasta que hayamos visto diez milisegundos de valores consistentes. Cada vez que el estado actual es el mismo que el estado anterior incrementamos el recuento. Cuando llega a 10 sabemos que hemos logrado al menos diez milisegundos de señal inmutable (debido a la llamada delay () de un milisegundo en la parte inferior del bucle), salimos del bucle y devolvemos el estado pin. Si los niveles cambian debido al rebote, el estado y el estado anterior no serán los mismos por lo que se restablece el recuento. Si un switch es defectuoso, el período de rebote podría durar mucho tiempo y para evitar que el código “cuelgue” y permanezca en esta función para siempre, se instituye un número máximo de 30 iteraciones (al menos 30 milisegundos) a través de la variable i.

    Ingresa la versión cuatro y guárdala bajo un nuevo nombre ya que volveremos a la versión tres un poco más tarde. Compila y transfiere el código, y luego pruébalo usando el Monitor Serial. Esta versión debería producir una salida agradable y consistente en el Monitor Serial sin las transiciones extrañas de la versión tres. También vale la pena señalar que el código de máquina resultante es aún más pequeño que el código original hecho con las bibliotecas Arduino a pesar de una mayor funcionalidad (2654 bytes frente a 2726 bytes para la versión uno).

    El segundo método para eliminar el rebote de un switch es a través de hardware. Generalmente, esto toma la forma de que el conmutador está conectado a una red RC que alimenta un disparador Schmitt (74HC14). La red RC filtrará efectivamente la señal de parloteo y la histéresis del Schmitt se encargará de cualquier ruido persistente o fluctuación. La figura\(\PageIndex{2}\) es un ejemplo típico (tenga en cuenta que la lógica del conmutador se invierte debido al inversor):

    clipboard_ed6c4bc8029df3433a62dcf89882a2fe8.png

    Figura\(\PageIndex{2}\): Circuito de desrebote del disparador RC-Schmitt

    Los valores típicos para este circuito serían 4.7 k\(\Omega\) para R1, 470 k\(\Omega\) para R2 y 100 nF para C. La constante de tiempo RC para este circuito es de aproximadamente 50 milisegundos por lo que los umbrales Schmitt se alcanzarán en alrededor de 200 milisegundos (menos de 5\(\tau\)). Esto debería encargarse incluso del interruptor mecánico más maniático. Además, tenga en cuenta que esta es una señal de entrada activa por lo que no se necesitará el pull-up de entrada. Volvamos a la versión tres (sin debounce de software) y hagamos una modificación para acomodar el debounce de hardware:

    /* Read Digital Input V5. Monitors Arduino pin 8 and sends value to the 
    Serial Monitor, generic form, only reports state changes, requires hardware 
    debounce to drive the input */
    
    // Arduino pin 8 is port bit B.0
    #define BITMASK 0x01
    
    int priorstate=0;
    
    void setup()
    {
          Serial.begin(9600);
    
          DDRB &= (~BITMASK);     // initialize the pin as an input.
          // pull-up code has been removed
    }
    
    void loop()
    {
          int state;
    
          state = PINB & BITMASK;
    
          if( state != priorstate )
          {
                Serial.println(state);
                priorstate = state;
          }
    }
    

    Retire el interruptor de hardware de la placa. Construye el circuito debounce de Figure\(\PageIndex{2}\) y conecta su salida al pin 8 de Arduino. Compilar y transferir el código. Abra el Monitor Serial y pruebe los resultados. Debe ser similar al de la versión cuatro con software debounce. También tenga en cuenta que el código es aproximadamente 300 bytes más pequeño. Hemos intercambiado memoria por hardware de manera efectiva.

    Hay algunas ventajas agradables para el debounce de software en comparación con el debounce de hardware. Primero, es muy flexible ya que el código se puede cambiar para afinar la actuación. En segundo lugar, no hay costo asociado para los componentes de hardware adicionales o el espacio de placa ampliado para acomodarlos. Sin embargo, hay algunas desventajas, como el aumento de los requisitos de memoria de código para las funciones de desrebote (recuerde, los microcontroladores, a diferencia de las PC, tienden a tener una capacidad de memoria muy modesta). Otro problema es el tiempo perdido esperando que se asiente la señal del interruptor. Diez o veinte milisegundos pueden no parecer mucho pero en algunas aplicaciones puede ser una eternidad. Si el debounce de software o hardware se utilizará para un diseño en particular; de hecho, si el debounce se utilizará en absoluto, dependerá de otros factores del sistema.

    Obviamente, monitorear el estado del pin con la herramienta Serial Monitor es muy útil para depurar y aprender cómo funciona el dispositivo pero no es una aplicación típica así que pasemos a algo un poco más útil. En lugar de enviar salida al monitor serie, reflejemos el estado usando un LED externo fuera del pin 12 de Arduino, es decir, bit 4 del puerto B. Continuaremos usando el circuito de debounce de hardware con el nuevo código a continuación:

    /* Read Digital Input V6. Monitors Arduino pin 8 and reflects value to an 
    external LED, generic form, requires hardware debounce to drive the input */
    
    // Arduino pin 8 is port bit B.0
    #define BITMASK 0x01
    
    // Place LED driver on Arduino pin 12 or port bit B.4
    #define LEDMASK 0x10
    
    int priorstate=0;
    
    void setup()
    {
          DDRB &= (~BITMASK);     // initialize the pin as an input from 74HC14
          DDRB |= LEDMASK;        // initialize the pin as an output to the LED
    }
    
    void loop()
    {
          int state;
    
          state = PINB & BITMASK;
    
          if( state != priorstate ) // don’t bother if no change
          {
                priorstate = state;
    
                if( state )
                      PORTB |= LEDMASK;       // light LED
                else
                      PORTB &= (~LEDMASK);    // extinguish LED
          }
    }
    

    Construya un circuito controlador LED estándar (las versiones NPN y PNP que se muestran en la Figura\(\PageIndex{3}\)) y conéctelo al pin 12 de Arduino. Determine un valor para Rc para lograr aproximadamente 10 miliamperios de corriente LED asumiendo que el voltaje del LED es de 2 voltios. Establezca Rb para lograr una corriente base de alrededor de 500 microamperios.

    clipboard_e7e6205152fc3ebd93f7586bd65c8f0ac.pngclipboard_e435c7c72053ecd8ad10adfc7e13013c5.png

    Figura\(\PageIndex{3}\): Circuitos de controlador LED

    Una vez que el hardware esté en su lugar; ingrese, compile y transfiera el código. El LED debe reflejar la posición de su interruptor. Además, si aún no te has dado cuenta, mira la barra de estado en el editor. Debido a que ya no estamos usando el Serial Monitor y su biblioteca asociada, ¡el tamaño del código ha caído a solo 510 bytes!


    This page titled 8.2: Desrebotar is shared under a CC BY-NC-SA 4.0 license and was authored, remixed, and/or curated by James M. Fiore via source content that was edited to the style and standards of the LibreTexts platform; a detailed edit history is available upon request.