Modern C++ on Arduino
August 03, 2021 -Embedded programming is always different with regular high-level programming with humanlike APIs--they tend to be closer to the metal, and less easy for humans to read.
However, recent developments of the C++ has some convenient features which you can use with Arduino--one of the most popular embedded system platform--and its API are quite in higher level than C or Assembly, and oftentimes use dynamic memory allocations, so it is not very good for critical applications like healthcare devices or aviations.
But it still can be used for many, many applications other than healthcare devices or aviations, such as the field of Internet of Things, CNC machines, smart farming, smart trackers, etc etc.
With other high level tools like MicroPython, Go for Embedded, and Embedded Rust on the rise, and more powerful microcontrollers like ESP8266, ESP32-S2 and ESP32-C3 which offers many, many hardware resources (like 160MHz clock and 512KB-ish SRAM), people are becoming less afraid of using dynamic memory allocations in a microcontroller.
Let's just jump into the ride and see what the modern C++ has to offer!
Content below are still WIP
The auto
keyword
String newString = String();
auto newString = String();
auto myInt = 1;
auto myFloat = 3.30;
auto str = "Hello" + ", world!";
Lambda function and closure
void setup() {
auto inScope = "I am still in scope.";
auto func = [&inScope](String& text, int arg) {
Serial.println(
"Hello, " +
text +
"!, I have " +
arg +
" apples."
);
Serial.println(inScope);
inScope += " yay!";
return inScope;
};
auto res = func("world", 5);
Serial.println(res);
}
String func(String& inScope, String& text, int arg) {
Serial.println(
"Hello, " +
text +
"!, I have " +
arg +
"apples."
);
Serial.println(inScope);
inScope += " yay!";
}
void setup() {
auto inScope = "I am still in scope.";
func(inScope, "world", 5);
Serial.println(inScope);
}
String reference
void (String& builder) {
builder += "string ";
builder += "to ";
builder += "build.";
}
foreach
loop
auto contents = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
foreach (auto item : contents) {
Serial.println(item);
}
Class, Enum class, and Template
enum class StepperDirection {
CLOCKWISE,
COUNTERCLOCKWISE
}
class Stepper {
public:
Stepper(int pinA, int pinB) {
}
void move(StepperDirection direction, int steps) {
switch (direction) {
case StepperDirection::CLOCKWISE:
// Toggle digital pins to move stepper clockwise here for n steps
break;
case StepperDirection::COUNTERCLOCKWISE:
// Toggle digital pins to move stepper counterclockwise here for n steps
break;
}
}
};
void setup() {
Stepper stepper(PIN_A, PIN_B);
stepper.move(StepperDirection::CLOCKWISE, 500);
stepper.move(StepperDirection::COUNTERCLOCKWISE, 200);
}
Example refactors
See how using modern C++ tidies up your code:
From this:
digitalWrite(1, LOW);
delay(500);
digitalWrite(1, HIGH);
delay(500);
digitalWrite(2, LOW);
delay(500);
digitalWrite(2, HIGH);
delay(500);
To this
auto pins = {1, 2};
foreach (auto pin : pins) {
// Turn LED on
digitalWrite(pin, HIGH);
delay(500);
// Turn LED off
digitalWrite(pin, LOW);
delay(500);
}