Go Down

Topic: (SOLVED) synchronicity strangeness (Read 3339 times)previous topic - next topic

kaporal_p

Aug 22, 2011, 04:33 amLast Edit: Aug 24, 2011, 07:31 pm by kaporal_p Reason: 1
hi,

I'm practicing with millis() and got on something I can't undurstand.

I modified the Blink Without Delay to accomodate 3 LEDs.

If I put 3 different intervals

Code: [Select]
`long interval5 = 1000;           // interval at which to blink (milliseconds)long interval6 = 2000;long interval7 = 3000;`

the LEDs start blinking in sync and after about 1 minute get out of sync.

but then,

If I put 3 times the same interval

Code: [Select]
`long interval5 = 1000;           // interval at which to blink (milliseconds)long interval6 = 1000;long interval7 = 1000;`

the LEDs never get out of sync!

I first thought that since the code for each LED passes through the loop turning them on or off one after the other, the small difference in the order of appearance slowly accumulates and ends up busting the pattern, but then the same would happen with equal intervals.

what am I missing?

here's the code
Code: [Select]
`// constants won't change. Used here to// set pin numbers:const int ledPin5 =  5;      // the number of the LED pinconst int ledPin6 =  6;const int ledPin7 =  7;// Variables will change:int ledState5 = LOW;             // ledState used to set the LEDint ledState6 = LOW;int ledState7 = LOW;long previousMillis5 = 0;        // will store last time LED was updatedlong previousMillis6 = 0;long previousMillis7 = 0;// the follow variables is a long because the time, measured in miliseconds,// will quickly become a bigger number than can be stored in an int.long interval5 = 1000;           // interval at which to blink (milliseconds)long interval6 = 2000;long interval7 = 3000;void setup() {  // set the digital pin as output:  pinMode(ledPin5, OUTPUT);  pinMode(ledPin6, OUTPUT);  pinMode(ledPin7, OUTPUT);   }void loop(){  // here is where you'd put code that needs to be running all the time.  // check to see if it's time to blink the LED; that is, if the  // difference between the current time and last time you blinked  // the LED is bigger than the interval at which you want to  // blink the LED.  unsigned long currentMillis5 = millis();  unsigned long currentMillis6 = millis();  unsigned long currentMillis7 = millis();             if(currentMillis5 - previousMillis5 > interval5) {    // save the last time you blinked the LED    previousMillis5 = currentMillis5;    if (ledState5 == LOW)      ledState5 = HIGH;    else      ledState5 = LOW;    digitalWrite(ledPin5, ledState5);     }   if(currentMillis6 - previousMillis6 > interval6) {    // save the last time you blinked the LED    previousMillis6 = currentMillis6;    if (ledState6 == LOW)      ledState6 = HIGH;    else      ledState6 = LOW;    digitalWrite(ledPin6, ledState6);     }   if(currentMillis7 - previousMillis7 > interval7) {    // save the last time you blinked the LED    previousMillis7 = currentMillis7;      if (ledState7 == LOW)      ledState7 = HIGH;    else      ledState7 = LOW;    digitalWrite(ledPin7, ledState7);    }}`

thanks

Grumpy_Mike

#1
Aug 22, 2011, 10:05 am
Code: [Select]
`unsigned long currentMillis5 = millis();  unsigned long currentMillis6 = millis();  unsigned long currentMillis7 = millis();`
Is wrong, only have one value of currentMillis to compare all the LED times.
What happens is that you can get a change in the value between one and the next

kaporal_p

#2
Aug 23, 2011, 06:14 pm
Hi,

Quote
have one value of currentMillis to compare all the LED times

this is so obviously logic!

modified the code right away and... no, not synchronized!?

Also, if that was the problem, then, when I put the 3 intervals to the same value

Code: [Select]
`long interval5 = 1000;           // interval at which to blink (milliseconds)long interval6 = 1000;long interval7 = 1000;`

they would also get out of sync.

this difference is what makes this wak, they stay syncronized with the same interval value...

I also tried rewiring the thing to other pins, didn't do anything

AWOL

#3
Aug 23, 2011, 06:50 pm
Quote
what am I missing?

Arrays (possibly structs or classes) and for loops
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.
I speak for myself, not Arduino.

kaporal_p

#4
Aug 23, 2011, 10:59 pm
AWOL;
ok I'll try to rewrite the program and put everything in little boxes (arrays). First I wanted to check if the program worked and I thought of doing this later on (to rewrite it in a nicer way), but then it desyncronized so fast I thought something must be wrong.

KE7GKP:
Quote
It is not clear whether this is just an abstract, generic, academic exercise or whether you are trying to ELIMINATE this gradual loss of sync, or maybe whether you are trying to PROGRAM some gradual randomness?

I am really trying to eliminate the loss of sync. But the reason I want this is purely holistic, I often need millis() and am in a learning process about them, this program for me is an introduction. I don't need those synced LED's themselves, but I need the knowledge to get them syncronized since I always need syncronized things ; )

thanks

Grumpy_Mike

#5
Aug 24, 2011, 06:09 am
Got it I think.
Change the :-
if(currentMillis5 - previousMillis5 > interval5){
to
if(currentMillis5 - previousMillis5 >= interval5)
in all three instances and it will work.

I will leave it to you to decide why, it's quite a nice penny dropping moment.
Ask if you can't get it.

dc42

#6
Aug 24, 2011, 09:36 am
I think Mike's solution should work, given that the time for one iteration of the loop should be much less than 1ms. You could also change:

previousMillis5 = currentMillis5;

to:

previousMillis5 += interval5;

and similarly for the other 2 similar lines.
Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

kaporal_p

#7
Aug 24, 2011, 07:30 pmLast Edit: Aug 24, 2011, 07:34 pm by kaporal_p Reason: 1
Nice, it works!

what I get is that it was necessary to wait for the iteration of the loop() that came right after the one that made the interval condition true, so if I was ''adding'', say, 1ms at every iteration, that means;

Code: [Select]
`long interval5 = 1000;           // adding 3ms every 3 secondslong interval6 = 2000;           // adding 1.5ms every 3 secondslong interval7 = 3000;           // adding 1ms every 3 seconds`

hence the out-of-syncness.

this also means that with equal intervals of, say, 1000ms, all the blinks were also being offset by 1 ms, but alltogether, rendering the effect unperceptible.

Also, I don't know, but shouldn't the code for the example of the blink without delay be modified like this. It seems to me this is a better way of writing it.

great,

many thanks to all of you.

Grumpy_Mike

#8
Aug 24, 2011, 09:45 pm
Close.
What is happening is that you don't get the action until the millisecond after the time so
1000 times out in 1001 mS
2000 times out in 2001 mS
3000 times out in 3001 mS
As they are no longer multiples of each other they will not be in sync.

If you want to prove this then use the original program and set the times to:-
999
1999
2999
If they stay in sync that's it.

Note you need to see the millis() clock every milli second. If not then calculate the next time not from the current value of millis() but from the last threshold. That is add the time period to the threshold you previously calculated not the current clock. This keeps things in sync.

kaporal_p

#9
Aug 26, 2011, 08:57 pm
Quote
If you want to prove this then use the original program and set the times to:-
999
1999
2999
If they stay in sync that's it.

LED's in sync. So it's all aquestion of understanding where the treshold happens and how long (1millis) the program waits before giving the go to the next timer.

Quote

Note you need to see the millis() clock every milli second. If not then calculate the next time not from the current value of millis() but from the last threshold. That is add the time period to the threshold you previously calculated not the current clock. This keeps things in sync.

I'm not sure I understand what you mean here. Is it that it could happen that the millis() clock could sometimes be unavailabe(because of interrups I guess)? But I don't get how to go around the millis() clock, whatever you take as a reference point, you still use the same clock!? Hmm, I'm missing something again

Grumpy_Mike

#10
Aug 26, 2011, 10:24 pm
Quote
So it's all aquestion of understanding where the treshold happens

If you wait until the millis() time is greater than the threshold then it happens the millisecond AFTER you want it to happen. By making it equals it happens at the exact time. Add the greater than as well in case something goes wrong and you over shoot it so use >= instead of ==. At the moment == will work just as well but it is not good practice to leave such a hostage to fortune.

Quote
Is it that it could happen that the millis() clock could sometimes be unavailabe

Not quite what I am saying is supposing you add some extra code in your loop, and that code takes longer than 1mS to execute then you could get out of sync because when you do this:-

Code: [Select]
` if(currentMillis5 - previousMillis5 > interval5) {    // save the last time you blinked the LED    previousMillis5 = currentMillis5;`
You are setting the LED to change at a time interval5 from now. BUT now is not in exact sync because of the extra time you took in the other code. So to get round this you do:-
Code: [Select]
` if(currentMillis5 - previousMillis5 > interval5) {    // save the last time you blinked the LED    previousMillis5 += interval5;`
This keeps the time slices exact even if you are late in updating the next interval.

Go Up