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.
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. |
|||||||||
|
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:
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. |
|||
|
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:
Here,
With each function of the form:
Each function can perform a separate task such as Hopefully, this should be enough to get you started. |
|||||||||||||
|
As per the description of your requirements:
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 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. |
||||
|
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. 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 To show that other things can simultaneously happen,
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 |
||||
|
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".
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.
The macro is syntactic sugar for the following:
Await can also be used to synchronize tasks. Below is an example snippet:
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.
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. |
||||
|