Microcontroller Programming
ü Timing
ü Object-oriented programming
Timing
The delay() problem
Arduino sketches are usually programmed so that the code is
executed line by line. For timings we have so far used the
delay() function, i.e. explicitly halting the program. During a
delay, the microprocessor does not accept any commands except
for interrupts. Thus, while the code is in a delay(), no sensors
can be read and no actuators can be controlled. Additionally,
running code with tasks that have different timings using
delay()is difficult.
Imagine the following setup:
The LEDs on the right should blink with a different rhythm. The
red LED should toggle every 400ms, the green LED every 750ms.
That is impossible to code using delay().
Dr. Jörn Kretschmer Faculty MME
Timing
Timing using the internal clock
The millis() function can be used to receive the time in
Milliseconds since the ARDUINO program started. Thus, instead
of using delay() we can time tasks by retrieving the current
system time through millis() in every loop() iteration (so-
called polling) and check if enough time has passed for the next
task to begin (here: toggle the LED). That way, the processor is
free to do other tasks while we wait for the right time to toggle
the LED.
The variables currentMillis and previousMillis
contain the current system time and the system time when the
LED was last toggled, respectively. In every loop() iteration
currentMillis is updated by retrieving the current time
through millis(). If enough time has passed,
previousMillis is updated with the current system time
and the waiting for the next time to toggle the LED begins.
Arduino code see 2LED_Blink_millis.ino
Dr. Jörn Kretschmer Faculty MME
Object-oriented programming
Reducing code redundancies
The code shown in the previous example can be extended to
work with more LEDs. We simply need to copy and paste the
timing query and the corresponding variables and adjust the
variable names. Repeating that copy and paste for a lot of LEDs
however is error-prone and the code would be unreadable at
some point.
A solution would be to introduce a function that uses pointers to
the time variables as inputs, much like what you we did in
chapter 8. This would still require to create multiple variables for
each LED denoting the pin, the toggling frequency and the
timings.
Thus, it is better to introduce an LED class that can be used to
create as much LED objects as needed.
Dr. Jörn Kretschmer Faculty MME
Object-oriented programming (OOP)
Classes
Object-oriented programming is a programming paradigm that is organized around objects rather than
functions. An object can be defined as a data field that has unique attributes and behavior. Objects contain
data in the form of attributes and code in the form of methods.
The most popular OOP languages use classes that act as a form of blueprint for the objects. Objects are
instances of a class, thus each object of the same class has the same methods and attributes, but differs
from the other objects by their attribute values.
Class
Attributes Human
Height
Weight Methods
Age Eat
Name Sleep
Talk
Walk
Dr. Jörn Kretschmer Faculty MME
Object-oriented programming (OOP)
Classes
Object-oriented programming is a programming paradigm that is organized around objects rather than
functions. An object can be defined as a data field that has unique attributes and behavior. Objects contain
data in the form of attributes and code in the form of methods.
The most popular OOP languages use classes that act as a form of blueprint for the objects. Objects are
instances of a class, thus each object of the same class has the same methods and attributes, but differs
from the other objects by their attribute values.
Name
Attributes person1
Height: 180cm
Weight: 70kg Methods
Age: 30 Eat
Name: John Sleep
Talk
Walk
Dr. Jörn Kretschmer Faculty MME
Object-oriented programming (OOP)
Classes - Attributes
To define a class in C++, we need to use class and the name of the class we want to define. The class
definition is surrounded with { }-brackets.
First we define the attributes or member variables:
class LED //The LED class
{ //!This bracket ends after the class definition!
//Member variables. i.e. attributes
int pin; //The pin the LED is connected to
long interval; //The toggle interval
//The system time at which the LED was last toggled.
unsigned long previousMillis;
Dr. Jörn Kretschmer Faculty MME
Object-oriented programming (OOP)
Classes - Constructor
To be able to create an instance (i.e. object) of a class, we need to define a so-called constructor.
Constructors can have inputs that allow the programmer to define attribute values when the object is
created. Public defines that the constructor can be called from outside of the class.
public:
LED(int pinP,long intervalP){ //The required parameters to create a
//new object of class LED
//Allocation and initialization of variables
pin = pinP;
interval = intervalP;
previousMillis = 0;
}
Dr. Jörn Kretschmer Faculty MME
Object-oriented programming (OOP)
Classes - Methods
Finally, we need to define the functions (called methods) that all objects of this class inherit. A class can
contain multiple methods. Below, we define two methods, one, begin(), to do the hardware
configuration of the LED pin and the other, blink(), to handle the polling and toggling of the LED.
void begin() {
pinMode(pin,OUTPUT);
}
void blink() {
unsigned long currentMillis = millis();
if(currentMillis - previousMillis >= interval){
previousMillis = currentMillis;
digitalWrite(pin, !digitalRead(pin));
}
}
}; //This is the bracket that closes the class
Dr. Jörn Kretschmer Faculty MME
Object-oriented programming (OOP)
Classes – Creating instances of a class
To create an instance or object of a class, we need to call the
constructor. If the object should be accessible globally, we create the
object before the setup() routine.
To create an LED object, we call the LED constructor and provide the
values for the pin and the toggle interval. To create three instances
that represent the LEDs on the diagram on the right with toggle
intervals of 400, 750 and 200ms, respectively, we use the following
code:
LED led1(2,400);
LED led2(3,750);
LED led3(1,200);
Dr. Jörn Kretschmer Faculty MME
Object-oriented programming (OOP)
Calling methods of an object
Finally, in the setup() routine, we call the begin() method
and in the loop() routine, we call the blink() method for
each LED object using the dot-operator:
void setup() {
[Link]();
[Link]();
[Link]();
}
Arduino code see
void loop() 3LED_Blink_OOP.ino
{
[Link]();
[Link]();
[Link]();
}
Dr. Jörn Kretschmer Faculty MME
Object-oriented programming (OOP)
Using multiple classes
A sketch can contain multiple classes. In
this example we add a Servomotor
class to the already existing LED class.
Using the Servomotor class we can run
multiple servos at different turn rates.
Arduino code see
3LED_2Servo_OOP.ino
Dr. Jörn Kretschmer Faculty MME
Creating a library
The header and source file
Now that we have created classes for the LEDs and the Servos, it would be even better to create a library
from those classes. That allows us or other users to use the code in different projects without having to
implement the whole class code into every program.
To create a new library, we need to create two files: the header file and the source file of our class. The
header file contains a definition of our class, while the source file contains the actual code that we have
written previously.
In both files, we need to make sure to use
#include "Arduino.h"
to include the standard ARDUINO command library, that comprises functions like digitalWrite(),
pinMode() etc. In normal sketches, the compiler includes that library automatically, however, it will not
include it in the header and the source file we are about to create.
Dr. Jörn Kretschmer Faculty MME
Creating a library
The header file
The header file in a library defines the class with all its attributes, methods and constructors. Thus a header
file for an LED library would look like this:
#include "Arduino.h"
class LED{
public: //public methods and attributes can be accessed
//from outside the class
LED(byte _pin, int _interval);
void begin();
void blink();
private: //private methods and attributes can only be accessed from within the
//class, this is usually done for all attributes.
byte _pin; //Naming convention for private attributes is _NAME
int _interval;
unsigned long _previousMillis
};
Dr. Jörn Kretschmer Faculty MME
Creating a library
The header file
Finally, we sorround the header file code with:
#ifndef LED_h
#define LED_h
... //the code shown in the previous slide
#endif
to make sure that the user can include the library only once in a program.
The header file then has to be saved as a .h file.
Dr. Jörn Kretschmer Faculty MME
Creating a library
The source file
The source file we need to include both the Arduino.h and the newly created LED.h. The rest of the code is
the same as in the LED class, we created before, with the exceptions, that the attributes are now private
with a preceeding _ and that each constructor and method has a preceeding LED:: that defines that they are
part of the LED class.
Thus, the constructor looks like this:
//The constructor
LED::LED(byte pin,int interval){ //The required parameters to create a
//new object of class LED
//Allocation and initialization of variables
_pin = pin;
_interval = interval;
_previousMillis = 0;
}
Dr. Jörn Kretschmer Faculty MME
Creating a library
The source file
The methods are written similarly:
//The method to configure the pin as an output
void LED::begin(){
pinMode(_pin,OUTPUT);
}
//The method to check if enough time has passed for toggling the LED
void LED::blink() {
unsigned long currentMillis = millis();
if(currentMillis - _previousMillis >= _interval){
_previousMillis = currentMillis;
digitalWrite(_pin, !digitalRead(_pin));
}
}
The source file must then be saved as a .cpp file (the C++ data type).
Dr. Jörn Kretschmer Faculty MME
Creating a library
The source file
Finally, to ensure that the methods and the class name itself are recognized as keywords (with the respective
coloring), we can add a [Link] file containing the following:
LED KEYWORD1
begin KEYWORD2
blink KEYWORD2
It is important that there a no spaces, just tabs to separate the words. KEYWORD1 is used for classes, while
KEYWORD2 is used for functions.
To form a new library, we need to place all three files (the header file, the source file and the keywords file)
in a folder with the name of the class. The folder can then be converted into a zip-file and installed through
Sketch → Include Library → Add .ZIP Library
Library and updated LED program
using the new library see
LED_w_library folder
Dr. Jörn Kretschmer Faculty MME
Object-oriented programming
Homework
Create a class to read in a button to toggle an LED. Before
writing the class, plan which attributes and methods are
required for the button class. Turning the class into a
library is optional.
Dr. Jörn Kretschmer Faculty MME