While this question/observation arose from a specific program (though single and first occasion), I'd like to discuss this at a more generic level (if at all possible). While I have been coding for a while, I am new to writing classes. Hence, I am a procedural rather than object-oriented guy. ![]()
The trigger:
I refactored a program I wrote two years ago over the last three days, adding my first ever written classes (one for controlling relays, another for LEDs).
Background:
The overall scenario is controlling a garage with three bays, each having a roller door and ceiling lights, thus have three boxes with four push buttons, one at each pillar next to a roller door.
_______ _______ _______
| | :: | | :: | | ::*
| | 1 | | 2 | | 3
Button arrangement :: (dots representing push buttons)
1 3 (light)
2 4 (roller door)
* (the two extra buttons at box 3, switch two other lights, so disregard these for the time being)
Box 1 and 2 can switch the bay to the left and right.
My initial program basically had push buttons sending a individual voltages to an analogue pin. The program would allocate a sequential button number:
Box 1 switch 1..4, to a button id of 1..4
Box 2 switch 1..4, to a button id of 5..8
Box 3 switch 1..4, to a button id of 9..12
And we end up with:
1 | 2 | 3 | Box
1 3 | 5 7 | 9 11 | light
2 4 | 6 8 | 10 12 | roller door
A switch statement would trigger the respective relay for a roller door or light.
case 1 -> light 1 ON
case 3, 5 -> light 2 ON
case 7, 9 -> light 3 ON
... roller doors accordingly...
Without complicating this further...
I had (in the non-class code) two functions switching the individual (light and roller door) relays ON or OFF via their button_id.
Because I am communicating the relay states to an automation system, which can also control the relays, the sequential number was ideal to track the relay state with bit setting and bit reading operations (A byte for lights, another for roller doors).
The MQTT message structure is [R|L][1..4][0|1]; e.g., L11 for light 1 ON.
If you could follow so far (better than 1,500 lines of code
) this seems straight forward.
Now... I replaced the relays for both lights and roller doors with a Relay class.
class Relay
{
public: // called access modifier
// Constructor
Relay(uint8_t pin_relay);
Relay() {}; // do not use
// member methods
// Normally a relay is set HIGH for it to be ON, and LOW for OFF
// SaintSmart branded relay boards work the opposite: HIGH = OFF
void init(bool default_low_for_off);
void on();
void off();
void toggle();
// Setter
void setState(bool desired_state);
// Getter
bool getState();
private: // called access modifier
uint8_t m_pin_relay;
bool m_default_low_for_off;
bool m_state;
};
I have instantiated these relays like so:
Relay relay_rollerdoor_south(PIN_ROLLERDOOR_SOUTH);
Relay relay_rollerdoor_centre(PIN_ROLLERDOOR_CENTRE);
Relay relay_rollerdoor_north(PIN_ROLLERDOOR_NORTH);
Relay relay_lights_south(PIN_LIGHTS_SOUTH);
Relay relay_lights_centre(PIN_LIGHTS_CENTRE);
Relay relay_lights_north(PIN_LIGHTS_NORTH);
Relay relay_lights_external_1(PIN_LIGHTS_EXTERNAL_1);
Relay relay_lights_external_2(PIN_LIGHTS_EXTERNAL_2);
Roller door relays are also treated differently than light relays, because lights are truly ON|OFF, while roller doors only need a momentary signal to toggle UP|DOWN. For the latter an auto OFF is sent to the relay 400 ms after it received an ON.
The difference in code is now (top with classes, bottom old code no classes)
20240723-2356 v0.2.0 w/o DEBUG
RAM: [= ] 11.8% (used 970 bytes from 8192 bytes)
Flash: [= ] 10.8% (used 27422 bytes from 253952 bytes)
20240720-0900 v0.1.3 w/o DEBUG
RAM: [= ] 11.1% (used 913 bytes from 8192 bytes)
Flash: [= ] 10.4% (used 26412 bytes from 253952 bytes)
While I could squeeze the bottom (non-class code) into an UNO, the upper has to go to a MEGA.
Now, I am not sure, whether the information provided can lead to the confirmation that classes require more flash or not.
But as a more generic question: Have experienced programmers seen something similar? (... that the use of classes can increase the flash memory requirement significantly.)
I usually try to avoid strings, and use F(), and the smallest size variable to actively save memory and squeeze the most into the UNO.
Any hints/commentary appreciated.