Is there a way I can have multiple parts of the program running together without doing multiple things in the same code block?

One thread waiting for an external device while also blinking a LED in another thread.

  • 3
    You should probably first ask yourself if you really need threads. Timers may be OK for your needs already and they are natively supported on Arduino. – jfpoilpret Feb 18 '14 at 19:34
  • 1
    You may want to check out the Uzebox too. It's a two chip homebrew video game console. So while it isn't exactly an Arduino, the entire system is built on interrupts. So audio, video, controls, etc. are all interrupt driven while the main program doesn't have to worry about any of it. May be good reference. – cbmeeks Jul 14 '15 at 16:59
up vote 43 down vote accepted

There is no multi-process, nor multi-threading, support on the Arduino. You can do something close to multiple threads with some software though.

You want to look at Protothreads:

Protothreads are extremely lightweight stackless threads designed for severely memory constrained systems, such as small embedded systems or wireless sensor network nodes. Protothreads provide linear code execution for event-driven systems implemented in C. Protothreads can be used with or without an underlying operating system to provide blocking event-handlers. Protothreads provide sequential flow of control without complex state machines or full multi-threading.

Of course, there is an Arduino example here with example code. This SO question might be useful, too.

ArduinoThread is a good one too.

AVR based Arduino's do not support (hardware) threading, I am unfamiliar with the ARM based Arduino's. One way around this limitation is the use of interrupts, especially timed interrupts. You can program a timer to interrupt the main routine every so many microseconds, to run a specific other routine.

http://arduino.cc/en/Reference/Interrupts

It is possible to do software side multi-threading on the Uno. Hardware level threading is not supported.

To achieve multithreading, it will require the implementation of a basic scheduler and maintaining a process or task list to track the different tasks that need to be run.

The structure of a very simple non-preemptive scheduler would be like:

//Pseudocode
void loop()
{

for(i=o; i<n; i++) 
run(tasklist[i] for timelimit):

}

Here, tasklist can be an array of function pointers.

tasklist [] = {function1, function2, function3, ...}

With each function of the form:

int function1(long time_available)
{
   top:
   //Do short task
   if (run_time<time_available)
   goto top;
}

Each function can perform a separate task such as function1 performing LED manipulations, and function2 doing float calculations. It will be the responsibility of each task(function) to adhere to the time allocated to it.

Hopefully, this should be enough to get you started.

  • 2
    I am not sure I would talk about "threads" when using a non preemptive scheduler. By the way, such a scheduler already exists as an arduino library: arduino.cc/en/Reference/Scheduler – jfpoilpret Feb 18 '14 at 20:40
  • 5
    @jfpoilpret - Cooperative multithreading is a real thing. – Connor Wolf Feb 20 '14 at 1:09
  • Yes you're right! My mistake; it had been so long ago I had not faced cooperative multithreading that in my mind, multithreading had to be preemptive. – jfpoilpret Feb 20 '14 at 4:47

As per the description of your requirements:

  • one thread waiting for an external device
  • one thread blinking a LED

It seems you could use one Arduino interrupt for the first "thread" (I would rather call it "task" in fact).

Arduino interrupts can call one function (your code) based on an external event (voltage level or level change on a digital input pin), that will trigger your function immediately.

However, one important point to keep in mind with interrupts is that the called function should be as fast as possible (typically, there should be no delay() call or any other API that would depend on delay()).

If you have a long task to activate upon external event trigger, then you could potentially use a cooperative scheduler and add a new task to it from your interrupt function.

A second important point about interrupts is that their number is limited (e.g. only 2 on UNO). So if you start tohave more external events, you would need to implement some kind of multiplexing all inputs into one, and have your interrupt function determine what multiplexed inut was the actual trigger.

A simple solution is to use a Scheduler. There are several implementations. This describes shortly one that is available for AVR and SAM based boards. Basically a single call will start a task; "sketch within a sketch".

#include <Scheduler.h>
....
void setup()
{
  ...
  Scheduler.start(taskSetup, taskLoop);
}

Scheduler.start() will add a new task that will run the taskSetup once and then repeatedly call taskLoop just as the Arduino sketch works. The task has its own stack. The size of the stack is an optional parameter. Default stack size is 128 bytes.

To allow context switching the tasks need to call yield() or delay(). There is also a support macro for waiting for a condition.

await(Serial.available());

The macro is syntactic sugar for the following:

while (!(Serial.available())) yield();

Await can also be used to synchronize tasks. Below is an example snippet:

volatile int taskEvent = 0;
#define signal(evt) do { await(taskEvent == 0); taskEvent = evt; } while (0)
...
void taskLoop()
{
  await(taskEvent);
  switch (taskEvent) {
  case 1: 
  ...
  }
  taskEvent = 0;
}
...
void loop()
{
  ...
  signal(1);
}

For further details see the examples. There are examples from multiple LED blink to debounce button and a simple shell with non-blocking command line read. Templates and namespaces can be used to help structure and reduce the source code. Below sketch shows how to use template functions for multi-blink. It is sufficient with 64 bytes for the stack.

#include <Scheduler.h>

template<int pin> void setupBlink()
{
  pinMode(pin, OUTPUT);
}

template<int pin, unsigned int ms> void loopBlink()
{
  digitalWrite(pin, HIGH);
  delay(ms);
  digitalWrite(pin, LOW);
  delay(ms);
}

void setup()
{
  Scheduler.start(setupBlink<11>, loopBlink<11,500>, 64);
  Scheduler.start(setupBlink<12>, loopBlink<12,250>, 64);
  Scheduler.start(setupBlink<13>, loopBlink<13,1000>, 64);
}

void loop()
{
  yield();
}

There is also a benchmark to give some idea of the performance, i.e. time to start task, context switch, etc.

Last, there are a few support classes for task level synchronization and communication; Queue and Semaphore.

From a previous incantation of this forum, the following question/answer was moved to Electrical Engineering. It has sample arduino code to blink an LED using a timer interrupt while using the main loop to do serial IO.

https://electronics.stackexchange.com/questions/67089/how-can-i-control-things-without-using-delay/67091#67091

Repost:

Interrupts are a common way to get things done while something else is going on. In the example below, the LED is blinking without using delay(). Whenever Timer1 fires, the interrupt service routine (ISR) isrBlinker() is called. It switches the LED on/off.

To show that other things can simultaneously happen, loop() repeatedly writes foo/bar to the serial port independent of the LED blinking.

#include "TimerOne.h"

int led = 13;

void isrBlinker()
{
  static bool on = false;
  digitalWrite( led, on ? HIGH : LOW );
  on = !on;
}

void setup() {                
  Serial.begin(9600);
  Serial.flush();
  Serial.println("Serial initialized");

  pinMode(led, OUTPUT);

  // initialize the ISR blinker
  Timer1.initialize(1000000);
  Timer1.attachInterrupt( isrBlinker );
}

void loop() {
  Serial.println("foo");
  delay(1000);
  Serial.println("bar");
  delay(1000);
}

This is a very simple demo. ISRs can be much more complex and can be triggered by timers and external events (pins). Many of the common libraries are implemented using ISRs.

I also came to this topic while implementing a matrix LED display.

In one word, you may build a polling scheduler by using millis() function and timer interrupt in Arduino.

I suggest the following articles from Bill Earl:

https://learn.adafruit.com/multi-tasking-the-arduino-part-1/overview

https://learn.adafruit.com/multi-tasking-the-arduino-part-2/overview

https://learn.adafruit.com/multi-tasking-the-arduino-part-3/overview

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.