1

Why I can't use "timeA = delay" to make the lights turn on gradually. The problem is that the delay don´t work, and the led light goes directly to the last color. What I need to do in my code to fix this?

Here is my code ↓

// C++ code
//

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; int i = 0;

if(delay - timeA >= interval && state == 0){ state += 1; for(i=0;i<=255;i++){ analogWrite(3, i); analogWrite(5, 0); analogWrite(6, 0); timeA = delay; } } if(delay - timeB >= interval2 && state == 1){ state += 1; for(i=0;i<=255;i++){ analogWrite(3, 0); analogWrite(5, i); analogWrite(6, 0); timeB = delay; } } if(delay - timeC >= interval3 && state == 2){ state += 1; for(i=0;i<=255;i++){ analogWrite(3, 0); analogWrite(5, 0); analogWrite(6, i); timeC = delay; } }

}

Ian Rapini
  • 11
  • 2

2 Answers2

1

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.
chrisl
  • 16,257
  • 2
  • 17
  • 27
  • Thank you bro! But one more doubt, Can´t I use "for" in that case? 'Cause are a college work that I need to use it. – Ian Rapini Sep 07 '21 at 14:23
  • 1
    If you use a for loop, you will also need to use delay() to create the correct timing of the fading. I assumed, that you didn't want to use delay() (which is a good thing for adding more features in the future). for loops 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 use for (and thus delay(), creating a blocking code) or the above code structure (and thus a non-blocking code) – chrisl Sep 07 '21 at 15:35
0

I think below is what you were going for. I removed the for-loop and used a static i variable to have each state take 256 intervals. Note that you don't need to have separate timeA/B/C variables. Using a single one would also make sure that the first "delay" actually occurs. It's not that critical for fading an led, but in other cases it might.

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;

static unsigned long state = 0; static int i = 0;

unsigned long delay = millis();

if(delay - timeA >= interval && state == 0){ analogWrite(3, i); analogWrite(5, 0); analogWrite(6, 0); timeA = delay;

i++;
if( i==256 )
{
  i=0;
  state++;
}

} if(delay - timeB >= interval2 && state == 1){ analogWrite(3, 0); analogWrite(5, i); analogWrite(6, 0); timeB = delay;

i++;
if( i==256 )
{
  i=0;
  state++;
}

} if(delay - timeC >= interval3 && state == 2){ analogWrite(3, 0); analogWrite(5, 0); analogWrite(6, i); timeC = delay;

i++;
if( i==256 )
{
  i=0;
  state++; // you probably want to use `state=0;`, so it starts over again
}

}

}```

Gerben
  • 11,286
  • 3
  • 20
  • 34