14 Key poller with debouncing DEMO

Dependencies:   mbed

Revision:
0:acabda48796c
Child:
1:6ee2362ce0fd
diff -r 000000000000 -r acabda48796c main.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Sat Jan 07 00:17:15 2012 +0000
@@ -0,0 +1,322 @@
+/* -----------------------------------------------------------------------
+   14 Key poller and debounce demo by Theo Ekelmans, Version 1.0
+   -----------------------------------------------------------------------
+   
+   In this demo, banks A, C and D are push buttons, bank B are toggle switches that have a LED inside
+   
+   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 
+   
+   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 ;)
+   
+   2: The USB COM port / VT100 terminal session hangs somtimes when you are bashing buttons like a madman, 
+      the LCD however is rock solid.
+   
+ */
+
+#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 PollCount1 = 0;
+unsigned long PollCount2 = 0;
+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, %ld bounces\r\nKey + %s @ %ld\r\n                    ", 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(), PollCount2, 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, %ld bounces\r\nKey - %s @ %ld\r\n                    ", 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(), PollCount2, 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, %ld bounces\r\nKey - %s @ %ld\r\n%s bounced %ld x    ", 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(), PollCount2, 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 (C4 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
+    PollCount2 = 0;
+    PollCount1 = 0;
+    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 loop
+//-------------------------------------------------------------------------------------------------------
+int main() {
+    
+    //Init Serial LCD
+    lcd.baud(115200);
+    lcd.printf("%c", CLS);
+
+    //Init USB COM port for VT100       
+    usbUART.baud(115200);
+
+    //VT100 clear screen (ESC[2J) , move cursor (ESC[1;1H) to Row 1, Col 1
+    usbUART.printf("%c[2J%c[1;1H", ESC , ESC );
+    
+    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;
+
+
+    PollCount1 = 0;
+    while (1) {
+
+        PollCount1 ++;
+       
+        //Update terminal every 500000'th pass
+        if ( PollCount1 % 500000 == 0 ) {
+        
+            PollCount1 = 0;
+            PollCount2 ++;
+           
+            //Send to VT100 terminal emulator on the PC USB COM port
+            //And because i think scrolling screens are annoying, i added cursor control codes below
+            //VT100 move cursor (ESC[1;1H) to Row 1, Col 1
+            usbUART.printf("%c[1;1H", ESC );
+            usbUART.printf("A%i%i%i%i ",buttonA1.read(),buttonA2.read(),buttonA3.read(),buttonA4.read());
+            usbUART.printf("B%i%i%i%i ",buttonB1.read(),buttonB2.read(),buttonB3.read(),buttonB4.read());
+            usbUART.printf("C%i%i%i%i ",buttonC1.read(),buttonC2.read(),buttonC3.read(),buttonC4.read());
+            usbUART.printf("D%i%i @ %ld, %ld bounces",buttonD1.read(),buttonD2.read(), PollCount2, DebounceActivationCounter);
+
+        }
+        
+    }
+}