Arduino Object-oriented

It has been more than a decade, that I switched over to programming in C# and even longer I am developing object-oriented code. But when it comes to Arduino, I can not count on C#. (Actually, there is an Arduino-like microcontroller, which can be programmed with C#. It is called Netduino) But we can still produce object-oriented code with Arduino.

Let’s first have a look at a simple Blink-App (from the Arduino tutorial).

// the setup function runs once when you press reset or power the board
void setup() {
// initialize digital pin LED_BUILTIN as an output.
pinMode(LED_BUILTIN, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second
}

As you can see, there are two standard functions, that get called, when the code is deployed on the device. setup() when the device starts, and loop(), which is something like a while(true)-loop after the setup finished. The code does that, what it is meant to do, make a LED blink every second. But let’s assume we have a button, that shall turn the blinking on and off. My OOP-brain always keeps saying:

“There should be a LED-object and a Button-object”

I can imagine, that there are other solutions, but that was the first thing, that comes in mind when I think about it. So let’s draw something…

uml-buttonblinky.png

When we now come to the point to include those objects in the Standard setup-loop-pattern, we also need a loop and setup-function in each of the classes. These could be called from the main functions.

Here comes the code:

enum SwitchState
{
On,
Off
};
//---------- Light
class Light
{
SwitchState _currentState = Off;
byte _pin;

public:
Light(byte pin)
{
_pin = pin;
}
SwitchState GetCurrentState()
{
return _currentState;
}
// turns on the light
void TurnOn()
{
_currentState = On;
}

// turns off the light
void TurnOff()
{
_currentState = Off;
}

void Setup()
{
pinMode(_pin, OUTPUT);
}

void Loop()
{
if (_currentState == On)
{
digitalWrite(_pin, HIGH);
}
else
{
digitalWrite(_pin, LOW);
}
}
};
//---------- Button
class Button
{
SwitchState _currentState = Off;
byte _pin;

void OnSwitchChanged()
{
SwitchChangedEvent();
}

public:
void(* SwitchChangedEvent)();

Button(byte pin)
{
_pin = pin;
}

SwitchState GetCurrentState()
{
return _currentState;
}

void Setup()
{
pinMode(_pin, INPUT);
}

void Loop()
{
byte val = digitalRead(_pin);
if (val == HIGH && _currentState == Off)
{
_currentState = On;
OnSwitchChanged();
}
else if (val == LOW && _currentState == On)
{
_currentState = Off;
OnSwitchChanged();
}
}
};

//-------------------------- MAIN
Light led1(1);
Button button1(2);

void InvertLight()
{
if (led1.GetCurrentState()==Off)
{
led1.TurnOn();
}
else
{
led1.TurnOff();
}
}

void setup() {
led1.Setup();
button1.Setup();
button1.SwitchChangedEvent = InvertLight;
}

void loop() {
led1.Loop();
button1.Loop();
}

From this starting point, you can do a lot of fancy stuff. First of all, you could implement a base class, to actually wrap up those functions, that tend to produce code doubles. Also you may not want to trigger (and write) the digital pins on every loop. You can simply introduce something like a timestamp, skipping the loop for an amount of time. Everything can be made in a base class, so there will be no need to implement it every time again.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.