millis() tutorials?

Are there any tutorials out there on timing for the Arduino?

A couple of the projects that I'm working on (simple pushbutton = action generated by the arduino type stuff) are going to require me to time things to work LEDs.

For example. One project is a MIDI controller for a device. Certain button presses create an audio loop, and other button presses stop this audio loop. I can tie the LED to the button states there no problem. But I can also make it only "play once" so it would stop once the loop has finished. So I'd need to keep track of the original loop length. That doesn't seem too difficult, but there are halfspeed and reverse functions as well, which will, at least to me, seem to complicate where/when the time is.

I could probably wrap my head around getting it to do the simple functions, but I have no idea how you could get it to update for halfspeed/reversing of a timeline. Halfspeed seems like you would just add a multiplier to the formula that decides when to turn things on off, but reverse time confuses me, much less combining the two.

Also, I don't know how one would go about making an LED flash when ON, instead of just being ON, while still running other code/receiving input. I'm assuming an interrupt of some kind? I'm not sure how it works, and it sounds over my head. Is there some kind of LED/blinking library that can handle that stuff for you?

Sorry for the run-on question(s) with no code posted. I have code for the project I'm working on, but none of it has timing/millis involved at the moment as I don't know how to start.

I'll just give explanation number ## on how to use millis for timing (this has been repeated half a dozen times in the past month now, but oh well):

millis() returns an unsigned long, this is a number that can count in milliseconds and go for over a month without reaching its limit. The 'unsigned' part says that it can't go into negative numbers, it will always be positive (without unsigned, half of your capacity will be used to allowing negative numbers). If the number would reach its maximum, it will turn back to 0 (called 'roll-over'), more on this later, it goes to 0 because it is unsigned (can't go negative, otherwise it goes to the lowest possible number).

This is all fine and dandy, but how to use it? millis() returns the time the arduino has been running in milliseconds. If with each iteration of loop, or each call to your function, you save the current time (in an unsigned long), you can compare the times. currentTime - pastTime = timePassed. Remember the roll-over thing? even if pastTime is a very large number, and currentTime is very tiny, you'd end up with a very large negative number.. but it can't handle negative, which makes it 'roll over' again, producing a small number, which is the correct number of milliseconds that have passed, so it is safe against roll-over.

Ok, now you have the number of milliseconds that have passed since the previous call of loop, or the function, how to use this? If you save the number of milliseconds it has to wait in a variable, and you remember at what part of the process you were, it is easy to proceed, no? A small example in code (please copy-paste in your editor to get all the text and such lined up properly) using a technique called a 'state engine', it is as simple as seen, you can check it on wiki if you want to know more, anyways.. the code:

unsigned long currentTime  = 0; //this variable will be overwritten by millis() each iteration of loop
unsigned long pastTime     = 0; //no time has passed yet
int           currentState = 0; //the default state
int           wait         = 0; //no need to wait, nothing has happened yet

void setup()
{
  pinMode(13, OUTPUT); //the LED we're going to blink.. I just put 13 in as a magic number so it doesn't spoil the view of the worthwhile millis code
}

void loop()
{
  pastTime    = currentTime; //currentTime at this point is the current time from the previous iteration, this should now be pastTime
  currentTime = millis();    //currentTime is now the current time (again).
  
  unsigned long timePassed = currentTime - pastTime; //this is roll-over proof, if currentTime is small, and pastTime large, the result rolls over to a small positive value, the time that has passed

  if(timePassed >= wait) //part1 of the state engine
  {
    switch(currentState) //part2 of the state engine, its this simple, an if and a switch
    {
      case 0:                   //the default state.. turn the led on!
        digitalWrite(13, HIGH); //light the LED up!
        wait         = 500;     //wait 500 milliseconds before doing something from this state engine again
        currentState = 1;       //the next state that should be executed is 1
        break;                  //break out of the switch, else it'll execute the case below this one too

      case 1:
        digitalWrite(13, LOW);  //turn the LED off again
        wait         = 500;     //wait 500 milliseconds again before turning the LED on again
        currentState = 0;       //turning the LED on again is done in state 0
       break;
    }
  }
}

I hope this was helpful and easy to follow, comments are welcome..

The current - past = passed makes sense, but how would that factor in with time that runs backwards.

For example. An event happens, then 5 seconds later, another event happens. Using the time - time, I can figure out that was 5 seconds, and act accordingly.

But what happens if I want something to happen every 5 second (rather, every time that loop happens), but half way through the loop I slow it down to have speed, then go reverse for 1second, then go back forwards. How do you keep track of time in that manner that will allow to do that? I guess keeping an extra variable and when direction is changed, it keeps track of how long the direction was changed for (and if ever flipped back) then that's added to the time - time formula?

Makes my head spin!

Makes my head spin!

Maybe watch the movie "Back to the future" and it will all make sense ;D

Lefty

Well, if you do the timePassed thing at the beginning of loop, you can modify that value based on what you want to do.
The rest you want to do would all use this time reference, else you’ll just be making things difficult for yourself.

What you want to do requires a slight adjustment of the generic ‘tutorial’ (if you’d like to call it that) that I posted earlier.
Instead of checking whether timePassed exceeds wait, you subtract timePassed from wait, and check if wait <= 0.
This way, you can ‘reverse’ time to increase wait… what it won’t do is reverse into previous states, while it would be possible to make it do this… it might be a bit complex for you at this point, though I could try and explain how I’d do it if you really want me to…

What I might do for the time being, is get the generic code plugged in, and then just make the code turn off all LEDs when halfspeed/reverse kick in, so the LEDs would always be correct, unless I do that.

Then once I understand more, I'll get the LEDs working up to snuff.