Multitasking/multithreading in C on Arduino

Doing multitasking/multithreading on Arduino has an advantage, it’s give the possibility to read multiple captors, blink led and start a motor at virtually the same time. This is done by cycling rapidly (faster as the Arduino can) witting all the functions. I made up this code to execute many functions in the default cycling loop function on the Arduino. In the sample, the starting functions are hard coded, but The program offer the advantage of starting and stopping functions at run time. In a more complex program I’m doing it by adding a serial communication ability to the code, so I can call only the functions I need.

// By kevin@playwithmyled.com - 2009-10-17.
// 2010-05-11: Better and lighter.

// Define a function pointer and initialize to NULL.
typedef void (*FunctionPointer) ();

// Declare looping actions function names, declared lower.
FunctionPointer xActions[] = {loopActionA,loopActionB,loopActionC};
// Define actions status flags. Set to 1 to auto execute a start.
int xActionsFlags[] = {0,0,0}; 

int xActionsCount = sizeof(xActions);

void xActionTrigger(int id=0, int action=0) {
  // The id represent it's position in the flags array.
  // Action 1 = executed, 0 not.
  xActionsFlags[id] = action;
}

// LOOPING FUNCTIONS

void loopActionA() {
        // Do something...
}

void loopActionB() {
	// Do something...
}

void loopActionC() {
	// Do something...
}

// Exectute all loop functions.
void xDoActions() {
	// Execute all looped function.
	for(unsigned int j=0; j < xActionsCount; j++) {
		if( xActionsFlags[j] == 1 ) { // Execute the action if.
			xActions[j](); // Call the related loop action.
		}
	}
}

void setup() {
        xActionTrigger(0,1); // First action.
        xActionTrigger(2,1); // Third action.
}

void loop() {
	xDoActions();
}

16 thoughts on “Multitasking/multithreading in C on Arduino

  1. I don’t get the point of your piece of code. This is actually not a multithreading program is it ?

    Specificly here : xActions[xActionsFlags[j]]();
    if xActionsFlags[j] can be 1 or 0, how can you call your loopActionC function ? Did you mean xActions[j](); ?

    Considering you wait the task to finish (because you just call it but don’t abort it), this has nothing to do with realtime or multithreading software !

    Can you explain what did you try to do when you wrote this code ?

  2. @Brewal Renault. I have made some improvement to this code, but the principle is about the same. What I wanted there, is a program that can flag ON or OFF a function to be called. So a button can activate the flag of a function and when it’s ON, the function is automatically called in the main loop. Maybe it’s not true multitasking, but the objective of running multiple tasks at virtually the same time is met. I wanted a program that can make a stepper run (each step at a time) while the program continue to check other stuff like buttons. I know I can do some of that with interrupt too. Indeed, called functions must not take the loop and too much time to execute their task. So like for spinning a stepper, I use timer and static variable in the function and I don’t loop in the function. Each time the function is called from the main loop, I check if the motor is ready to move a step, if yes I do it and return. I hope I make me understandable. If you have betters idea, I am really open to it!

  3. Ok, I see what you are doing ! This script is indeed quite interesting. But, if you want your system to operate so, you can use an RTOS. You can use DuinOS, an RTOS based on FreeRTOS. This OS is easy to use, but you should take a look at the FreeRTOS website in order to understand how it runs.
    I used it for a project, and it works like a charm !

    But your script has the advantage of being robust and convenient for small specific applications.

  4. You look like an expert on Arduino multi-tasking, i’m struggling with Serial communication and multitasking. I programmed a piece of code that read serial commands and executes it, such as “Turn LED ON”, “Turn LED off”, etc… but i’m not sure how to do something like “BLINK LED ON”, “BLINK LED OFF”…. the minute i get into the blink led loop, i’m unable to send a serial command… Any ideas?

  5. Thank you, but I am no expert. I’m just doing my best. You can’t use the delay function in your program. This function makes everything else, like the serial connection, hang until the delay is past. You must use the time in your loop. When the right time is reach, you tell your function to do what you need. Else you let the program continue. Take a look at the motorSpin function in my stepper motor controller program for an example.

  6. Thank you for the sample.
    I have found a little error in xDoActions() :

    change row
    xActions[xActionsFlags[j]]();

    in
    xActions[j]();

  7. Hello sir, I got the same project with the example program above, I copied the code but error

    this error :
    jun25c.cpp: In function ‘void xDoActions()':
    jun25c.cpp:32:16: error: ‘xActionsFlags’ was not declared in this scope

    can you help me ? thanks

  8. Hello sir, i have copied your code. But nothing happen on my led. In void loopactionA i give task blink led. But the led just on not blink. Why ? Can you help me.

  9. Hi Kevin,

    I test your code to light up/down 2 LEDs at the same time but it doesn’t work. It still waiting for the other loop to finished before continue its own loop.

    void loopActionA() {
    // Do something…
    digitalWrite(12, HIGH);
    delay(1000);
    digitalWrite(12, LOW);
    delay(1000);
    }

    void loopActionB() {
    // Do something…
    digitalWrite(13, HIGH);
    delay(1000);
    digitalWrite(13, LOW);
    delay(1000);
    }

  10. You can’t use delay function within your loops. This function freezes de program.

  11. hi im rommel can u help me in this codes i need to run many action in same time and delays for aquarium

    my mission is to run
    auto feeder
    auto cleaner
    auto lights
    auto blink led

    in own loops

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /*
    CODES BY ROMMEL D. ACOSTA

    */
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /*
    PIN CONNECTIONS
    */

    int autoled = 13;
    int feeder = 3;
    int cleaner = 4;
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    int sensing = 400; //TIME DELAYS 5sec
    int light = 3000; //TIME DELAYS 3sec

    int feederon = 10000; //TIME DELAYS 10sec
    int feederoff = 3000; //TIME DELAYS 3sec

    int cleanon = 1000; //TIME DELAYS 1hr
    int cleanoff = 3000; //TIME DELAYS 3hr

    //int cleanon = 3600000; //TIME DELAYS 1hr
    //int cleanoff = 10800000; //TIME DELAYS 3hr
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////

    void setup() {

    Serial.begin(9600);
    pinMode (autoled,OUTPUT);
    pinMode (feeder,OUTPUT);
    pinMode (cleaner,OUTPUT);

    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    void loop() {
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////

    {
    int sensorValue = analogRead(A0);
    float voltage = sensorValue * (5.0 / 1023.0);
    Serial.print(“=D>>>>>>>>> SENSE VOLTAGE: “);
    Serial.println(voltage);
    delay (sensing); //FOR SENSING CONFIRMATION IN miliSEC

    if (voltage > 1); Serial.println (“*********** LIGHT DETECTED – Led OFF ***********”);
    if (voltage > 1); digitalWrite (autoled,LOW);

    if (voltage < 0.99) Serial.println ("*********** CANT DETECT – LIGHT Led ON ***********");
    if (voltage < 0.99) digitalWrite (autoled,HIGH);

    }
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////

    {

    Serial.println ("FEEDER IS ON…!");
    digitalWrite (feeder,HIGH); //SIGNAL FOR ON
    delay (feederon); //run time of feeder

    Serial.println ("FEEDER IS OFF…!");
    digitalWrite (feeder,LOW); //SIGNAL FOR OFF
    delay (feederoff); //OFF TIME
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////

    {

    Serial.println ("CLEANER IS ON…!");
    digitalWrite (cleaner,HIGH); //SIGNAL FOR ON
    delay (cleanon); //run time of cleaner

    Serial.println ("CLEANER IS OFF…!");
    digitalWrite (cleaner,LOW); //SIGNAL FOR OFF
    delay (cleanoff); //OFF TIME
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //for temperature
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //forchaging water
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /*
    CODES BY ROMMEL D. ACOSTA
    BSIT 4 F4A
    UNIVERSITY OF PERPETUAL HELP – GMA
    */
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    }

  12. Hi Rommel. You can’t use delay function in your script. This function makes the script stop executing for the time prescribed. You have to time your event and loop through all them.

    Here’s the logic :


    loop
    feeder function
    cleaner function
    lights function
    blink_led function

    The looping is performed several times a second. In each of your functions, you have a logic like this :


    If it's time to go ON : go ON. Else stay OFF. Don't delay and continue to the next function.

    Please refer to Looping without breaking the code with the Millis function for the code to put in your functions to test the time.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>