Interruptor de software efectivo que elimina el AVR

0

Quizás sea un asunto simple, pero causa algunos problemas.

¿Tiene formas efectivas y sencillas de cambiar las eliminaciones por rebote? Estoy realizando un experimento y conecté el microinterruptor a una E / S digital en el AVR y el LED para las pruebas, y estoy luchando con ello. Necesito un método que funcione en segundo plano (no demora ()) y no muy sofisticado. Solo una manera simple.

Hasta ahora he intentado esas formas:

1.

   #include <avr/io.h>

  #define LED (1<<PB5)
  #define BUTTON (1<<PD0)

  uint8_t key_lock = 0;

 int main()
 {
   DDRB |= (1<<LED);
   DDRD &= ~(1<<BUTTON);
   PORTD |= (1<<BUTTON);


   while(1)
   {
      if (!key_lock && !(PIND & BUTTON))
   {
      key_lock = 1;
      PORTB ^= LED;
    }
    else if (key_lock && (PIND && BUTTON))
   {
      key_lock++;
    }
   }  
  }

2.

 #include <avr/io.h>
 #include <avr/interrupt.h>

 #define LED (1<<PB5)
 #define BUTTON (1<<PD0)

 volatile bool  state_but = false;

 int main()
 {
   DDRB |= (1<<LED);
   DDRD &= ~(1<<BUTTON);
   PORTD |= (1<<BUTTON);

  // Timera0  overflow
  //F_CPU = 16MHz. time interrupt 16 ms
  TCCR0B |= (1<<CS02) | (1<<CS00);
  TIMSK0 |= (1<<TOIE0);


  sei();

   while(1)
    {
    if (state_but == 1)
     PORTB ^= LED;
    }  
   }

  ISR (TIMER0_OVF_vect)
  {

    static uint8_t state_last = 0, state_new;

  //1- ON, 0 - OFF
  state_new = (~PIND & BUTTON);

   if (state_last == state_new)
     state_but = state_new;

    state_last = state_new;
   }

3.

      #include <avr/io.h>
      #include <avr/interrupt.h>

    #define LED (1<<PB5)
    #define BUTTON (1<<PD0)

   volatile uint8_t counter;

  int main()
 {
 DDRB |= (1<<LED);
 DDRD &= ~(1<<BUTTON);
  PORTD |= (1<<BUTTON);

    //  Timera0  overflow
 //F_CPU = 16MHz. time interrupt 16ms

  TCCR0B |= (1<<CS02) | (1<<CS00);
  TIMSK0 |= (1<<TOIE0);


    sei();

 while(1)
 {
     if (counter == 2)
     PORTB ^= LED;
  }  
 }

     ISR (TIMER0_OVF_vect)
     {


         if (!(PIND & BUTTON))
       {
         counter++;    
        }
       else
       {
         counter = 0;
       }

       if (counter > 2) counter = 0;



   }    

Y ninguno de esos funciona tan bien. A veces, cuando presiono el botón aparece estados aleatorios y el LED parpadea sin control.

Necesito agregar que estoy usando ATmega 2560 (Arduino MEGA) pero programando solo en C, como puedes ver.

¿Alguna idea?

    
pregunta M_K

2 respuestas

2

Utilizo varias técnicas diferentes, pero la mayoría confío en tener disponible un tick de temporizador continuo.

Debido a que trabajo principalmente con microcontroladores PIC que funcionan a 4 MHz, mi temporizador es de 1.024 ms. Este es un tic del temporizador de sondeo en lugar de una interrupción: Tmr0 se ejecuta con un valor de preescala apropiado. Utilizo el indicador de interrupción Tmr0 como mi indicador de desbordamiento, a pesar de que la interrupción Tmr0 está desactivada.

Los dos métodos que uso con más frecuencia son los siguientes:

1) un contador ascendente que está configurado para no ajustarse por debajo o por encima del flujo. El conteo 0x00 es un estado no permitido y nunca ocurre durante el tiempo de ejecución. El ancho de bits del contador se adapta para que coincida con mi tiempo de rebote deseado.

El rebote en sí mismo ocurre durante la tarea en segundo plano cuando se actualiza la marca del temporizador. La tarea de primer plano simplemente prueba el valor del contador para valor máximo o mínimo, según sea necesario.

2) un solo byte donde el estado de entrada se gira en el byte. La frecuencia de muestreo es un sub-múltiplo de mi marca del temporizador principal.

Como antes, la muestra se produce durante la tarea en segundo plano cuando se actualiza la marca del temporizador. También como se indicó anteriormente, la tarea de primer plano simplemente prueba el byte para 0xFF o 0x00.

Usaré esta técnica cuando ejecuto un reloj muy lento y donde solo 8 muestras me dan un tiempo de rebote adecuado.

Ambos son muy rápidos y muy fáciles de implementar.

    
respondido por el Dwayne Reid
1

La forma más simple es hacer esto por muestreo. Por ejemplo, si el rebote observado toma, por ejemplo, un máximo de 100 us, elegí 10 veces más tiempo para el muestreo: 1 ms (1 kHz).

Por lo tanto, cada milisegundo se leerá el estado del botón. Entonces, el valor muestreado se rebobinará por completo y el tiempo de reacción máximo será, en este caso, inferior a 1 ms.

Será como un filtro discreto de paso bajo configurado a 500Hz (la mitad de la frecuencia de muestreo - 1kHz).

Personalmente utilizo este principio en todas partes donde tengo botones o teclado y es 100% confiable y también muy simple para la implementación.

    
respondido por el vlk

Lea otras preguntas en las etiquetas