/*
fade PWM pins
Example for HP http://werner.rothschopf.net/microcontroller/202304_millis_dimmer_fading_led.htm
inspired by https://forum.arduino.cc/t/1-button-1-led-fade/1113139/4 (code in forum)
2023-04-10 by noiasca
*/
// a class for one button, one LED, one Relay
class Dimmer {
const uint8_t buttonPin; // the input GPIO, active LOW
const uint8_t ledPin; // the output GPIO, active HIGH, must be a PWM pin
uint8_t brightness = 0; // current PWM for output pin
uint32_t previousMillis = 0; // time management
enum State {
IDLE, // wait for button press
DIMMUP, // push and hold button results in fade in (stop at max)
HOLD, // stay in setted brightness
DIMMDOWN // press button second time results in fade out (stop at light off)
} state;
const uint8_t intervalUp = 50; // up interval / debounce button
const uint8_t intervalDown = 10;
public:
Dimmer(uint8_t buttonPin, uint8_t ledPin) : buttonPin{buttonPin}, ledPin{ledPin}
{}
void begin() { // to be called in setup()
pinMode(buttonPin, INPUT_PULLUP);
pinMode(ledPin, OUTPUT);
}
// just a function to print debug information to Serial
void debug() {
Serial.print(ledPin); Serial.print(F("\t")); Serial.print(state); Serial.print(F("\t")); Serial.println(brightness);
}
void update(uint32_t currentMillis = millis()) { // to be called in loop()
uint8_t buttonState = digitalRead(buttonPin);
switch (state) {
case State::IDLE :
if (buttonState == LOW) {
previousMillis = currentMillis;
brightness = 1;
analogWrite(ledPin, brightness);
debug();
state = State::DIMMUP; // switch to next state
}
break;
case State::DIMMUP :
if (currentMillis - previousMillis > intervalUp) {
if (buttonState == LOW) {
previousMillis = currentMillis;
if (brightness < 255) brightness++; // increase if possible
debug();
analogWrite(ledPin, brightness);
}
else {
state = State::HOLD; // button isn't pressed any more - goto to next state
}
}
break;
case State::HOLD :
if (currentMillis - previousMillis > intervalDown) {
if (buttonState == LOW) {
previousMillis = currentMillis;
if (brightness > 0) brightness--; // decrease if possible
analogWrite(ledPin, brightness);
debug();
state = DIMMDOWN; // goto next state
}
}
break;
case State::DIMMDOWN :
if (currentMillis - previousMillis > intervalDown) {
previousMillis = currentMillis;
if (brightness > 0) brightness--;
analogWrite(ledPin, brightness);
debug();
//if (brightness == 0) state = State::IDLE; // go back to IDLE
if (brightness == 0 && buttonState != LOW) state = State::IDLE; // go back to IDLE - alternative if you don't want to restart in case button is still pressed.
}
break;
}
}
};
//create instances (each with one button and one led/LED)
Dimmer dimmer[] {
{A0, 3}, // buttonPin, ledPin
{A1, 5},
{A2, 6},
};
void setup() {
Serial.begin(115200);
for (auto &i : dimmer) i.begin(); // call begin for all instances
}
void loop() {
for (auto &i : dimmer) i.update(); // call update() for all instances
}