0
\$\begingroup\$

Maybe simple matter, but causes some troubles.

Do you have any effective and simple ways for switch bouncing elliminations? I'm doing an experiment and I've connected micro-switch to a digital I/O in AVR and LED for the testing, and I'm struggling with it. I need method which works in background (not delay()) and not very sophisticated. Just a simple way.

So far I tried those ways:

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;



   }    

And none of those works so good. Sometimes when I push the button it appears random states and LED blinks without control.

I need to add that I'm using ATmega 2560 (Arduino MEGA) but programing only in C, as you can see.

Any ideas?

\$\endgroup\$
  • \$\begingroup\$ It would help if you put comments into your code, and what you expect it to do. \$\endgroup\$ – Anonymous Jul 28 '17 at 17:43
  • \$\begingroup\$ I haven't used assembly on the ATmega yet, but if it is similar enough to the AT90 assembly then you might consider this post I made some time ago: electronics.stackexchange.com/questions/269909/… \$\endgroup\$ – jonk Jul 28 '17 at 20:28
  • \$\begingroup\$ Option 2 is essentially what I have used in ~15 years of projects. A 16mS debounce time should be enough for most types of switches. What exactly is the problem you are observing when you run this code? \$\endgroup\$ – Jon Jul 29 '17 at 7:37
2
\$\begingroup\$

I use several different techniques but most rely upon having a continuous timer tick available.

Because I work mostly with PIC microcontrollers running at 4 MHz, my timer tick is 1.024 ms. This is a polled timer tick rather than an interrupt: Tmr0 free-runs with an appropriate prescale value. I use the Tmr0 Interrupt Flag as my indicator of overflow even though the Tmr0 Interrupt is disabled.

The two methods I use most often are as follows:

1) an up-down counter that is configured not to wrap either under or over flow. Count 0x00 is a disallowed state and never occurs during run time. The bit width of the counter is tailored to match my desired debounce time.

The debounce itself occurs during the background task when the timer tick is updated. The foreground task simply tests the counter value for either max or min value as required.

2) a single byte where the input state is rotated into the byte. The sample rate is some sub-multiple of my main timer tick.

As above, the sample occurs during the background task when the timer tick is updated. Also as above, the foreground task simply tests the byte for either 0xFF or 0x00.

I'll use this technique when I'm running a very slow clock and where only 8 samples gives me an appropriate debounce time.

Both of these are ery, very quick and quite easy to implement.

\$\endgroup\$
1
\$\begingroup\$

Simplest way is to do this by sampling. For example, if observed bouncing takes for example maximum 100us, I chose 10 times longer time for sampling: 1ms (1kHz).

So every millisecond the button status will be read. Then the sampled value will be completely debounced and maximum reaction time will be in this case less than 1ms.

It will be like discrete low pass filter set to 500Hz (half of sampling frequency - 1kHz).

Personally I use this principle everywhere where I have buttons or keyboard and it is 100% reliable and also very simple for implementation.

\$\endgroup\$
  • \$\begingroup\$ Somethig is still wrong. I expand my interrupt time until 100 ms and I've noticed one thing. I carried an experiment and short uC pin do the ground (just like button constantly pressed). Every time the LED blinks several very short times and then there is longer gap, and this process is repeated when this short exists. It weird. What do you think about it? \$\endgroup\$ – M_K Aug 10 '17 at 17:48
  • \$\begingroup\$ You probably encountered with race condition. Never read and write GPIO from interrupt routines! Be very careful with interrupts, best is to always avoid interrupts if it is possible to do it witout. Try to do this in main loop. Interrupt is not necessary in this case and if you need an exact time constant and you think that interrupt is the only way, then in interrupt routine just set flag or increment one number (it must be volatile) and in main loop just compare the number with last and if was changed then do action which you do actually in interrupt. \$\endgroup\$ – vlk Aug 11 '17 at 5:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.