/*
Arduino Forum
Topics: Multi Button Programming
Link: https://forum.arduino.cc/t/multi-button-programming/1094488
Variant: keep track of runtime for each Output
Sketch: sketch.ino
Created: 2023-03-02
delete: 2023-05
Author: noiasca
*/
const uint8_t b1 {A2}; // Button
const uint8_t b2 {A1}; // Button
const uint8_t b3 {A0}; // Button
const uint8_t r1 {12}; // Output relay
const uint8_t r2 {11}; // Output relay
const uint8_t r3 {10}; // Output relay
const uint8_t commonStatePin {9}; // Output relay
// a class for one LED one button
class Indicator {
const uint8_t buttonPin; // the input GPIO, active LOW
const uint8_t relayPin; // the output GPIO, active HIGH
uint8_t state = 0; // switched off or on
uint32_t runtimeMillis = 0; // timestamp of last update of counterTotal
uint32_t runtimeTotal = 0; // current total running time
public:
static constexpr uint8_t noPin = 255; // dummy value for "no button is pressed"
Indicator(uint8_t buttonPin, uint8_t relayPin) : buttonPin{buttonPin}, relayPin{relayPin}
{}
// call in setup()
void begin() {
pinMode(buttonPin, INPUT_PULLUP);
pinMode(relayPin, OUTPUT);
}
// if running, add the current open time to the totalTime
void addTime() {
uint32_t currentMillis = millis();
if (state == 1) {
runtimeTotal = runtimeTotal + (currentMillis - runtimeMillis)/1000; // add passed time till now
runtimeMillis = currentMillis;
}
}
// return the total runtime
uint32_t getRuntimeTotal() {
addTime();
return runtimeTotal;
}
// to be called in loop.
// returns the buttonPin if active or the value of noPin if inactive
uint8_t update(uint32_t currentMillis = millis()) {
uint8_t lastActive = noPin;
uint8_t buttonState = digitalRead(buttonPin);
if (state == 0) {
if (buttonState == LOW) {
state = 1;
digitalWrite(relayPin, HIGH);
runtimeMillis = currentMillis; // start the runtime counter
lastActive = buttonPin;
}
}
else {
if (buttonState == HIGH) {
state = 0;
addTime(); // call before a switch off
digitalWrite(relayPin, LOW);
//lastActive = noPin;
}
else
lastActive = buttonPin;
}
return lastActive; // returns the button GPIO if it is pressed
}
};
//create 3 indicators (each with one button and one relay/LED)
Indicator indicator[] {
{b1, r1},
{b2, r2},
{b3, r3},
};
// print the runtimes to Serial Monitor (just for debugging)
void showInfo(uint32_t currentMillis = millis()) {
static uint32_t previousMillis = 0;
if (currentMillis - previousMillis > 1000) {
previousMillis = currentMillis;
for (auto &i : indicator) {
Serial.print(i.getRuntimeTotal());
Serial.print("\t");
}
Serial.println();
}
}
void setup() {
Serial.begin(115200);
for (auto &i : indicator) i.begin();
pinMode(commonStatePin, OUTPUT);
}
void loop() {
bool commonState = HIGH;
for (auto &i : indicator) if (i.update() != Indicator::noPin) commonState = LOW; // if one button reports active, common Relay has to be switched off
digitalWrite(commonStatePin, commonState);
showInfo();
}