constexpr int buttonPin = 2; // the number of the pushbutton pin
// With an UNO the digital pins 0 and 1 are dedicated to Serial
// The digital pins 3, 5, 6, 9, 10 and 11 can be used for PWM
// Therefore usually one would use 2, 4, 7, 8, 12 or 13 for
// pure digital input or output
// variables that will or may change:
byte buttonState; // variable for reading the pushbutton status
byte lastButtonState = 1; // variable that holds the last status read
// Both variables together allow it to check if the button status has changed
// since it was read the last time:
// buttonState gets the actual status in every loop though loop()
// if buttonState and lastButtonState are different,
// we know that the button has changed its state.
// If this is the case we keep the new state in lastButtonState
// and do something (depending on this new state)
// While through all following loops the actual state and lastButtonState
// are the same nothing will happen in this sketch
// setup() is called once before the software enters loop()
void setup() {
// We initialize the Serial communication so that
// the Serial communication is prepared and
// the controller knows which speed (Baud rate) we want for communication
// Let us use a speed rate of 115200 as that is more appropriate for
// "state-of-the-art" computers
Serial.begin(115200);
// buttonPin is set as an input and the internal pulluo resistor is activated
// by INPUT_PULLUP. This means that the input pin is usually HIGH if not
// pulled down to Ground (if open and/or not connected to GND)
// The pull_up resistor has usually several 10 kOhm so that a shortcut to
// GND does not destroy the input port.
// If you do not like the internal pull_up you can of course use an external
// resistor with e.g. 10, 20, 30 kOhm, connect one side to 3.3V or 5V
// depending on the controller you use and the other to the input pin
// then use pinMode(Pin, INPUT); for this pin. Be aware that - if there is
// no pull_up resistor connected - the pin may "float" which leads to arbitrary
// pin states!
pinMode(buttonPin, INPUT_PULLUP);
}
void loop() {
// read the state of the pushbutton value:
buttonState = buttonStatus();
// Now compare the actual value with the one we stored last time
// If they are identical -> skip the next steps
if (buttonState != lastButtonState) {
// We only come to this line if both states are different
// Now we make both values identical again
// so that we get into the if-clause only after another change
lastButtonState = buttonState;
// Now we decide what to do depending on the new state we sensed:
// We use INPUT_PULLUP and a button that "grounds" the pin only
// while it is pressed. This means that HIGH is the pin state
// if the button is not pressed and LOW means it is pressed!
// By our own definition released equals to OFF and
// pressed to ON.
// Why our own definition? Because we could define it vice versa of course
// We can define that a pressed button means OFF and released ON
// e.g. if something shall move all the time and only stop while we press
// the button. It depends on the application ...
if (buttonState == HIGH) {
Serial.println("OFF");
} else {
Serial.println("ON");
}
}
}
// This function reads the actual button state but only changes its output
// if a "new" state is stable for at least 30 msec (hardcoded in this routine).
// The byte in front of the function name tells the compiler to return a byteis le
// which is defined in the line "return state;"
byte buttonStatus() {
// static explains the compiler that these variables shall keep their content
// after the function has been finished. So the next time it is called it
// "remembers" lastChange, state and lastState while actState is newly initialized.
// lastChange keeps the time in msec when the last status change has taken place
static unsigned long lastChange = 0;
// state keeps our "official" state
// lastState keeps the button state detected when at the time of "lastChange"
static byte state = HIGH;
static byte lastState = HIGH;
byte actState = digitalRead(buttonPin);
// if the actual state differs from the lastState
// we keep track of the new value and the time it occured
if (actState != lastState) {
lastChange = millis();
lastState = actState;
}
// if our official state and the new state are different AND
// the new state did not change in the last 30 msec we accept it
// as our new official state
// This way we filter bouncing of the state between HIGH and LOW
if (state != lastState && millis() - lastChange > 30) {
state = lastState;
}
// Here we return the official state
return state;
}