Close

Button control: Working

A project log for Key Pass

Keychain USB multiple password manager/generator/injector

danjovicdanjovic 10/31/2015 at 15:010 Comments

I've managed to put both SELECT and SEND buttons to work by using a non-blocking de-bouncing routine than can even distinguish between 'short-press' and 'long-press'.

The algorithm is very simple

static int counter;

if (button_is_pressed) 
    counter++;
else { // button is released
   if (counter < _time_short_press) return _no_key_pressed
   if (counter < _time_long_press) return _short_press
   /*else */ return _long_press
}

the real code is a bit more complex because you have to saturate the counter so it doesn't roll over, and at the release it has to be zeroed.


Another challenge was how to measure the correct timing for the temporization of short press (~100ms) and long press (500ms). Initially I have set the 'counter' variable to uint_16 and tried to guess the correct values but ,since the debounce routines run in the main loop, even a large value like 65500 counts were reached withing the time of a short press.
The solution was another trick involving TIMER2. We know from a previous log that TIMER2 increments at each 64us (16MHz/1024=15625Hz=1/64us). Using other words, the bit 0 from register TCNT2 flips at each 64us, then the bit 1 flips at each 128us, and so on.

Then if I consider again using a counter with 8 bits, and want to keep the long press time close to the end of counting, I can assume that 250 countings will be equal 500ms. Doing the math, a short press shall take at least 50 counts (100ms) and ONE count shall be as close as possible to 2ms.

Well, 2ms/64us is pretty close to 32 and now the problem is solved: The debouncing routine shall check if the 5th bit of TCNT 2 has flipped since the last time it was called. If so and the button is pressed, then increment the counter.

The whole code for 1 button is shown below

#define B1_Pressed ((PINB & (1<<1))==0)
#define treshold_short_press 50  
#define treshold_long_press  250  
uint8_t debounce_B1 (void) {

    static uint8_t last_timer_toggle=0;
    static uint8_t time_button_pressed=0;
    uint8_t temp;

    if (B1_Pressed) {  
        temp=TCNT2 & (1<<5); // 
        if ( (temp!=last_timer_toggle) & (time_button_pressed <255) ) 
        {// advance and saturate VX7333b6450X
            time_button_pressed++; 
            last_timer_toggle=temp;
        }  
        return _no_press;     
    } else {  // button is released  
        temp=time_button_pressed;
        time_button_pressed=0;
        if (temp < treshold_short_press) return _no_press;     //below noise treshold 
        if (temp < treshold_long_press)  return _short_press;  //above noise treshold and below long press treshold
        else return _long_press ;                           //above long press treshold 
    }
    return _no_press; // redundant  
}

Discussions