You millis() code is not structured correctly. Lets look at what happens:
timeA and co are all initiated with the value 10. So as soon as the program has run 10ms, the first if statement (the one for state 0) will execute. First you increment state, so that the next state can be reached. Then you have a for loop without any timed code. It will execute very very fast, without giving the PWM hardware any chance to actually output the analogWrite() values. Then you update timeA (which normally wouldn't go into the for loop). We leave the if statement and reach the next one. Nearly no time has passed, since we entered the first if statement. And now we are executing the next if statement, since state is now 1 and the program had run for more than 10ms. Here it is the same as above.
So the program is rushing through the analogWrite() calls ending in the last one, since state is never reset, giving the last analogWrite() value the change to be output on the pin.
The whole structure of the code does not really make sense. I guess you wanted to do this non-blocking, thus using millis(). For loops are not really fitting to this and the millis() value has to be compared to the right values to get the order right.
What to do now: With the state variable you nearly have something that is called Finite State Machine (FSM). It is a powerful programming concept. Basically the state of the program decides, what block of code should be executed on each loop() iteration. This is best done via a switch statement. Then in each case we are using an if statement using the millis() value to decide, if it is time to execute the new analogWrite():
void setup()
{
pinMode(3, OUTPUT);
pinMode(5, OUTPUT);
pinMode(6, OUTPUT);
}
void loop(){
static unsigned long timeA = 10;
const long interval = 10;
static unsigned long timeB = 10;
const long interval2 = 10;
static unsigned long timeC = 10;
const long interval3 = 10;
unsigned long delay = millis();
static unsigned long state = 0;
static int i = 0;
switch(state){
case 0:
if(delay - timeA >= interval){
analogWrite(3, i);
analogWrite(5, 0);
analogWrite(6, 0);
i++;
timeA = delay;
}
if(i > 255){
state = 1;
i = 0;
}
break;
case 1:
if(delay - timeB >= interval2){
analogWrite(3, 0);
analogWrite(5, i);
analogWrite(6, 0);
i++;
timeB = delay;
}
if(i > 255){
state = 2;
i = 0;
}
break;
case 2:
if(delay - timeC >= interval3){
analogWrite(3, 0);
analogWrite(5, 0);
analogWrite(6, i);
i++;
timeC = delay;
}
if(i > 255){
state = 0;
i = 0;
}
break;
}
}
By setting the variable state we can choose, what should be executed next. The variable i is handling the fading of each LED, while the interval variables set how fast the fading occurs. This coding principle can be used in many different situations, so learning it is really worth it.
Note:
- I have not tested the above code.
- The code can still be optimized/generalized.
forloop, you will also need to usedelay()to create the correct timing of the fading. I assumed, that you didn't want to usedelay()(which is a good thing for adding more features in the future).forloops are just one way to create loops. There are others and the above code principle should also work. It is up to you, if you want to usefor(and thusdelay(), creating a blocking code) or the above code structure (and thus a non-blocking code) – chrisl Sep 07 '21 at 15:35