multitasking- not sure how to use millis()

Status
Not open for further replies.

gony

Well-known member
hello everyone
my goal is to run a code that would respond to inputs by initiating a function , but while performing the function still "listen" to inputs to see if another function should initiate .
for example , i receive a 16 bit input , 4 bits are saying i should run the reward function and the 12 remaining imply the amount of time a certain pin should remain HIGH .
so far i used delay for that time , but its occupying the program while i need it to be attentive to new assignments coming in , for example another 16 bit input with a different function to operate .
i looked online and encountered the millis() for multitasking but not sure how to use it . this is what i got so far

Code:
// PTA (12 13) = [3 4] // ready signal and XS2
// PTB (0 1 2 3) = [16 17 19 18] // For address bits
// PTC (0 1 2 3 4 5 6 7 8 9 10 11) = [15 22 23 9 10 13 11 12 35 36 37 38] // For digital inputs from NI cards
// PTD (0 1 2 3 4 5 6 7 ) = [2 14 7 8 6 20 21 5] // For digital output to marker
// PTE (25) = [34] // for digital output to reward

byte inputPins[] = {3, 4, 16, 17, 19, 18, 15, 22, 23, 9, 10, 13, 11, 12, 35, 36, 37, 38};
byte outputPIns[] = {2, 14, 7, 8, 6, 20, 21, 5, 34};
unsigned long previousMillis = 0;

IntervalTimer myTimerOne;


void reward(void) {
  if (!digitalReadFast(3)  && ((GPIOB_PDIR & 0xF) == 4)){// Received command
     Serial.println("test");
     Serial.println(GPIOC_PDIR,HEX);
     digitalWriteFast(34, HIGH);//reward
     previousMillis = millis(); //start counting until stop

  }
}



void setup() {
  Serial.begin(9600); while(!Serial);
  pinMode(34,OUTPUT);
  for (int pinnum = 0; pinnum < 18; pinnum++) {
        pinMode(inputPins[pinnum], INPUT_PULLDOWN);
    //pinMode(inputPins[pinnum], INPUT);
  }
  for (int pinnum = 0; pinnum < 9; pinnum++) {
    pinMode(outputPIns[pinnum], OUTPUT);
  }
  myTimerOne.priority(0);
  myTimerOne.begin(reward,10);
  myTimerOne.priority(0);
}

void loop() {
  unsigned long currentMillis=millis();
  if ( digitalReadFast(34) && currentMillis - previousMillis > GPIOC_PDIR) {
    digitalWriteFast(34, LOW);//reward
    
  }
  
}

do you think it can work ? i can't test it yet cause the other functions are not ready yet , but i need to know if this is a problem i'm capable of overcoming . i couldn't find anywhere a proper explanation about order of events in the software . i mean there is the void loop and the intervalTimer that are both supposed to run infintely , how does it work?
 
Normal method is sort of like what you are doing where you subtract last time you checked and get a period in milliseconds to see if your time has ellapsed. Not sure why you are doing a greater than compar to GOIOC though?

Working an a Teensy there is the ellapsedmillis function
https://www.pjrc.com/teensy/td_timing_elaspedMillis.html
Which has an example doing pretty much what you want I think and does some of the background for you since you just zero it when you need to rather than tracking previous, and believe (but have not tested) that it correctly handles the millis rollover back to zero which your example above will hit trouble with (if previousmllis is 0xFFF... and current is rolled over to 0x00... and you subtract). Ways to make it work but if writing your own you always need to think about:

Actions at program start where previous may have never been set (or be a negative number)
Action just before rollover when values are close to 0xFFF... but conclude after rollover
and when you straddle the rollover.
 
ok , good point about the rollover !
i compare to GPIOC because the input i get is the actual time i want the pin to be HIGH .
i'll examine the link you sent in the next hour , but i still didn't understand the way things go between void loop and intervalTimer .

thank you for your effort!!!
 
can someone point out links to that info ? or simply explain ?
i'm trying to understand the order of importance for the software when it comes to different functions like loop() and my own function called 'reward' which is being called by intervalTimer every 10 microseconds .

in common words , when and why does the computer leave the loop and go do something else , and when and why does it go back to the loop ?
 
i usually put a static for a reoccuring timer in a function or a local timeout timer for breaking a while loop but its as simple as this:

uint32_t myTimer = millis();

then:

if ( millis() - myTimer > 5000 ){ do something};

i usually like to trigger timers once only if needed, ex:

bool run_timer;
uint32_t myTimer;

void trigger() {
run_timer = 1;
myTimer = millis();
}

void loop() {
if ( run_timer && millis() - myTimer > 5000 ) { // greater than 5 seconds
run_timer = 0; // disable this condition
// do something
}
}
 
In Arduino terms loop is what keeps running whenever nothing else is, so at the end of loop() there is a 'goto loop();'. There is nothing stopping you making a routine called say main() and running there if that does what you need but normal process (and greatly improves chances of people helping with your code) is to have cyclic functions happen in loop().

Hidden at the end of loop is some house keeping stuff so unless you really want 100% control of what happens normal process is to stick your main code in loop and be done with it.

If you want a test engine to get your head around this may be worth looking at processing.org, which uses a lot of the same concepts and structures on your PC where it's easier to see.
 
And sniped by Tonton...

Re leaving loop, execution will depart loop if you

send it with a procedure call like if(digitalReadX,HIGH) goDoSomething();
If you have an interrupt from a system function (millis timer, serial etc)
If you have an interrupt you created with attach interupt
If you have an interrupt from a library you added (like interval timer)
At the end of each interrupt program state will be restored, and if need be you can dig in and change interrupt priority, so say system timer functions interrupt serial coms handling but not vice versa.
 
You can also play around using the new EventResponder code and setup MillisTimer

With this you can have an EventResponder object, which you set a callback function to. Probably easiest to look at some of Paul's example code for this.

But you would have something like:
Code:
#include <EventResponder.h>
   EventResponder event1;
   MillisTimer millis1;
...

void setup() {
    event1.attachImmediate(&myfunc1);
...
}

void myfunc1(EventResponderRef eventref) {
    digitalWriteFast(34, LOW);
}

void loop() {
...
    digitalWriteFast(34, HIGH);
    millis1.begin(millis_delay, event1);  // Where millis_delay is how long before you wish for the event to be triggered. 
...
 
Status
Not open for further replies.
Back
Top