Multi tasking, Fast, rogue example.

Many may not like this method, but some may, and I like it.

I see this as a “To Do List”. When I need to do a task, I put it on a list showing the day/time to do it. I don’t list it as “when it was done last, and how many minutes later I need to do it again.”

This method seems to be a lots cleaner and faster (more loops per second), than others I have seen.

This example is short (less than 65 lines of code) with three functions running at different times.

Do you think it is:
1 faster
2 easier to read
3 less code
4 easier to understand
5 or otherwise

/* multitasking 101-3 By using softdelays after setup(), we
can have many processes (functions) running without noticable
delays. The loop(), on a nano v3 runs a bit over 140,000 times
a second with this code.
Inside each function, it sets the next milli time to run again.
The millis will reset at about ever 7 weeks, so be aware.  */
const int led =  13;
// next time to run functions (simulate multiTasking)
unsigned long nowMilli = 1;
unsigned long lastMilli = 1;
unsigned long nextMilliLogSpeed = 1;
unsigned long nextMilliLedToggle = 1;
unsigned long nextMilliUpdateLcd = 1;
unsigned long loopCounter = 1;
unsigned long KloopPerSecond = 100;// kili loops/sec
unsigned long KloopPerSecondAverage = 100;
unsigned long lastKloopPerSecondAverage = 100;
void setup()
{	// delay is ok in setup(), but not in loop() (just my thoughts)
	pinMode(led, OUTPUT);
	Serial.begin(9600);
	Serial.println("Hello, Joe ");
	delay(799); // total delays over 700 ms
}

void loop()
{	nowMilli = millis(); // used to simulate multi-tasking
	if(nowMilli != lastMilli)
	{	if(nowMilli <700 ) processRollover(); // for 7 week rollover
		if(nextMilliLogSpeed < nowMilli) logSpeed();
		if(nextMilliLedToggle < nowMilli) toggleLed();
		if(nextMilliUpdateLcd < nowMilli) updateDisplay();
		lastMilli = nowMilli;
	}
	loopCounter++;
}
void processRollover()
{	logSpeed();
	toggleLed();
	updateDisplay();
	delay(750);
}
void logSpeed()
{	KloopPerSecond = loopCounter / 1000;
	KloopPerSecondAverage =
	    (KloopPerSecondAverage * 3 + KloopPerSecond) / 4;
	if(lastKloopPerSecondAverage!=KloopPerSecondAverage) 
	{ nextMilliUpdateLcd = nowMilli + 50;
		lastKloopPerSecondAverage = KloopPerSecondAverage;
	}
	loopCounter = 0;
	nextMilliLogSpeed = nowMilli + 1000;
}
void updateDisplay()
{	Serial.print(nowMilli / 1000);
	Serial.print(",   K loops/sec=");
	Serial.println(KloopPerSecondAverage);
	nextMilliUpdateLcd = nowMilli + 5000;
}
void toggleLed()   //toggle led
{	digitalWrite(led, ! digitalRead(led));
	nextMilliLedToggle = nowMilli + 99;
	if (digitalRead(led) == LOW) nextMilliLedToggle = nowMilli + 4999;
}

The kludge to deal with rollover is clumsy at best.

I assume you understand the code.
For me, it is not self documenting.

.

"The kludge to deal with rollover is clumsy at best."
Thanks for your input. It's really a small piece of code. Can you show how it could work better?

This function will only run once ever 7 weeks. So how can you make it better?

Do you think it is:

6 buggy

"For me, it is not self documenting."
Thanks LarryD for looking.
Basically, each function sets the time that it should run next. When that time has come, the function will run again.
Was there a different question that you had about the code?

Which section is confusion, setup(), loop(), or another function ?

@Coding Badly,
Thanks for reviewing the code. What bugs do you see? Thanks for pointing them out for me! If you see any Bugs, where are they?

I am not the best codder (or speller), but I think this works. Have you loaded it and tried it?
Please elaborate on you "buggy" comment. I am all ears. I have had to debug many times before. Thanks for your help.

Have you got a script that can run near 140,000 times per second? Please show it.

This is kind of similar:

const unsigned long TaskAwait  = 100UL;  //Runs TaskA every 100ms
const unsigned long TaskBwait  = 500UL;  //Runs TaskB every 1/2 second
const unsigned long TaskCwait  = 1000UL; //Runs TaskC every 1 seconds
const unsigned long TaskDwait  = 2000UL; //Runs TaskD every 2 seconds

unsigned long TimeA;                     //used to calculate when 
unsigned long TimeB;                     //the associated Task
unsigned long TimeC;                     //will be run next
unsigned long TimeD;                     //
unsigned long currentMillis; 

boolean restartA = true;                 //does this task repeat
boolean restartB = true;
boolean restartC = true;
boolean restartD = true;

boolean runFlagA = true;                 //is this task scheduled?
boolean runFlagB = true;
boolean runFlagC = true;
boolean runFlagD = true;



//========================================================== 
void setup()
{
  currentMillis = millis();
  TimeA = currentMillis;                 //initialize all times 
  TimeB = currentMillis;                 //
  TimeC = currentMillis;                 //
  TimeD = currentMillis;                 //

  pinMode(13,OUTPUT);                    //
  pinMode(12,OUTPUT);                    //
  pinMode(11,OUTPUT);                    //
  pinMode(10,OUTPUT);                    //

} //>>>>>>>>>>>>>>  E N D   O F   s e t u p ( ) <<<<<<<<<<<<<<<<<

//========================================================== 
void loop()
{
  // keep this line here
  currentMillis = millis();  

  //check all Tasks to see if it is time to run them
  //*********************
  if (runFlagA && CheckTime(TimeA, TaskAwait, restartA)) 
  {
    TaskA();
  }

  if (runFlagB && CheckTime(TimeB, TaskBwait, restartB)) 
  {
    TaskB();
  }

  if (runFlagC && CheckTime(TimeC, TaskCwait, restartC)) 
  {
    TaskC();
  }

  if (runFlagD && CheckTime(TimeD, TaskDwait, restartD)) 
  {
    TaskD();
  }
  //*********************

  //Other loop code goes here


} //>>>>>>>>>>>>>>  E N D   O F   l o o p ( )  <<<<<<<<<<<<<<<<<



// FUNCTIONS
//========================================================== 

//Delay time expired function
//lastMillis = time we started, wait = delay in mS, restart = do we start again  
boolean CheckTime(unsigned long &lastMillis, unsigned long wait, boolean restart) 
{
  //is the time up for this task?
  if (currentMillis - lastMillis >= wait) 
  {
    //should this start again? 
    if(restart)
    {
      //get ready for the next iteration
      lastMillis += wait;  //get ready for the next iteration
    }
    return true;
  }
  return false;

} // END of CheckTime()

//==================
void TaskA()
{
  digitalWrite(13,!digitalRead(13));   //Toggle pin 13
  //Other stuff

} //END of TaskA()

//==================
void TaskB()
{
  digitalWrite(12,!digitalRead(12));   //Toggle pin 12
  //Other stuff

} //END of TaskB()

//==================
void TaskC()
{
  digitalWrite(11,!digitalRead(11));   //Toggle pin 11
  //Other stuff

} //END of TaskC()

//==================
void TaskD()
{
  digitalWrite(10,!digitalRead(10));   //Toggle pin 10
  //Other stuff

} //END of TaskD()



//======================================================================
//                             END OF CODE
//======================================================================

Sometimes a brain is all that is necessary to spot a problem.

Overflow bug.

Have you got a script that can run near 140,000 times per second?

void setup() 
{
  DDRB |= (1 << DDB5);

  while ( true )
  {
    PINB = (1 << PINB5);
  }
}

void loop() 
{
}

Pin 13 blinks significantly faster than 140,000 times per second on a standard Uno.

@LarryD, looks good, but can you put a loop counter in there to see how many loops per second it takes? With three functions (processes)?

@Coding Badly, I didn’t (don’t) see an overflow error.
I thought of an overflow error as a processor stack overflow. Is that what you mean?

Thanks for pointing that out. Where is it? Do you mean the millis() overflow. I thought I handled that.
if(nowMilli <700 ) processRollover();

I thought a rollover was safer than an overflow. I may not understand.

millis overflow (aka “wrap”, “rollover”).

The value “overflows” the storage space. 32 bits are available for storing the value. When millis reaches 4294967295, 33 bits are needed to store the next value. With only 32 bits available the value overflows the storage space.

I thought I handled that.

Which is why the recommendation for handling rollover is always…

CurrentValue - PreviousValue >= Delta

@Nick, thanks for your input. I always value your opinion.
I hope it was not to cold there today. It was 99F here in East Texas today.

It is 54 °F today. :slight_smile:

[quote author=jack wp link=msg=2327913 date=1437689635]
"The kludge to deal with rollover is clumsy at best."
Thanks for your input. It’s really a small piece of code. Can you show how it could work better?

This function will only run once ever 7 weeks. So how can you make it better?

[/quote]Use the standard
currentMillis - startMillis >= requiredPeriodand the rollover problem disappears. To me your method seems to offer no advantage whatsoever I am afraid.

The code in your original post seems to me to be harder to figure out than the code in several things at a time. But perhaps I am biased.

And, as far as I can see it works the same way (apart from your complex way of dealing with millis() rollover which could easily be fixed)

...R

Use the standard...and the rollover problem disappears.

It should be pointed out that that only works if "next time" is less than 7 weeks away.

If you REALLY want to do things a fixed time later, the ONLY solution is an RTC. I really can't see doing things that need to happen regularly based on elapsed milliseconds.

@PaulS
Quote:
"It should be pointed out that that only works if “next time” is less than 7 weeks away.

If you REALLY want to do things a fixed time later, the ONLY solution is an RTC. I really can’t see doing things that need to happen regularly based on elapsed milliseconds."

This is intended to simulate multi tasking, not as a scheduler.
For multi tasking, I expect the system to only use the resources required, and not produce unnecessary delays/blocking that could slow down other tasks. That is the reason I check how many times a second that loop() runs.

This script tests at 140,000 a second. I have not tested other systems, but I suspect they would be about half of that. Has anyone run a test?

@Robin2, You ask
"Please feel free to compare my code with yours and let us know the results."

I put loopCounter++; at the bottom of the loop(), in your code, and it appears to be running just under 100 loops per second.

In comparison, my script is running 140,000 times a second.

I could have read this wrong tho. It is a bit hard to believe they would be that much different.

Let us know if you get different readings. Thanks.