Programmers coming to Arduino from a background in programming large systems often cite the lack of multithreading and concurrency in Arduino as a deficiency. In this chapter, I’ll try to set the record straight and show you how to embrace the single-thread model of embedded systems.
Arduino has attracted many enthusiasts, including me, who have spent years in the software industry and are used to teams of dozens of people contributing to a huge software effort, with all the related problems of managing the ensuing complexity. For us, the ability to write a few lines of code and have something interesting and physical happen almost immediately, without large amounts of engineering, is the perfect antidote to big software.
It does, however, mean that we often look for things in Arduino that we are used to seeing in our day jobs. When moving from the big development world to the miniature world of Arduino, one of the first adjustments we need to make is to the very simplicity of writing for Arduino. To develop a large system without the benefit of Test Driven Development, version control, and some kind of agile process to follow is reckless. On the other hand, a large Arduino project may be only 200 lines of code written by one person. If that person is an experienced software developer, he or she can simply keep the details in mind without needing any of the usual accoutrements of development.
So stop fretting about version control, design patterns, writing unit tests, and having a refactoring IDE and just embrace the joyous simplicity of Arduino.
If you are old enough to have programmed home computers in BASIC, then you remember that “doing one thing at a time” is simply how computers operate. In BASIC, if a game required a number of sprites to be moved apparently simultaneously, then you had to be smart and include a main loop that moved each sprite a little bit.
This mindset is a good one to have for Arduino programming. Rather than multiple threads each being responsible for one of the sprites, a single execution thread does a little bit of everything in turn, without “blocking” on any one thing.
Aside from multicore computers, essentially a computer only genuinely does one thing at once. The rest of the time, the operating system switches the processor’s attention among the numerous processes running on the computer. On the Arduino, with a limited need to do more than one thing at a time, you can code it yourself, as there is no operating system.
It is no accident that the two functions you must write for any sketch are setup and loop. The fact that loop repeats over and over again, indicates why you should not really allow loop to block. Your code should wiz through loop and around again before you know it.
Most Arduino projects contain an element of needing to control something. Therefore, the contents of a loop often:
• Check if buttons are pressed or a sensor threshold has been exceeded.
• Perform a relevant action.
A simple example of this would be a push switch that, when pressed, toggles LED flashing on and off.
The following example illustrates this. As you shall see later, however, the limitations imposed by having to wait while the LED flashes are sometimes not acceptable.
The problem with this code is that you can only check that the button has been pressed once the blinking has finished. If a button is pressed while the blinking is in progress, it won’t register. This may not be important to the operation of the sketch, but if it is important to register every button press, then you need to make sure the loop does not have any delays in it. In fact, once the flashing is triggered, the Arduino spends most of its time blinking and there is only a tiny window in which the button press can be registered.
The example in the next section solves this problem.
You can rewrite the previous sketch to avoid using delay:
In this sketch, I have added two new variables: lastChangeTime and ledState. The lastChangeTime variable records the last time the LED was toggled between on and off, and the ledState variable contains that on/off state, so when it needs to be toggled, you know what the LED’s current state is.
The loop now contains no delays. The first part of the loop checks for a button press, and if a button is pressed, it toggles the flashing state. The extra if statement, shown next, is simply a nice refinement that turns the LED off if the button press has caused flashing to be turned off. Otherwise, the LED might be left on, even though flashing has been canceled.
The second part of the loop finds the current millis() count and then compares this with the value in lastChangeTime with period added to it. This means that the code inside the if will only be run if more than period milliseconds has elapsed.
The ledState variable is then toggled and the digital output set accordingly. The value in now is then copied to lastChangeTime so the code can wait for the next period to elapse before being activated again.
The “Pause Without Blocking” approach of the previous section has been generalized into a library that allows you to schedule repeating events using millis. Despite its name, the library has nothing to do with the hardware timers on the device and will, therefore, work just fine on most Arduino and Arduino-compatible boards.
You can download the library from http://playground.arduino.cc//Code/Timer.
Using this library simplifies the code, as you can see here:
To use this library, you define a timer, in this case called t, and then within your setup function you specify a function that calls periodically using:
t.every(period, flashIfRequired);
You then place the following line in your loop function:
t.update();
Every time the update function is called, millis checks if any of the timed events need to be actioned, and if they do, it calls the linked function (in this case flashIfRequired).
The Timer library also has a number of other utility functions; for more information on the library, see the link at the beginning of this section.
A simple Arduino program can be written without much advanced planning. But often even the most innocuous of projects can suddenly become frustratingly complex. Such complexity often arises from the need for the project to be in different states.
Imagine you are designing an Arduino controller for festive lights. For now (and because this is a book about software and not hardware) let’s assume that light is being controlled (the L LED on pin 13 of an Uno) and that a single push switch is being used to toggle between the different display modes of “off,” “on,” and “blinking.”
Sounds simple enough, doesn’t it? But if you start writing the code, you may start to run into problems such as:
• How do I watch out for keypresses while also blinking the LED?
• How do I move from mode to mode?
A really useful technique for writing the code for this type of project is to start by drawing a diagram (Figure 16-1).
Each “state” is represented as a bubble with a label in it. In this case, because we need to make the LED blink some of the time, we actually end up with four states that the program can be in.
Figure 16-1 A state diagram for a festive lights controller.
• OFF: The LED is off.
• ON: The LED is on.
• BLINK_ON: The LED is set to blink, but it is currently on.
• BLINK_OFF: The LED is set to blink, but it is currently off.
The program moves between states in response to either the button being pressed or, in the case of the BLINK states, after a period of time has elapsed. Each possible “transition” between states is indicated as an arrow from one state to another. Each of these arrows has a label that has a top and sometimes a bottom separated by a line. The top part is the condition for changing state (e.g., button pressed) and the bottom (if there is one) is a list of actions that should take place during the transition before the program goes into the next state.
A state diagram like Figure 16-1 is said to describe a “state machine,” which is a good phrase to drop into conversations with other techies if you want to appear clever. However, a diagram isn’t a program and we need a way of converting the diagram into an Arduino C. There are many ways to do this, but here is the style I prefer.
First of all, we need a way of representing the different states that the program can be in. This can be done by simply assigning a number to each possible state and keeping it in a variable. To make this more readable, the C language has a useful data type for this called enum. The code below defines a variable called mode that can only be assigned to one of the uppercase names in the list.
enum {OFF, ON, BLINK_ON, BLINK_OFF} mode;
Behind the scenes, each of the names in the list will be assigned a number, so OFF will be 0, ON will be 1, etc. However, we never need to refer to these numbers; we can always just use the name.
Now we need a way of representing the mechanism of moving between the states. We do this in the loop function, as the following example illustrates:
All we do is have a series of “if” clauses that check the mode and then call the appropriate handler function for that mode. Each time around the loop, just the handler for the mode we are in will be called.
Thinking about the handler for the mode OFF, the only transition possible is to the mode ON if the button is pressed, which will also require an action of turning on the LED. Here it is in C.
The function switchPressed is a utility function that checks for a key press, but also “debounces” the switch ensuring that each press of button is registered just once, even if the switches contacts “bounce” before making a good connection. So, just by setting the mode variable to ON, the next time around the loop, the handler handleONwill be run.
The function handleON also only has one possible transition. That is, if the button is pressed the mode is set to BLINK_ON. Notice that we don’t need to set the LED on, because it is already on.
The handler for BLINK_ON is more complex because there are two possible transitions (referring to Figure 16-1). A button press will take us back to the OFF state, whereas a timeout will take us to BLINK_OFF.
The timeout is achieved by using a variable (lastTime) to record the time in milliseconds from reset that the LED last changed from on to off or vice-versa.
The code for handleBLINK_OFF is very similar to handleBLINK_ON and you can find this along with the rest of the working sketch for this example in sketch_16_04_state_example.
In this chapter, you learned how to allow multiple things to appear to happen at the same time on an Arduino, without using multiple threads. This is simply a matter of adjusting your mindset to the constraints imposed by your favorite little microcontroller board.
In the final chapter of this book, you will learn how to share your code creations with the Arduino community by creating and publishing Arduino libraries.