why don't you make your class reusable? handover the pin in the constructor. If you do so - another LED is one line in setup, and one line in loop. That's why one uses OOP - to make things reusable.
make a "begin" member function and call it in setup to set the pinMode.
read again the BlinkWithoutDelay example and check how they use the pattern "millis() timer" correctly.
use camelCase for your member functions (--> use .flash instead of .Flash())
something like
//
// blinks several LEDs in different intervals without using the 'delay' function.
// Written in object orientated style.
//
// Public Domain: Please feel free to use but citation appreciated
// JIT 06/01/23
// applied Arduino style by noiasca
class LED {
protected:
const uint8_t pin;
bool state; // whether the LED is on or off
uint16_t interval = 1000;
uint32_t previousMillis = 0;
public:
LED(uint8_t pin) : pin(pin) {}
void begin()
{
pinMode(pin, OUTPUT);
}
void setInterval(uint16_t interval)
{
this->interval = interval;
}
void blink(unsigned long currentMillis = millis())
{
if (currentMillis - previousMillis > interval) {
previousMillis = currentMillis;
if ( state ) {
digitalWrite(pin, LOW); // turn the LED off by making the voltage LOW
} else
{
digitalWrite(pin, HIGH); // turn the LED on (HIGH is the voltage level)}
}
state = !state;
}
}
};
LED ledA(LED_BUILTIN); // create a LED instance with the built in LED
LED ledB(12);
LED led[] {11, 10}; // create an array of LED with several pins
void setup() {
ledA.begin();
ledB.begin();
ledB.setInterval(500); // modify the default interval
for (auto &i : led) i.begin(); // call begin function for all members of the array led[]
led[0].setInterval(700);
led[1].setInterval(900);
}
void loop() {
uint32_t currentMillis = millis();
ledA.blink(currentMillis);
ledB.blink(currentMillis);
for (auto &i : led) i.blink(currentMillis); // call blink function for all members of the array led[]
}
In fact I discovered I could use classes through reading the library code, and realising if "they" could use classes etc. then so could I since it was all going through the same compiler.
For me "Reference" - the name of the document I refered to - did not imply beginner documents.
why don't you make your class reusable? handover the pin in the constructor. If you do so - a another LED is one line in setup, and one line in loop. That's why one uses OOP - to make things reusable.
It had crossed my mind, but really my objective was really to produce a short piece of code to make sure my understanding of C++ classes (and especially in the Arduino environment) was correct.
I'm working towards a couple of real(ish) applications, which may well be maintained and modified by other people, and the proliferation of global variables to keep track of the states of controlled devices was kind of irritating me. Having used OOP in the past it seemed the right solution.
A couple (hopefully seen as constructive) comments:
about this variable name
if it's a bool I would make it obvious what you mean, for example
bool ledIsOn; // true when the LED is on, false when it's off
and begin() should read that state of the pin and use it to initialise the boolean? (or assumption is setting OUPUT means LOW so false which is the default value as 0 is promoted into false ?)
and I wonder why you pass currentMillis to the blink function at all? is that to share a common time if you blink multiple leds in a row ?
short:
more or less yes, but not to be meant as sync.
long:
That's just my way. Sometimes I find it handy to be able to handover the millis in the update function from the outside. Mostly because a millis() call takes some time. If I have some simple like blinking, flashing, ... imho it's ok that all calls are done with the same millis() timestamp.
Furthermore it makes not so much difference if I would have declared a currentMillis in the member function. But to do that as parameter gives me a) the local variable b) the possibility to hand over the millis, or c) just call the member function blink() without the parameter and let the function call millis() itself...
PS: your other points are valid. I should have renamed all variables. For my defense: My example wasn't meant to be 100% "Tutorial Safe" .
The Arduino example BwD uses ledState... I would reuse that. But I would not mention that it is the output - it is the state. So true/false is imho better, the inverse ! correct and the handling of HIGH or LOW according to the digitalWrite API.
The struct keyword was there in C Language before the advent of C++ whose one of the principle characteristics was to conceive the idea of class keyword. What advantage (s) the class keyword did offer, which promoted C to the status of C++?
it's more for historical reasons that struct evolved into class. Initially there was also this concept of polyglot libraries where you can provide a single header file that declares the same API to programs written in C or C++ language.
The common pattern I've seen is that you use a struct if it's mostly to group various data together and you use a class when you start attaching functions operating on this data or other OOP concepts like inheritance.
With one exception class and struct are the same thing in C++. That exception is that the default access specifier for struct is 'public' while for class it's 'private'. THAT'S IT.
i wouldn't be surprised that there is a very good reason for making this distinction, but more willing to believe early versions of an improved C didn't have the class keyword and hence this is needed for backward compatibility with those very early versions
i can also believe, an organizations coding style guidelines would not allow the use of struct with inheritance.