23

I have a couple of tasks to do with arduino but one of them takes very long time, so I was thinking to use threads to run them simultaneously. I have an Arduino Mega

[Update] Finally after four years I can install FreeRTOS in my arduino mega. Here is a link

Snake Sanders
  • 2,641
  • 2
  • 31
  • 42
  • You can use a AVR with the ArduinoProcessScheduler library. It's very close to real multitasking. Check it out at: https://github.com/wizard97/ArduinoProcessScheduler – Unsigned_Arduino Aug 29 '18 at 20:07

11 Answers11

18

In short: NO. But you may give it a shot at: http://www.kwartzlab.ca/2010/09/arduino-multi-threading-librar/

(Archived version: https://web.archive.org/web/20160505034337/http://www.kwartzlab.ca/2010/09/arduino-multi-threading-librar

Github: https://github.com/jlamothe/mthread

Filipe YaBa Polido
  • 1,656
  • 1
  • 17
  • 39
8

Not yet, but I always use this Library with big projects: https://github.com/ivanseidel/ArduinoThread

I place the callback within a Timer interrupt, and voilá! You have pseudo-threads running on the Arduino...

Ivan Seidel
  • 2,394
  • 5
  • 32
  • 49
6

Just to make this thread more complete: there are also protothreads which have very small memory footprint (couple bytes if I remember right) and preserve variables local to thread; very handy and time saving (far less finite state machines -> more readable code).

Examples and code: arduino-class / ProtoThreads wiki

Just to let you know what results you may expect: serial communication @ 153K6 baudrate with threads for: status diodes blinking, time keeping, requested functions evaluation, IO handling and logic and all on atmega328.

Mr. Girgitt
  • 2,853
  • 1
  • 19
  • 22
4

Not real threading but TimedActions are a good alternative for many uses

http://playground.arduino.cc/Code/TimedAction#Example

Of course, if one task blocks, the others will too, while threading can let one task freeze and the others will continue...

FrancescoMM
  • 2,845
  • 1
  • 18
  • 29
2

No you can't but you can use Timer interrupt. Ref : https://www.teachmemicro.com/arduino-timer-interrupt-tutorial/

BATMAN_
  • 307
  • 3
  • 11
1

The previous answer is correct, however, the arduino generally runs pretty quick, so if you properly time your code, it can accomplish tasks more or less simultaneously.

The best practice is to make your own functions and avoid putting too much real code in the default void loop

lkrasner
  • 112
  • 2
  • 13
  • 7
    I can't agree with this: "The best practice is to make your own functions and avoid putting too much real code in the default void loop" - it doesn't matter whether the code is in the loop or in your own functions, if it gets *called* from the loop, it's pretty much the same thing timing wise (plus a tiny function-call overhead) – Martin Thompson Mar 08 '13 at 13:09
  • 2
    @MartinThompson I don't think he was writing about it timing wise. I rather think he was referring to the functional organization, the fact that it is much more practical to rearrange the code later (adding TimedAction or ArduinoThread later to the same code, for instance). – FrancescoMM Dec 13 '13 at 11:50
  • 1
    @FrancescoMM: thanks - I hadn't read it that way at all, but now you mention it, that probably is what the OP meant! I think the mention of "timing" in the first sentence through me. – Martin Thompson Dec 13 '13 at 14:44
1

You can use arduinos

It is designed for Arduino environment. Features:

  • Only static allocation (no malloc/new)
  • Support context switching when delaying execution
  • Implements semaphores
  • Lightweight, both cpu and memory

I use it when I need to receive new commands from bluetooth/network/serial while executing the old ones and the old ones have delay in them. One thread is the sever thread that does the following loop:

while (1) {
    while ((n = Serial.read()) != -1) {
        // do something with n, like filling a buffer
        if (command_was_received) {
            arduinos_create(command_func, arg);
        }
    }
    arduinos_yield(); // context switch to other threads
}

The other is the command thread that executes the command:

int command_func(void* arg) {
    // move some servos
    arduinos_delay(1000); // wait for them to move
    // move some more servos
}
eyal
  • 29
  • 1
1

Arduino does not support multithread programming.

However there have been some workarounds, for example the one in this project (you can install it also from the Arduino IDE).

It seems you have to define the schedule time yourself while in a real multithread environment it is the OS that decides when to execute tasks.

Alternatively you can use protothreads

roschach
  • 8,390
  • 14
  • 74
  • 124
1

The straight answer is No No No!. There are some alternatives but you can't expect a perfect multi threading functionality from an arduino mega. You can use arduino due or lenado for multithreading like below-

void loop1(){
}
void loop2(){
}
void loop3(){
}

Normally, I handle those types of cases in backend. You can run the main code in a server while using Arduino to just collect inputs and show outputs. In such cases I would prefer nodemcu which has built in wifi.

1

Thread NO! Concurrent YES!

You can run different tasks concurrently with FreeRTOS library. https://www.arduino.cc/reference/en/libraries/freertos/

void TaskBlink( void *pvParameters );
void TaskAnalogRead( void *pvParameters );


  // Now set up two tasks to run independently.
  xTaskCreate(
    TaskBlink
    ,  (const portCHAR *)"Blink"   // A name just for humans
    ,  128  // Stack size
    ,  NULL
    ,  2  // priority
    ,  NULL );

  xTaskCreate(
    TaskAnalogRead
    ,  (const portCHAR *) "AnalogRead"
    ,  128 // This stack size can be checked & adjusted by reading Highwater
    ,  NULL
    ,  1  // priority
    ,  NULL );

void TaskBlink(void *pvParameters)  // This is a task.
{
  (void) pvParameters;

  // initialize digital pin 13 as an output.
  pinMode(13, OUTPUT);

  for (;;) // A Task shall never return or exit.
  {
    digitalWrite(13, HIGH);   // turn the LED on (HIGH is the voltage level)
    vTaskDelay( 1000 / portTICK_PERIOD_MS ); // wait for one second
    digitalWrite(13, LOW);    // turn the LED off by making the voltage LOW
    vTaskDelay( 1000 / portTICK_PERIOD_MS ); // wait for one second
  }
}

void TaskAnalogRead(void *pvParameters)  // This is a task.
{
  (void) pvParameters;

  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);

  for (;;)
  {
    // read the input on analog pin 0:
    int sensorValue = analogRead(A0);
    // print out the value you read:
    Serial.println(sensorValue);
    vTaskDelay(1);  // one tick delay (15ms) in between reads for stability
  }
}

Just take care! When different tasks tried to reach variables at the same time, like i2c communication line or sd card module. Use Semaphores and mutexes https://www.geeksforgeeks.org/mutex-vs-semaphore/.

ouflak
  • 2,458
  • 10
  • 44
  • 49
0

Arduino does not supports threading. However, you can do the next best thing and structure your code around state machines running in interleaving.

While there are lots of ways to implement your tasks as state machines, I recommend this library (https://github.com/Elidio/StateMachine). This library abstracts most of the process.

You can create a state machine as a class like this:

#include "StateMachine.h"
class STATEMACHINE(Blink) {
  private:
    int port;
    int waitTime;
    CREATE_STATE(low);
    CREATE_STATE(high);

    void low() {
      digitalWrite(port, LOW);
      *this << &STATE(high)<< waitTime;
    }
    void high() {
      digitalWrite(port, HIGH);
      *this << &STATE(low)<< waitTime;
    }
  public:
    Blink(int port = 0, int waitTime = 0) :
      port(port),
      waitTime(waitTime),
      INIT_STATE(low),
      INIT_STATE(high)
      {
        pinMode(port, OUTPUT);
        *this << &STATE(low);
      }
};

The macro STATEMACHINE() abstracts the class inheritances, the macro CREATE_STATE() abstracts the state wrapper creation, the macro INIT_STATE() abstracts method wrapping and the macro STATE() abstracts state wrapper reference within the state machine class.

State transition is abstracted by << operator between the state machine class and the state, and if you want a delayed state transition, all you have to do is to use that operator with an integer, where the integer is the delay in millisseconds.

To use the state machine, first you have to instantiate it. Declaring an reference to the class in global space while instantiating it with new on setup function might do the trick

Blink *led1, *led2, *led3;


void setup() {
  led1 = new Blink(12, 300);
  led2 = new Blink(11, 500);
  led3 = new Blink(10, 700);
}

Then you run the states on loop.

void loop() {
    (*led2)();
    (*led1)();
    (*led3)();
}
Luiz Menezes
  • 749
  • 7
  • 16