14 Key poller with debouncing DEMO

Dependencies:   mbed

main.cpp

Committer:
ekelmans
Date:
2012-01-07
Revision:
1:6ee2362ce0fd
Parent:
0:acabda48796c

File content as of revision 1:6ee2362ce0fd:

/* -----------------------------------------------------------------------
   14 Key poller and debounce demo by Theo Ekelmans, Version 1.01
   -----------------------------------------------------------------------
   
   In this demo, banks A, C and D are push buttons, bank B are toggle switches that have a LED inside
   
   A 4x20 LCD is used in this demo to show key status and debounce info
   
   The timer used for SampleInterval is set to 10 ms (sample time)

   2 * SampleInterval = 20ms for good quality switches, 80ms for high CPU load or really crappy switches :)
   
   led3 on the MBED is used to indicate a debounce
   
   Config your USB COM port terminal session as a VT100 terminal :)
       
   Notes: 
   1: The SampleCnt is 32 bit, that means every 2^32 times 10ms SampleInterval it will trigger an overflow 
      on the long vars, thats why @ 4000000000 the TimerOverflowRecover resets all counters. 
      During in that brief moment (2 miliseconds every 25 days or so), the debounce is not reliable ;)
  
 */

#include "mbed.h"
#include "DigitalIn.h"

//--- Defines
#define ON  1
#define OFF 0

//ASCII commands for the VT100 terminal
#define LF  10
#define CLS 12
#define CR  13
#define BS  8
#define ESC 27 

//Serial LCD - Matrix Orbital LK204 command codes
#define CMD 254 
#define CurPos 71 //follow up by COL ROW

Serial lcd(p9, p10);  // tx, rx

//Debounce vars
int  DebounceThreshold = 3; // 2 * SampleInterval = 20ms for good quality switches, 80ms for high CPU load or really crappy switches :)
float SampleInterval = 0.01; // The timer for debouncing interval: 10 ms sample time

unsigned long KillBeepAt = 0;
char strCmd [100] = ""; 

//Debounce vars
unsigned long SampleCnt = 0;
unsigned long DebounceActivationCounter = 0;
unsigned long LastSampleA1 = 0;
unsigned long LastSampleA2 = 0;
unsigned long LastSampleA3 = 0;
unsigned long LastSampleA4 = 0;
unsigned long LastSampleB1 = 0;
unsigned long LastSampleB2 = 0;
unsigned long LastSampleB3 = 0;
unsigned long LastSampleB4 = 0;
unsigned long LastSampleC1 = 0;
unsigned long LastSampleC2 = 0;
unsigned long LastSampleC3 = 0;
unsigned long LastSampleC4 = 0;
unsigned long LastSampleD1 = 0;
unsigned long LastSampleD2 = 0;

bool LastButtonA1 = false;
bool LastButtonA2 = false;
bool LastButtonA3 = false;
bool LastButtonA4 = false;
bool LastButtonB1 = false;
bool LastButtonB2 = false;
bool LastButtonB3 = false;
bool LastButtonB4 = false;
bool LastButtonC1 = false;
bool LastButtonC2 = false;
bool LastButtonC3 = false;
bool LastButtonC4 = false;
bool LastButtonD1 = false;
bool LastButtonD2 = false;

// The switch mapping
DigitalIn buttonA1(p11);
DigitalIn buttonA2(p12);
DigitalIn buttonA3(p13);
DigitalIn buttonA4(p14);
DigitalIn buttonB1(p15);
DigitalIn buttonB2(p16);
DigitalIn buttonB3(p17);
DigitalIn buttonB4(p18);
DigitalIn buttonC1(p21);
DigitalIn buttonC2(p22);
DigitalIn buttonC3(p23);
DigitalIn buttonC4(p24);
DigitalIn buttonD1(p28);
DigitalIn buttonD2(p27);

//Bank B Leds
DigitalOut ledH1(p5);
DigitalOut ledH2(p6);
DigitalOut ledH3(p7);
DigitalOut ledH4(p8);

//MBED leds
DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);
DigitalOut led4(LED4);

//Timer that starts the polling event
Ticker DebounceTimer;

//Beeper port
DigitalOut Beep(p29);

// Config your USB COM port terminal session as a VT100 terminal :)
Serial usbUART ( USBTX, USBRX );

// Kill tha beep.... 
void KillBeep() {Beep = OFF; } // beepTimer.detach();}


//-------------------------------------------------------------------------------------------------------
//This is where you put your payload; 
//-------------------------------------------------------------------------------------------------------
void PayLoadPressed(char msg[] ) { lcd.printf("%c%c%c%cA%i%i%i%iB%i%i%i%iC%i%i%i%iD%i%i\r\n%ld bounce events\r\nKey + %s @ %ld", CMD, CurPos, 1, 1,buttonA1.read(),buttonA2.read(),buttonA3.read(),buttonA4.read(),buttonB1.read(),buttonB2.read(),buttonB3.read(),buttonB4.read(),buttonC1.read(),buttonC2.read(),buttonC3.read(),buttonC4.read(),buttonD1.read(),buttonD2.read(), DebounceActivationCounter, msg, SampleCnt);};
void PayLoadRelease(char msg[] ) { lcd.printf("%c%c%c%cA%i%i%i%iB%i%i%i%iC%i%i%i%iD%i%i\r\n%ld bounce events\r\nKey - %s @ %ld", CMD, CurPos, 1, 1,buttonA1.read(),buttonA2.read(),buttonA3.read(),buttonA4.read(),buttonB1.read(),buttonB2.read(),buttonB3.read(),buttonB4.read(),buttonC1.read(),buttonC2.read(),buttonC3.read(),buttonC4.read(),buttonD1.read(),buttonD2.read(), DebounceActivationCounter, msg, SampleCnt);};

//-------------------------------------------------------------------------------------------------------
//This routine is only needed for the demo and can be removed for runtime
//-------------------------------------------------------------------------------------------------------
void DeboucnceActive(char msg[], unsigned long l, unsigned long c) { 
    lcd.printf("%c%c%c%cA%i%i%i%iB%i%i%i%iC%i%i%i%iD%i%i\r\n%ld bounces\r\nKey - %s @ %ld\r\n%s bounced %ld samples", CMD, CurPos, 1, 1, buttonA1.read(),buttonA2.read(),buttonA3.read(),buttonA4.read(),buttonB1.read(),buttonB2.read(),buttonB3.read(),buttonB4.read(),buttonC1.read(),buttonC2.read(),buttonC3.read(),buttonC4.read(),buttonD1.read(),buttonD2.read(), DebounceActivationCounter, msg, SampleCnt, msg, (c - l));
    DebounceActivationCounter ++; 
    led3 = !led3; //Blink on debounce
    Beep = ON;
    KillBeepAt = SampleCnt + 50; //Kill Beep in 500 Ms
    };

//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//                              Wait at least <DebounceThreshold> samples       Toggle status             Payload              Save debounce counter           Debounce active         
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void keyPressedA1 ( void ) {if ((LastSampleA1 + DebounceThreshold) < SampleCnt) {LastButtonA1 = buttonA1; PayLoadPressed("F"); LastSampleA1 = SampleCnt;} else {DeboucnceActive("F", LastSampleA1, SampleCnt);};};
void keyReleasedA1( void ) {if ((LastSampleA1 + DebounceThreshold) < SampleCnt) {LastButtonA1 = buttonA1; /*no key up event*/  LastSampleA1 = SampleCnt;} else {/*no key up debounce needed either*/         ;};};
void keyPressedA2 ( void ) {if ((LastSampleA2 + DebounceThreshold) < SampleCnt) {LastButtonA2 = buttonA2; PayLoadPressed("G"); LastSampleA2 = SampleCnt;} else {DeboucnceActive("G", LastSampleA2, SampleCnt);};};
void keyReleasedA2( void ) {if ((LastSampleA2 + DebounceThreshold) < SampleCnt) {LastButtonA2 = buttonA2;                      LastSampleA2 = SampleCnt;} else {                                             ;};};
void keyPressedA3 ( void ) {if ((LastSampleA3 + DebounceThreshold) < SampleCnt) {LastButtonA3 = buttonA3; PayLoadPressed("H"); LastSampleA3 = SampleCnt;} else {DeboucnceActive("H", LastSampleA3, SampleCnt);};};
void keyReleasedA3( void ) {if ((LastSampleA3 + DebounceThreshold) < SampleCnt) {LastButtonA3 = buttonA3;                      LastSampleA3 = SampleCnt;} else {                                             ;};};
void keyPressedA4 ( void ) {if ((LastSampleA4 + DebounceThreshold) < SampleCnt) {LastButtonA4 = buttonA4; PayLoadPressed("I"); LastSampleA4 = SampleCnt;} else {DeboucnceActive("I", LastSampleA4, SampleCnt);};};
void keyReleasedA4( void ) {if ((LastSampleA4 + DebounceThreshold) < SampleCnt) {LastButtonA4 = buttonA4;                      LastSampleA4 = SampleCnt;} else {                                             ;};};

//Toggle switches need a payload on the pressed and release event, and debouncing on both 
void keyPressedB1 ( void ) {if ((LastSampleB1 + DebounceThreshold) < SampleCnt) {LastButtonB1 = buttonB1; PayLoadPressed("A"); LastSampleB1 = SampleCnt;} else {DeboucnceActive("A", LastSampleB1, SampleCnt);};};
void keyReleasedB1( void ) {if ((LastSampleB1 + DebounceThreshold) < SampleCnt) {LastButtonB1 = buttonB1; PayLoadRelease("a"); LastSampleB1 = SampleCnt;} else {DeboucnceActive("a", LastSampleB1, SampleCnt);};};
void keyPressedB2 ( void ) {if ((LastSampleB2 + DebounceThreshold) < SampleCnt) {LastButtonB2 = buttonB2; PayLoadPressed("B"); LastSampleB2 = SampleCnt;} else {DeboucnceActive("B", LastSampleB2, SampleCnt);};};
void keyReleasedB2( void ) {if ((LastSampleB2 + DebounceThreshold) < SampleCnt) {LastButtonB2 = buttonB2; PayLoadRelease("b"); LastSampleB2 = SampleCnt;} else {DeboucnceActive("b", LastSampleB2, SampleCnt);};};
void keyPressedB3 ( void ) {if ((LastSampleB3 + DebounceThreshold) < SampleCnt) {LastButtonB3 = buttonB3; PayLoadPressed("C"); LastSampleB3 = SampleCnt;} else {DeboucnceActive("C", LastSampleB3, SampleCnt);};};
void keyReleasedB3( void ) {if ((LastSampleB3 + DebounceThreshold) < SampleCnt) {LastButtonB3 = buttonB3; PayLoadRelease("c"); LastSampleB3 = SampleCnt;} else {DeboucnceActive("c", LastSampleB3, SampleCnt);};};
void keyPressedB4 ( void ) {if ((LastSampleB4 + DebounceThreshold) < SampleCnt) {LastButtonB4 = buttonB4; PayLoadPressed("D"); LastSampleB4 = SampleCnt;} else {DeboucnceActive("D", LastSampleB4, SampleCnt);};};
void keyReleasedB4( void ) {if ((LastSampleB4 + DebounceThreshold) < SampleCnt) {LastButtonB4 = buttonB4; PayLoadRelease("d"); LastSampleB4 = SampleCnt;} else {DeboucnceActive("d", LastSampleB4, SampleCnt);};};

//Push button switches only need a payload and debouncing on the pressed event, and you can ignore the release event (C4 left on for demo purposes)
void keyPressedC1 ( void ) {if ((LastSampleC1 + DebounceThreshold) < SampleCnt) {LastButtonC1 = buttonC1; PayLoadPressed("L"); LastSampleC1 = SampleCnt;} else {DeboucnceActive("L", LastSampleC1, SampleCnt);};};
void keyReleasedC1( void ) {if ((LastSampleC1 + DebounceThreshold) < SampleCnt) {LastButtonC1 = buttonC1; /*no key up event*/  LastSampleC1 = SampleCnt;} else {/*no key up debounce needed either*/         ;};};
void keyPressedC2 ( void ) {if ((LastSampleC2 + DebounceThreshold) < SampleCnt) {LastButtonC2 = buttonC2; PayLoadPressed("M"); LastSampleC2 = SampleCnt;} else {DeboucnceActive("M", LastSampleC2, SampleCnt);};};
void keyReleasedC2( void ) {if ((LastSampleC2 + DebounceThreshold) < SampleCnt) {LastButtonC2 = buttonC2;                      LastSampleC2 = SampleCnt;} else {                                             ;};};
void keyPressedC3 ( void ) {if ((LastSampleC3 + DebounceThreshold) < SampleCnt) {LastButtonC3 = buttonC3; PayLoadPressed("N"); LastSampleC3 = SampleCnt;} else {DeboucnceActive("N", LastSampleC3, SampleCnt);};};
void keyReleasedC3( void ) {if ((LastSampleC3 + DebounceThreshold) < SampleCnt) {LastButtonC3 = buttonC3;                      LastSampleC3 = SampleCnt;} else {                                             ;};};
void keyPressedC4 ( void ) {if ((LastSampleC4 + DebounceThreshold) < SampleCnt) {LastButtonC4 = buttonC4; PayLoadPressed("O"); LastSampleC4 = SampleCnt;} else {DeboucnceActive("O", LastSampleC4, SampleCnt);};};
void keyReleasedC4( void ) {if ((LastSampleC4 + DebounceThreshold) < SampleCnt) {LastButtonC4 = buttonC4; PayLoadRelease("o"); LastSampleC4 = SampleCnt;} else {DeboucnceActive("o", LastSampleC4, SampleCnt);};};

//Push button switches only need a payload and debouncing on the pressed event, and you can ignore the release event (D2 left on for demo purposes)
void keyPressedD1 ( void ) {if ((LastSampleD1 + DebounceThreshold) < SampleCnt) {LastButtonD1 = buttonD1; PayLoadPressed("Q"); LastSampleD1 = SampleCnt;} else {DeboucnceActive("Q", LastSampleD1, SampleCnt);};};
void keyReleasedD1( void ) {if ((LastSampleD1 + DebounceThreshold) < SampleCnt) {LastButtonD1 = buttonD1; /*no key up event*/  LastSampleD1 = SampleCnt;} else {/*no key up debounce needed either*/         ;};};
void keyPressedD2 ( void ) {if ((LastSampleD2 + DebounceThreshold) < SampleCnt) {LastButtonD2 = buttonD2; PayLoadPressed("P"); LastSampleD2 = SampleCnt;} else {DeboucnceActive("P", LastSampleD2, SampleCnt);};};
void keyReleasedD2( void ) {if ((LastSampleD2 + DebounceThreshold) < SampleCnt) {LastButtonD2 = buttonD2; PayLoadRelease("p"); LastSampleD2 = SampleCnt;} else {DeboucnceActive("P", LastSampleD2, SampleCnt);};};
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


//-------------------------------------------------------------------------------------------------------
//INIT of the buttons, since toggle switches can be ON at startup
//-------------------------------------------------------------------------------------------------------
void InitButtons(void) {

    if (buttonA1){LastButtonA1 = true;} else {LastButtonA1 = false;};
    if (buttonA2){LastButtonA2 = true;} else {LastButtonA2 = false;};
    if (buttonA3){LastButtonA3 = true;} else {LastButtonA3 = false;};
    if (buttonA4){LastButtonA4 = true;} else {LastButtonA4 = false;};
    if (buttonB1){LastButtonB1 = true;} else {LastButtonB1 = false;};
    if (buttonB2){LastButtonB2 = true;} else {LastButtonB2 = false;};
    if (buttonB3){LastButtonB3 = true;} else {LastButtonB3 = false;};
    if (buttonB4){LastButtonB4 = true;} else {LastButtonB4 = false;};
    if (buttonC1){LastButtonC1 = true;} else {LastButtonC1 = false;};
    if (buttonC2){LastButtonC2 = true;} else {LastButtonC2 = false;};
    if (buttonC3){LastButtonC3 = true;} else {LastButtonC3 = false;};
    if (buttonC4){LastButtonC4 = true;} else {LastButtonC4 = false;};
    if (buttonD1){LastButtonD1 = true;} else {LastButtonD1 = false;};
    if (buttonD2){LastButtonD2 = true;} else {LastButtonD2 = false;};
    
    // Update bank B Leds (Toggle switches)
    ledH1 = buttonB1.read();
    ledH2 = buttonB2.read();
    ledH3 = buttonB3.read();
    ledH4 = buttonB4.read();
    
}

void TimerOverflowRecover (void) {

    //Reset all counters
    SampleCnt = 0;
    LastSampleA1 = 0;
    LastSampleA2 = 0;
    LastSampleA3 = 0;
    LastSampleA4 = 0;
    LastSampleB1 = 0;
    LastSampleB2 = 0;
    LastSampleB3 = 0;
    LastSampleB4 = 0;
    LastSampleC1 = 0;
    LastSampleC2 = 0;
    LastSampleC3 = 0;
    LastSampleC4 = 0;
    LastSampleD1 = 0;
    LastSampleD2 = 0;

}

//-------------------------------------------------------------------------------------------------------
//The key detection routine
//-------------------------------------------------------------------------------------------------------
void DebounceTick() { 

        // XOR only traps 01 and 10         0->1 = pressed                   1->0 = released
        if (buttonA1 ^ LastButtonA1) {if (buttonA1){keyPressedA1();} else {keyReleasedA1();};}; 
        if (buttonA2 ^ LastButtonA2) {if (buttonA2){keyPressedA2();} else {keyReleasedA2();};}; 
        if (buttonA3 ^ LastButtonA3) {if (buttonA3){keyPressedA3();} else {keyReleasedA3();};}; 
        if (buttonA4 ^ LastButtonA4) {if (buttonA4){keyPressedA4();} else {keyReleasedA4();};}; 
        if (buttonB1 ^ LastButtonB1) {if (buttonB1){keyPressedB1();} else {keyReleasedB1();};}; 
        if (buttonB2 ^ LastButtonB2) {if (buttonB2){keyPressedB2();} else {keyReleasedB2();};}; 
        if (buttonB3 ^ LastButtonB3) {if (buttonB3){keyPressedB3();} else {keyReleasedB3();};}; 
        if (buttonB4 ^ LastButtonB4) {if (buttonB4){keyPressedB4();} else {keyReleasedB4();};}; 
        if (buttonC1 ^ LastButtonC1) {if (buttonC1){keyPressedC1();} else {keyReleasedC1();};}; 
        if (buttonC2 ^ LastButtonC2) {if (buttonC2){keyPressedC2();} else {keyReleasedC2();};}; 
        if (buttonC3 ^ LastButtonC3) {if (buttonC3){keyPressedC3();} else {keyReleasedC3();};}; 
        if (buttonC4 ^ LastButtonC4) {if (buttonC4){keyPressedC4();} else {keyReleasedC4();};}; 
        if (buttonD1 ^ LastButtonD1) {if (buttonD1){keyPressedD1();} else {keyReleasedD1();};}; 
        if (buttonD2 ^ LastButtonD2) {if (buttonD2){keyPressedD2();} else {keyReleasedD2();};}; 

        // Update bank B Leds (Toggle switches)
        ledH1 = buttonB1.read();
        ledH2 = buttonB2.read();
        ledH3 = buttonB3.read();
        ledH4 = buttonB4.read();

        SampleCnt ++; 
        
        //Kill Beep
        if (SampleCnt > KillBeepAt) {Beep = OFF;}

        //Overflow protection        
        if (SampleCnt >= 4000000000) {TimerOverflowRecover();};
}



//-------------------------------------------------------------------------------------------------------
// Main - no loop needed because the Sample timer does all the work
//-------------------------------------------------------------------------------------------------------
int main() {
    
    //Init Serial LCD
    lcd.baud(115200);
    lcd.printf("%c", CLS);
    
    InitButtons();
    
    // The timer for debouncing interval: 10 ms sample time
    DebounceTimer.attach(&DebounceTick, SampleInterval); 
        
    //Sound a beep for 500 Ms
    Beep = ON; 
    KillBeepAt = SampleCnt + 50;

    lcd.printf("Ready !!");

}