Theo Ekelmans
/
14_Key_Poller_debounce_DEMO
14 Key poller with debouncing DEMO
Diff: main.cpp
- 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); + + } + + } +}