Pages: [1]   Go Down
Author Topic: (SOLVED) synchronicity strangeness  (Read 1827 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 55
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
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:
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:

// constants won't change. Used here to
// set pin numbers:
const int ledPin5 =  5;      // the number of the LED pin
const int ledPin6 =  6;
const int ledPin7 =  7;

// Variables will change:
int ledState5 = LOW;             // ledState used to set the LED
int ledState6 = LOW;
int ledState7 = LOW;
long previousMillis5 = 0;        // will store last time LED was updated
long 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
« Last Edit: August 24, 2011, 12:31:21 pm by kaporal_p » Logged

Manchester (England England)
Offline Offline
Brattain Member
*****
Karma: 596
Posts: 33288
Solder is electric glue
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
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
Logged

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 55
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
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
Logged

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 285
Posts: 25646
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
what am I missing?
Arrays (possibly structs or classes) and for loops   smiley-yell
Logged

"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.

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 55
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged

Manchester (England England)
Offline Offline
Brattain Member
*****
Karma: 596
Posts: 33288
Solder is electric glue
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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. smiley
Logged

United Kingdom
Offline Offline
Tesla Member
***
Karma: 223
Posts: 6593
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

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.

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 55
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
long interval5 = 1000;           // adding 3ms every 3 seconds
long interval6 = 2000;           // adding 1.5ms every 3 seconds
long 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.
« Last Edit: August 24, 2011, 12:34:27 pm by kaporal_p » Logged

Manchester (England England)
Offline Offline
Brattain Member
*****
Karma: 596
Posts: 33288
Solder is electric glue
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 55
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged

Manchester (England England)
Offline Offline
Brattain Member
*****
Karma: 596
Posts: 33288
Solder is electric glue
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
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:
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.
Logged

Pages: [1]   Go Up
Jump to: