Pages: [1] 2   Go Down
Author Topic: Arduino Multithreading  (Read 19532 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Newbie
*
Karma: 0
Posts: 16
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi, I want to do two things at the same time, for example: turn on two servo motors.

Or I dunno, but can the Arduino handle multithread tasks?
Like calculating [ch960] and flashing a led at the same time.
Logged

Connecticut, US
Offline Offline
Edison Member
*
Karma: 2
Posts: 1036
Whatduino
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

No such thing as a thread, to the microcontroller.  But you could write your own simple task scheduler, and bounce between those tasks according to their timing requirements.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 23
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Here's a function I came up with to do what halley is talking about.

Code:
boolean cycleCheck(unsigned long *lastMillis, unsigned int cycle)
{
  unsigned long currentMillis = millis();
  if(currentMillis - *lastMillis >= cycle)
  {
    *lastMillis = currentMillis;
    return true;
  }
  else
    return false;
}

Basic usage:

For each event you want to deal with, set up an unsigned int for how often it should trigger in ms (cycle), and an unsigned long to keep track of the last millis() reading since the last event (lastMillis). You call the function passing the address of the lastMillis for that event and the cycle for that event. The function returns a true if the event is due for action, and a false if the syscle time hasn't elapsed yet.

Typical usage example (Simple blinking 2 LEDs at different rates)

Code:
#define ledPin1 11
#define ledPin2 12

#define led1Cycle 100U
#define led2Cycle 275U

unsigned long led1LastMillis = 0;
unsigned long led2LastMillis = 0;

boolean led1State = false;
boolean led2State = false;

boolean cycleCheck(unsigned long *lastMillis, unsigned int cycle)
{
  unsigned long currentMillis = millis();
  if(currentMillis - *lastMillis >= cycle)
  {
    *lastMillis = currentMillis;
    return true;
  }
  else
    return false;
}

void setup()
{
  pinMode(ledPin1, OUTPUT);
  pinMode(ledPin2, OUTPUT);
}

void loop()
{
  if(cycleCheck(&led1LastMillis, led1Cycle))
  {
    digitalWrite(ledPin1, led1State);
    led1State = !led1State;
  }
  if(cycleCheck(&led2LastMillis, led2Cycle))
  {
    digitalWrite(ledPin2, led2State);
    led2State = !led2State;
  }
}

I've found this to work very well, and it keeps the main loop code very clean. You can even make the cycle times variable by making them variables instead of #defines. Then you can change the cycle times during execution. For example, you want to change the blink rate with a potentiometer.
« Last Edit: January 06, 2009, 01:23:10 am by dmesser » Logged

Copenhagen / Denmark
Offline Offline
Edison Member
*
Karma: 6
Posts: 2360
Do it !
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

That's a very good generalized solution to a common problem.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 23
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks. Hope it's useful to some... Someday I'll make the function deal with millis() rollover, too....
« Last Edit: January 06, 2009, 01:26:35 am by dmesser » Logged

0
Offline Offline
Full Member
***
Karma: 0
Posts: 147
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
For each event you want to deal with, set up an unsigned int for how often it should trigger in ms (cycle), and an unsigned long to keep track of the last millis() reading since the last event (lastMillis). You call the function passing the address of the lastMillis for that event and the cycle for that event. The function returns a true if the event is due for action, and a false if the syscle time hasn't elapsed yet.

I use a very similar function myself, the difference is that I'm using a struct to hold the last_millis- and interval-values. I'm also using similar functions to poll switches, changes in analog input etc. As you said, it keeps the main loop clean and the code is much easier to follow.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 23
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I like the idea of using a struct for the last millis and cycle parameters. Good idea.
Logged

0
Offline Offline
God Member
*****
Karma: 1
Posts: 513
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Maybe have a look at http://www.bdmicro.com/code/threads/ too.

Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 7
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hello i have to play a sound on a buzzer (so repeat HIGH and LOW on its pins, at a given frequency (the note)) and while i'm doing this, i have to check if to continue or not.

i check from an incoming message from the usb (a midi message), if the message is NoteOff then it has to stop the BUzzer.

maybe i could use this code to deal with that? :-?
Logged

London
Offline Offline
Tesla Member
***
Karma: 10
Posts: 6255
Have fun!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

giacomo, have a look at the Arduino tone function introduced in release 0018: http://arduino.cc/en/Reference/Tone
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 7
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

thaaaaaanks!
Logged

Norway@Oslo
Offline Offline
Edison Member
*
Karma: 13
Posts: 2033
loveArduino(true);
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Could have a look at this next time you need to time some reoccurring actions:
http://www.arduino.cc/playground/Code/TimedAction
 smiley
Logged

São Paulo - SP
Offline Offline
Newbie
*
Karma: 0
Posts: 11
Bruno
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi.

I wrote some lines using structs and 2 task running, one for send display data and other for read keyboard buttons.

Task for display run every 3000 milliseconds
Keyboard task run every 100 milliseconds

Enjoy ...

Bruno

typedef struct Timer
{
    unsigned long start;
    unsigned long timeout;
};

char TimerExpired ( struct Timer * timer )
{
    if ( millis () > timer->start + timer->timeout )
        return true;

    return false;    
}

void TimerStart ( struct Timer * timer )
{
    timer->start = millis ( );
}

//Display task running every 3000 milliseconds
Timer timerDisplay = { 0, 3000 };
//Keyboard task running every 100 milliseconds
Timer timerKeyboard = { 0, 100 };

void setup (void)
{
}

void loop (void)
{
    if ( TimerExpired ( & timerDisplay ) )
    {
        taskDisplay ( );
        TimerStart ( & timerDisplay );
    }

    if ( TimerExpired ( & timerKeyboard ) )
    {
        taskKeyboard ( );
        TimerStart ( & timerKeyboard );
    }
}

void taskKeyboard ( void )
{
}

void taskDisplay ( void )
{
}
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 2
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Try this:
http://robotgroup.com.ar/noticias/20091102/duinos-sistema-operativo-multitarea-para-arduino
Logged

B0100111001000011, USA
Offline Offline
Edison Member
*
Karma: 0
Posts: 1503
I'm confused.  Wait, maybe not..
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

You can you use the Arduino's in-built PWM timers to change the brightness (as you see it) of an LED.

Check out analogWrite().
Logged

Pages: [1] 2   Go Up
Jump to: