You need to maintain more state information to have 'case 3' work like a KITT-style back and forth LED scanner. I think you can do it with three state variables, j for which pair of LEDs is active, backwardsScan to say which way to go, and timer4 to remember where in the 91ms cycle we are with the active pair of LEDs.
Try something like this:
...
int backwardsScan = 0;
...
case 3: // KITT-like scanning back and forth 90us/1us
// j remembers which LED pair is active
// backwardsScan remembers which direction to scan
// timer4 handles the 90ms/1ms on-off cycle.
//
// reset output leds appropriately for (j,timer4):
for(int ii=0;ii<=5;ii++){
digitalWrite(ledArray[ii],( (ii==j) && (timer4 <90)));
}
// update KITT state based on (j,backwardsScan,timer4)
if(timer4 > 91){
j += backwardsScan? -1 : 1 ;
if (j > 5){
backwardsScan = 1;
j = 5;
}
if (j < 0) {
backwardsScan = 0;
j = 0;
}
timer4 = 0;
}
break;
The main trick with state machines is being able to fully determine the complete state from what you are keeping track of--It should be memoryless, in that the state variable(s) fully specify the state, and you don't need to remember the prior state. If you find you need to know more than one thing, you might need a vector or set of state variables. One could map the whole led-backwardsScan-timer4 state vector into a single state variable (timer4, modulo 182ms for example,) but that would be unnecessarily complicated. Recognizing all the variables required to fully specify the state is important.
Answer from Dave X on Stack ExchangeI'm thinking about writing an article* about how to implement cooperative multi-tasking on Arduino-compatible microcontrollers. Working title: Beyond "Blink without Delay". Much of the article will talk about ways structure a program to simplify the handling of multiple concurrent "tasks" with different timing requirements, based on my own experience.
At a lower level, I'd like to discuss the pros and cons of the various methods to measure task time intervals. At minimum I'll cover the blink-without-delay method based on millis(), as well as the elapsedMillis library. I've tried a few different methods, including the Ticker library, but have come to rely exclusively on elapsedMillis for all my projects. But before I go off and profess my love for elapsedMillis, I'd like to get your input.
For reference, here's a brief synopsis of the blink-without-delay/millis() method:
unsigned long currentTime, previousTime;
unsigned int taskDelay = 300;
void loop() {
currentTime = millis();
if ((currentTime - previousTime) > taskDelay) {
previousTime = currentTime;
// Perform task
}
} And here's the elapsedMillis equivalent:
elapsedMillis taskTimer;
unsigned int taskDelay = 300;
void loop() {
if (taskTimer > taskDelay) {
taskTimer = 0;
// Perform task
}
}The key advantage of the elapsedMillis method is that the code is more concise and readable. It also eliminates any perceived issue with millis() rollover (which isn't really an issue with unsigned variables).
A disadvantage is the minor "time slippage" that occurs in the delay between the compare if (TaskTimer > TaskDelay) and resetting the timer taskTimer = 0. This is only an issue if the cumulative delays need to maintain long-term timing accuracy (a rare situation I think).
In addition to "going deep" on the two methods shown above, I'l also provide a brief survey of other timing methods, including Ticker and also the EVERY_N_MILLISECONDS method provided by the FastLED library.
What do you folks think? What's your preferred method, and why?
*If you want to see examples of my other articles, check here.