Pages: [1]   Go Down
Author Topic: Change request example code "Blink Without Delay"  (Read 1144 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Newbie
*
Karma: 0
Posts: 12
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The example code for "Blink Without Delay" will show a glitch in time over the blink itereations. This happens becaus there is some calculation time between the two subsequent millis()-calls. That means between
   <code> if (millis() - previousMillis > interval) </code>
and
   <code> previousMillis = millis();  </code>

I suggest to change example from
   <code> previousMillis = millis();  </code>
to
   <code> previousMillis = previousMillis+interval;  </code>

That gives us a constant time distance for each comparison and uses only one millis() call. That may be important if some wants to play with the interval values or needs a somewhat synchronised blink frequency.
Logged

New York, NY, USA
Offline Offline
Newbie
*
Karma: 0
Posts: 40
Howdy. I don't check PMs often, so email me!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I'll try it when I've got a board in front of me next. Seems like a reasonable change, as long as the time between checks is never significantly larger than the interval, for any reason.
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 547
Posts: 45982
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Another solution is to store the current time, and use that value throughout the block:

Code:
unsigned long currentMillis = millis();
if(currentMillis - previousMillis > interval)

Code:
previousMillis = currentMillis;

This way, it doesn't matter how long the action part of the loop is. The recorded time is the start of the block, if that's what you want.
Logged

New York, NY, USA
Offline Offline
Newbie
*
Karma: 0
Posts: 40
Howdy. I don't check PMs often, so email me!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I like that last solution even better, since it is consistent with what we do in the state change detection example. I'll put that in the SVn for the next version, thanks.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 1
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I just got my Arduino and loaded up the sketch for the first time, so it's possible I may be missing something, but the comments about  interval needing to be a long variable are wrong aren't they?
Quote
// Variables will change:
int ledState = LOW;             // ledState used to set the LED
long previousMillis = 0;        // will store last time LED was updated

[glow]// 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 interval = 1000;           // interval at which to blink (milliseconds)[/glow]

the comment would apply to the previous variable (previousMillis)
but as writen interval might as well be a constant no?
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 12
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

@PaulS : No that will not do it. Becaus your sugesstion has a kind of a jitter of reading millis() depending on loop execution time.

My solutions provides an absolut "correct" line of trigger point for time comparison:

For ilustration example some asumptions befor entering the loop :
    interval =1000 (msec)
    first previousMillis= 1300 (msec)

Then two cases

1) my code delivers a line of previousMillis like that : 1300, 2300, 3300, 4300, 5300, ..... = 1300 + n * 1000.

2) your example might show something like this for previousMillis : 1300, 2301, 3305, 4307, 5311, .....  = 1300 + n *(1000+jitter)
The jitter error will accumulate over the loops.
The reason while we have that jitter is, that we never have
 (currentMillis - previousMillis) == interval !!! Only in that case, we have the timeline like example 1.

You can test your code by replacing the if block with (havn´t compiled it by my own) to show the jitter
Code:
unsigned long currentMillis = millis();
if(currentMillis - previousMillis > interval) {
previousMillis = currentMillis;
Serial.println (currentMillis - previousMillis - interval);
}
This should show a row of zeros, if the code is fine.

Well the error is quite small, but look what will happen, if the interval is set to interval = 20 ? The we have a much bigger error accumulation during the loops. If we try to build relieable controler software, we have to take care for predicticality.
Ditmar
Logged

Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 176
Posts: 12285
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Because your sugesstion has a kind of a jitter of reading millis() depending on loop execution time.
The Blink Without Delay code does have "jitter" (I prefer to call it "drift") but the change suggested by PaulS eliminates it.

Quote
This should show a row of zeros, if the code is fine.
I have the PaulS code running now and it returns a row of zeros...

Code:
const unsigned long interval = 1000;

unsigned long previousMillis;
unsigned long delta;


void setup( void )
{
  Serial.begin( 9600 );
  pinMode( 6, OUTPUT );
  digitalWrite( 6, LOW );
  delay( 3000 );
  digitalWrite( 6, HIGH );
  previousMillis = millis();
}

void loop( void )
{
  unsigned long currentMillis = millis();
  
  if( currentMillis - previousMillis >= interval )
  {
    delta = currentMillis - previousMillis - interval;

    if ( delta != 0 )
    {
      digitalWrite( 6, LOW );
      Serial.println( delta );
    }
    previousMillis = currentMillis;
  }
  
  if ( Serial.available() )
  {
    while ( Serial.available() )
    {
      Serial.read();
    }
    digitalWrite( 6, HIGH );
  }
}

The difference between your code and the code suggested by PaulS is how overruns are handled.  Your code will run twice in quick succession (number of runs over a given time span is preserved).  The code from PaulS skips overruns (delay between runs is preserved).  There is nothing wrong with either version.  It's simply a matter of choosing which is appropriate for the application.
Logged

Pages: [1]   Go Up
Jump to: