/* BounceEMA2 program to test exponential moving average debouncer J L Errington skillbank.co.uk Large chunks copied from Thomas O Fredericks Bounce2.h & Bounce2.cpp for compatibility & some not used here Button down & released allows program to run once. REMEMBER to start serial monitor before running program The circuit: - LED attached from pin 9 to Vcc via resistor - button attached to pin 2 from ground - pin3 "switchpin" attached to pin 9 to simulate switch bounce signal. */ // constants won't change. They're used here to set pin numbers: const int goPin = 2; // the start - stop test switch const int switchPin = 3; // switch under test const int ledPin = 9; // the go / stop LED pin //values for flag bits in variable "state" static const uint8_t DEBOUNCED_STATE = 0b00000001; static const uint8_t UNSTABLE_STATE = 0b00000010; static const uint8_t CHANGED_STATE = 0b00000100; //values for hysteresis thresholds const uint8_t upper = 77; //128*0.6 const uint8_t lower = 51; //128*0.4 //variables byte count; //index values from test array uint8_t temp; //to receive switch reading value to be shifted bool test[] = {1,1,1,1,1,0,1,0,0,0,1,0,0,0,0,0,1,0,0,1,1,1,1,1}; //24 values to simulate switch bounce uint8_t threshold; //upper or lower bound int OldEMA, EMA; //protected : //can only be accessed from within the class unsigned long previous_millis; uint16_t interval_millis; uint8_t state; uint8_t pin; unsigned long stateChangeLastTime; unsigned long durationOfPreviousState; //FUNCTION PROTOTYPES FOLLOW - not all used void attach(int pin, int mode); //Attach to a pin and set mode (INPUT, INPUT_PULLUP or OUTPUT). //void attach(int pin); //Only if pin mode already set up void interval(uint16_t interval_millis); // Sets the debounce interval in msec bool update(int pin); // Updates the pin's state. //bool read(); //Returns the pin's state (HIGH or LOW). //bool fell(); //Returns true if pin signal transitions from high to low. //bool rose(); //Returns true if pin signal transitions from low to high //unsigned long duration(); //Returns duration in msec of the current state //unsigned long previousDuration(); //Returns duration in msec of previous state. //bool readCurrentState() { return digitalRead(pin); } //void setPinMode(int pin, int mode) { pinMode(pin, mode);} void printValues(); inline void changeState(); // Declared in .cpp file inline void setStateFlag(const uint8_t flag) {state |= flag;} inline void unsetStateFlag(const uint8_t flag) {state &= ~flag;} inline void toggleStateFlag(const uint8_t flag) {state ^= flag;} inline bool getStateFlag(const uint8_t flag) {return((state & flag) != 0);} bool changed( ) { return getStateFlag(CHANGED_STATE); } void setup() { //Initiate Serial communication for testing. Serial.begin(9600); while (!Serial) ; //wait for serial stream to open pinMode(ledPin, OUTPUT); // initialize the LED pin as an output: digitalWrite(ledPin, HIGH); // turn LED off, test input = HIGH: pinMode(goPin, INPUT_PULLUP); // initialize the go button as an input with pullup: attach(switchPin, INPUT_PULLUP); // use pin 3 for test input, & set states while(digitalRead(goPin)==1){}; //wait for button to start temp = getStateFlag(UNSTABLE_STATE); //set during attach if(temp)threshold=lower;else threshold=upper;//pre-set the threhold OldEMA = temp <<7; //multiply by 128 to get better resolution EMA=OldEMA; //print header row Serial.println("Bit ,Switch,, EMA , threshold , Debounced State ,"); count=-1; //print values as csv printValues(); } void loop() { for (count = 0; count<24; count++){ digitalWrite(ledPin,test[count]); //send next bit to LED & simulated switch input bool qchanged = update(switchPin); temp = getStateFlag(UNSTABLE_STATE); //reflects "switch" value EMA = (OldEMA>>1) + (OldEMA>>2) + (temp<<5); //EMA = OLDEMA/2 + OldEMA/4 + new value*128/4 if(getStateFlag(DEBOUNCED_STATE))threshold=lower;else threshold=upper; //apply hysteresis if (EMA>threshold){setStateFlag(DEBOUNCED_STATE);}else {unsetStateFlag(DEBOUNCED_STATE);} //update state //print current conditions printValues(); OldEMA = EMA; //ready for next reading delay(200); if(count==23) { while(digitalRead(goPin)==1){}; } //wait to go again } //for loop } void printValues() { //print all current values as csv string Serial.print(count); Serial.print(","); Serial.print(getStateFlag(UNSTABLE_STATE)); Serial.print(", ,"); Serial.print(EMA); Serial.print(","); Serial.print(threshold); Serial.print(","); Serial.println(getStateFlag(DEBOUNCED_STATE)); } void attach(int pin, int mode) //set mode & attach pin { pinMode(pin, mode); state = 0x80; //clear all state flags – changed, unstable, debounced LEAVE MSB at 1 to force Bin printing for test if (digitalRead(pin)) { setStateFlag(DEBOUNCED_STATE | UNSTABLE_STATE); } previous_millis = millis(); } bool update(int pin) { unsetStateFlag(CHANGED_STATE); bool currentState = digitalRead(pin); // Read the state of the switch in a temporary variable. if ( currentState != getStateFlag(UNSTABLE_STATE) ) // If the switch value has changed reset the timer { durationOfPreviousState = millis() - stateChangeLastTime; stateChangeLastTime = millis(); //record time of this changeprevious_millis = millis(); toggleStateFlag(UNSTABLE_STATE); //change UNSTABLE_STATE to match switch reading setStateFlag(CHANGED_STATE); } return changed(); }