Arduino Multitasaking

I don't have to !

It was my brain power versus your assumptions :brain:

doesn't that suggest loop() takes > 1 msec to execute?

and consider the units (seconds)

why?

ok, if millis () behaves as you suggest, then the approach Terry described should work.

but i wonder how accurate the timing needs to be if the OP is asking how to do this on this Arduino forum. does the accuracy need to be within 1ms over a 24 hour period or 1 sec?

i've worked on a number projects maintaining time within a couple nsec accuracy. depends on the OPs requirements

but keep in mind the OP thought this was a multi-tasking problem

I removed the completely off-topic posts. Everyone, please try to focus the replies here on helping vignesh_skp with their project. You are welcome to open a separate topic for the interesting tangential discussions.

i believe the following will remain aligned to the starting millis() value without drifting using the Terry method

i ran the millis() code on the laptop and found that it increments twice every 42 tics and reason for odd start time. note how while the cycle is an even 100, the first interval expire at 43 while the 3rd at 142

     43     42      5  On test
     47     47     95 Off test
    142    142      5  On test
    147    147     95 Off test
    242    242      5  On test
    247    247     95 Off test
    342    342      5  On test
    347    347     95 Off test
    442    442      5  On test
    447    447     95 Off test
    542    542      5  On test
    547    547     95 Off test
    642    642      5  On test
    647    647     95 Off test
    742    742      5  On test
    747    747     95 Off test
    842    842      5  On test
    847    847     95 Off test
    942    942      5  On test
    947    947     95 Off test
   1042   1042      5  On test
   1047   1047     95 Off test
   1142   1142      5  On test
   1147   1147     95 Off test
   1242   1242      5  On test
   1247   1247     95 Off test
   1342   1342      5  On test
   1347   1347     95 Off test
   1442   1442      5  On test
   1447   1447     95 Off test
   1542   1542      5  On test
   1547   1547     95 Off test
   1642   1642      5  On test
   1647   1647     95 Off test
   1742   1742      5  On test
   1747   1747     95 Off test
   1842   1842      5  On test
   1847   1847     95 Off test
   1942   1942      5  On test
   1947   1947     95 Off test
   2042   2042      5  On test
   2048   2047     95 Off test
   2142   2142      5  On test
   2147   2147     95 Off test
   2242   2242      5  On test
   2247   2247     95 Off test
   2342   2342      5  On test
   2347   2347     95 Off test
   2442   2442      5  On test
   2447   2447     95 Off test
   2542   2542      5  On test
   2547   2547     95 Off test
   2642   2642      5  On test
   2647   2647     95 Off test
struct Led {
    const byte PinLed;

    const unsigned long MsecStart;
    const unsigned long MsecOn;
    const unsigned long MsecOff;

    const char *desc;

    unsigned long msecLst;
    unsigned long msecPeriod;
};

Led leds [] = {
#if 0
    { 10,    0,  300,  300, "MV1" },
    { 11,   10,  240,  360, "EV2" },
    { 12,  246,    4,  296, "DRAIN" },
    { 13,  310,  240,  360, "EV1" },
#else
    { 12,   42,    5,   95, "test" },
#endif
};

const int Nled = sizeof(leds) / sizeof(Led);

const int K = 1;                    // scale timing for testing

enum { Off = HIGH, On = LOW };

char s [80];

// -----------------------------------------------------------------------------
void loop ()
{
    unsigned long msec = millis ();
    char *t;

    Led *p = leds;
    for (int n = 0; n < Nled; n++, p++)  {
        // check for led timeout
        if (msec - p->msecLst >= p->msecPeriod)  {
            p->msecLst    += p->msecPeriod;

            if (On == digitalRead (p->PinLed))  {
                digitalWrite (p->PinLed, Off);
                p->msecPeriod  = p->MsecOff * K;
                t = (char*) "Off";
            }
            else  {
                digitalWrite (p->PinLed, On);
                p->msecPeriod  = p->MsecOn * K;
                t = (char*) "On";
            }


            sprintf (s, " %6lu %6lu %6lu %3s %s",
                    msec, p->msecLst, p->msecPeriod, t, p->desc);
            Serial.println (s);
        }
    }
}

// -----------------------------------------------------------------------------
void setup ()
{
    Serial.begin (9600);
    Serial.println ();

    Led *p = leds;
    for (int n = 0; n < Nled; n++, p++)  {
        pinMode      (p->PinLed, OUTPUT);
        digitalWrite (p->PinLed, Off);

        p->msecPeriod =   p->MsecOff;
        p->msecLst    = -(p->MsecOff - p->MsecStart) * K;
    }
}

@gcjr Is this all and what you are talking about?

  p->msecLst    += p->msecPeriod;

versus

            p->msecLst = msec;

Each method has its place. Here, if your belief is in some truth, the first method is preferred works.

a7

the earlier version is simpler, and as already mentioned, not sure what the OPs requirements are.

i didn't realize millis() skipped values.

i didn't think the challenge was avoiding the slip. i thought it was to how to initialize them to start precisely

you're having a hard time reading 44 lines of code?

lots of code has been reviewed. we used git. some in Android.

Kernighan advocates simple variable names in Practice of Programming.

'p' for ptr. i first saw this approach looking at Unix process management code

You can keep denying it, and I appreciate that you think tossing a beginner into some water somewhat deeper than she might be able to even tread, let alone swim in, is an effective teaching method, but you do use some techniques that are, well, advanced. Or obscure. Or clever.

Often unnecessarily very too deeper.

I know everyone arrives at whatever level they claim for themselves; I think the most effective path is through an understanding of the very simplest way to do things, no matter they be naive or literal or embarrassing or whatever.

Step by step. You know what we are all talking about.

a7

a variable which holds the value from millis(), to be used the next time and called "previousMillis" makes imho more sense than to call it just timeStamp and compare it in the next iteration with something called currentTime. At least you could have called that variable currentTimeStamp.
You want to compare timeStamps, don't you?

For a non English native speaker like me (obvious), previousMillis makes as much sense as millis().

i'd sincerely appreciate it if you would point out what you think is advanced. even better an alternate approach that you believe would better suited for the OP (probably arrays)

i don't know the experience level of the OP and he mentioned multi-tasking.

i've heard very experienced programers describe how difficult it was for them to understand C++ code and i often see people posting code using classes

i'm more than happy to explain more if the OP asks, and i have.

but is this a coding question or an algorithm question (multitasking?)

+1. Or two, is that allowed?

I've always been very bad at naming things, but I have settled on now for the current reading of the clock (millls()), and lastTime or a variation of last<Whatecer>.

I like the idea of explicitly calculating elapsedTime, I'll see if we can scare up a name for it that we like better, don't hold your collective breath on that.

And the stripped out code is good, except there's either no refreshing of the timeStanp or I have too much sand in my eyes.

FWIW, comments in code sections managing time can just be confusing. I routinely ignore comments in amateur code as they can redundant noise, misleading or just plain wrong. In 44 lines of code one might argue that an full understanding of the purpose of the code and the mechanics of the algorithm being coded is better than line by line commentary.

A wrinkle that I think makes some things even better, and has the added benefit of out-denting the controlled code, is to reverse the test, viz:

    if (elapsedTime < interval)  // too soon to even look at the button?
      return;                    // yes. maybe next time

    // do whatever

    timeStanp += interval;       // throw the stone down the road

which fits in well with dragging someone over an essential idea of state machinery in hand-made "muktitasking" - functiions that are called very frequently and only occasionally, when it is time to, take a step further in whatever process they are managing.

I've said this is hard until it is easy. I know of no one who didn't experience some kind of Aha! moment. For some, later than sooner.

Much of this is so much simpler IRL, where one can gauge the progress of the student(s) and probe with alternate angles until a connection is made. Knowing where the student is at seems key - when we deal with ppl still trying to debug their voids by trying an if loop instead of a while loop, who don't even get that lines of code do things and are run one at a time and do those things just like that, your nose on the code line by line, it is hard. And the fact that solutions can be found or are offered complete here you go on these fora just reduces the motivation, for many, that it takes to read code and see how it does the task it was written for.

There is nothing more gratifying than hearing from a noob that she gets it and… it will change the way she codes from now on.

a7

here are 2 less advanced versions

const byte          PinLed     [] = {  10,  11,  12,  13 };
const unsigned long MsecStart  [] = {   0,  10, 246, 310 };
const unsigned long MsecOn     [] = { 300, 240,   4, 240 };
const unsigned long MsecOff    [] = { 300, 360, 296, 360 };
const char         *desc       [] = { "MV1", "EV2", "DRAIN", "EV1" };

const int           Nled = sizeof(PinLed);
      unsigned long msecLst    [Nled];
      unsigned long msecPeriod [Nled];

const int K = 1;                    // scale timing for testing

enum { Off = HIGH, On = LOW };

char s [80];

// -----------------------------------------------------------------------------
void loop ()
{
    unsigned long msec = millis ();
    char *t;

    for (int n = 0; n < Nled; n++)  {
        // check for led timeout
        if (msec - msecLst [n] >= msecPeriod [n])  {
            msecLst [n]    += msecPeriod [n];

            if (On == digitalRead (PinLed [n]))  {
                digitalWrite (PinLed [n], Off);
                msecPeriod [n]  = MsecOff [n] * K;
                t = (char*) "Off";
            }
            else  {
                digitalWrite (PinLed [n], On);
                msecPeriod [n]  = MsecOn [n] * K;
                t = (char*) "On";
            }


            sprintf (s, " %6lu %6lu %6lu %3s %s",
                    msec, msecLst [n], msecPeriod [n], t, desc [n]);
            Serial.println (s);
        }
    }
}

// -----------------------------------------------------------------------------
void setup ()
{
    Serial.begin (9600);
    Serial.println ();

    for (int n = 0; n < Nled; n++)  {
        pinMode      (PinLed [n], OUTPUT);
        digitalWrite (PinLed [n], Off);

        msecPeriod [n] =   MsecOff [n];
        msecLst    [n] = -(MsecOff [n] - MsecStart [n]) * K;
    }
}
const byte          Pin0       = 10;
const byte          Pin1       = 11;
const byte          Pin2       = 12;
const byte          Pin3       = 13;

const unsigned long MsecStart0 = 0;
const unsigned long MsecStart1 = 10;
const unsigned long MsecStart2 = 246;
const unsigned long MsecStart3 = 310;

const unsigned long MsecOn0    = 300;
const unsigned long MsecOn1    = 240;
const unsigned long MsecOn2    = 4;
const unsigned long MsecOn3    = 240;

const unsigned long MsecOff0   = 300;
const unsigned long MsecOff1   = 360;
const unsigned long MsecOff2   = 296;
const unsigned long MsecOff3   = 360;

const char         *desc0      = "MV1";
const char         *desc1      = "EV2";
const char         *desc2      = "DRAIN";
const char         *desc3      = "EV1";

unsigned long msecLst0;
unsigned long msecLst1;
unsigned long msecLst2;
unsigned long msecLst3;

unsigned long msecPeriod0;
unsigned long msecPeriod1;
unsigned long msecPeriod2;
unsigned long msecPeriod3;

unsigned long msec;

const int K = 1;                    // scale timing for testing

enum { Off = HIGH, On = LOW };

char s [80];
char *t;

// -----------------------------------------------------------------------------
void check (
    const byte          & Pin,
    const unsigned long & MsecStart,
    const unsigned long & MsecOn,
    const unsigned long & MsecOff,
          unsigned long & msecLst,
          unsigned long & msecPeriod,
    const char           *desc)
{
    if (msec - msecLst >= msecPeriod)  {
        msecLst    += msecPeriod;

        if (On == digitalRead (Pin))  {
            digitalWrite (Pin, Off);
            msecPeriod  = MsecOff * K;
            t = (char*) "Off";
        }
        else  {
            digitalWrite (Pin, On);
            msecPeriod  = MsecOn * K;
            t = (char*) "On";
        }


        sprintf (s, " %6lu %6lu %6lu %3s %s",
                msec, msecLst, msecPeriod, t, desc);
        Serial.println (s);
    }
}

// -----------------------------------------------------------------------------
void init (
    const byte          & Pin,
    const unsigned long & MsecStart,
    const unsigned long & MsecOn,
    const unsigned long & MsecOff,
          unsigned long & msecLst,
          unsigned long & msecPeriod,
    const char           *desc)
{
    pinMode      (Pin, OUTPUT);
    digitalWrite (Pin, Off);

    msecPeriod =   MsecOff;
    msecLst    = -(MsecOff - MsecStart) * K;
}

// -----------------------------------------------------------------------------
void loop ()
{
    msec = millis ();

    check (Pin0, MsecStart0, MsecOn0, MsecOff0, msecLst0, msecPeriod0, desc0);
    check (Pin1, MsecStart1, MsecOn1, MsecOff1, msecLst1, msecPeriod1, desc1);
    check (Pin2, MsecStart2, MsecOn2, MsecOff2, msecLst2, msecPeriod2, desc2);
    check (Pin3, MsecStart3, MsecOn3, MsecOff3, msecLst3, msecPeriod3, desc3);
}

// -----------------------------------------------------------------------------
void setup ()
{
    Serial.begin (9600);
    Serial.println ();

    init (Pin0, MsecStart0, MsecOn0, MsecOff0, msecLst0, msecPeriod0, desc0);
    init (Pin1, MsecStart1, MsecOn1, MsecOff1, msecLst1, msecPeriod1, desc1);
    init (Pin2, MsecStart2, MsecOn2, MsecOff2, msecLst2, msecPeriod2, desc2);
    init (Pin3, MsecStart3, MsecOn3, MsecOff3, msecLst3, msecPeriod3, desc3);
}

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.