Letâs be honest: weâve all been there. You start a new project with the best of intentions. âIâll keep my code clean this time,â you lie to yourself. Three days, four sensors, and 1,200 lines of void loop() later, you have a monstrous file of spaghetti code that looks like a cat walked across your keyboard. You try to reuse that cool blinking LED sequence in another project, only to realize itâs hopelessly tangled with your servo control logic. You try to untangle it, accidentally delete a curly brace, and suddenly your Arduino thinks itâs a toaster. The magic blue smoke is practically begging to be released.
Itâs time to stop the madness. Itâs time to learn Object-Oriented Programming (OOP) for Arduino.
In this lesson, weâre going to rescue your sanity by teaching you how to encapsulate your messy code into neat, reusable objects and libraries. By the end, your code will be so clean, you could eat off it (though we still recommend a plate).
The trusty Arduino Uno R3 - a perfect canvas for your new clean code.
When you write procedural code (the default Arduino way), everything lives in one big file. Global variables run wild, and functions step on each otherâs toes.
Object-Oriented Programming allows you to package variables and the functions that use them into a single âObjectâ. Think of an Object like a physical component. If you have an LED, it has a pin number (variable), a state (variable), and actions like turnOn() or blink() (functions).
led1Pin, led2Pin, led3Pin variables cluttering the top of your sketch.void loop() should read like a story, not a phonebook.A Class is the blueprint for an Object. We define it in two parts (usually in separate files when making a true library, but we can do it right in the Arduino IDE for now):
Letâs build a simple Flasher class that blinks an LED without using the dreaded delay() function. (Remember Lesson 156: millis() vs delay()?)
class Flasher {
// Class Member Variables
// These are initialized at startup
int ledPin;
long OnTime;
long OffTime;
// These maintain the current state
int ledState;
unsigned long previousMillis;
public:
// Constructor - creates a Flasher
// and initializes the member variables and state
Flasher(int pin, long on, long off) {
ledPin = pin;
pinMode(ledPin, OUTPUT);
OnTime = on;
OffTime = off;
ledState = LOW;
previousMillis = 0;
}
// Method to update the LED state
void Update() {
// check to see if it's time to change the state of the LED
unsigned long currentMillis = millis();
if((ledState == HIGH) && (currentMillis - previousMillis >= OnTime)) {
ledState = LOW; // Turn it off
previousMillis = currentMillis; // Remember the time
digitalWrite(ledPin, ledState); // Update the actual LED
}
else if ((ledState == LOW) && (currentMillis - previousMillis >= OffTime)) {
ledState = HIGH; // turn it on
previousMillis = currentMillis; // Remember the time
digitalWrite(ledPin, ledState); // Update the actual LED
}
}
};
Now that we have our blueprint, using it in our main sketch is incredibly satisfying.
// Instantiate two Flasher objects, passing in the pin, on-time, and off-time
Flasher led1(12, 100, 400); // Pin 12, On 100ms, Off 400ms
Flasher led2(13, 350, 350); // Pin 13, On 350ms, Off 350ms
void setup() {
// Nothing to do here! The constructor handles pinMode setup.
}
void loop() {
// Our loop is totally clean and non-blocking!
led1.Update();
led2.Update();
}
Look at that void loop(). It brings a tear to the eye. No delay(), no overlapping timer logic. Just two clean, independent objects minding their own business.
To truly write your own library that you can share or easily drop into other projects, you need to split this class into two files:
By placing these in a folder named Flasher inside your Arduino libraries folder, you can simply #include <Flasher.h> in any future project!
If youâre testing multiple components with OOP, youâll need a solid breadboard setup. Donât fry your board because your wires crossed.
Moving to Object-Oriented Programming on Arduino takes a slight mental shift, but once you make the leap, youâll never want to write giant procedural sketches again. Start small, encapsulate your most repetitive code, and soon youâll be writing modular libraries like a pro!
Related reading: Brush up on the basics of non-blocking code in Lesson 156: Battery Super-Saver or check out our Arduino Uno vs. Nano Showdown if you need a smaller board for your new clean code.