Learning millis() - puzzling result?

While learning the basics about the millis() function I'm using this code (all inside setup to minimise distraction for a while). But why does it return zero instead of something over 3000 as I'd expected?

void setup()
{
  Serial.begin(9600);
  Serial.println("Start print");
  if (millis() > 3000UL)
  {
    Serial.print("millis is now -> ");
    Serial.println(millis());
  }
}
void loop() {}

Terry, East Grinstead, UK

Because setup() runs once only, so at the moment when it evaluates if (millis() > 3000UL) the system has just started so millis() returns 0 or maybe 1ms. And it never goes near that if again.

Put it in loop() and after a while it will be > 3000.

While learning the basics about the millis() function

Have you read Using millis() for timing. A beginners guide ?

Or, if you just want to test your theory, add a delay(5000); right after Serial.begin(9600);

UKHeliBob:
Have you read Using millis() for timing. A beginners guide ?

Yes

Terry, East Grinstead, UK

Upload the following sketch (yours one with slight modification). Study the result of the Serial Monitor and then figure out why you are getting 0 when your sketch is uploaded.

void setup()
{
  Serial.begin(9600);
  Serial.println("Start print");
  if (millis() != 3000UL)
  {
    delay(200);
    Serial.print("millis is now -> ");
    Serial.println(millis());
  }
}
void loop() {}

DangerToMyself:
Or, if you just want to test your theory, add a delay(5000); right after Serial.begin(9600);

Thanks, tried that but why would that delay apparently get doubled?

void setup()
{
  Serial.begin(9600);
  delay(5000);
  Serial.println("Start print");
  if (millis() > 10UL)
  {
    Serial.print("millis is now -> ");
    Serial.println(millis());
  }
}
void loop() {}

// From clicking Upload to the following appearing in the
// monitor took 10s, not 5s as I'd expected
// Same whatever the millis() value.

// 11:58:52.912 -> Start print
// 11:58:52.912 -> millis is now -> 5000

Terry, East Grinstead, UK

Because upload includes compiling the sketch and uploading it before it runs.

The output you have does show that it took 5s from when it started running...

11:58:52.912 -> millis is now -> 5000

Run it again now that it's uploaded: just close and re-open the monitor. Result in the monitor will be the same, but total elapsed time will be closer to the 5s.

sayHovis:
Because setup() runs once only, so at the moment when it evaluates if (millis() > 3000UL) the system has just started so millis() returns 0 or maybe 1ms. And it never goes near that if again.

Put it in loop() and after a while it will be > 3000.

Thanks, I now see why I don't get what I previously expected, a number over 3000. But why would my code deliver any result? I would now expect it to print nothing, because the IF is not satisfied and there are no further commands afterwards.

Terry, East Grinstead, UK

1. When uploading of a ketch sketch (edit) is finished in the Arduino UNO, a timer is started in the background which updates the following (Fig-1) 32-bit wide (unsigned) counter at 1 ms interval. The intial value of the Counter is 0.
millisCounter.png
Figure-1:

2. The timer of Step-1 has started at time t1 = 0; now at time t2, we wish to know how much milliseconds have elapsed -- that means we want to know the time difference between t2 and t1 (t2 - t1). This requires us to know the content of the Counter of Fig-1 at time t1 and t2.

3. The content of Counter can be known by executing the following code; where, the Arduino function millis() returns the current content of the Counter into variable elapsedTime.

unsigned long elapsedTime  =  millis();

Hope, the above information will he helpful to understand the posted examples. (ul stands for unsigned long: 0x00000000 - 0xFFFFFFFF = 0 - 4294967295)

millisCounter.png

GolamMostafa:
When uploading of a ketch.....

One of these? :wink:

+1k. I have learnt a new word not by miracle; but, by virtue of being a member of this Forum.

sayHovis:
Because upload includes compiling the sketch and uploading it before it runs.

The output you have does show that it took 5s from when it started running...

11:58:52.912 -> millis is now -> 5000

Run it again now that it's uploaded: just close and re-open the monitor. Result in the monitor will be the same, but total elapsed time will be closer to the 5s.

Thanks for your patience! Maybe I need more coffee before I get it, because after doing what you suggest the delay before print appears is consistently about 2s, not 5s, and I don't see why.

The monitor shows two lines:
12:33:16.176 -> Start print
12:33:16.377 -> millis is now -> 199

Terry, East Grinstead, UK

But why would my code deliver any result? I would now expect it to print nothing, because the IF is not satisfied and there are no further commands afterwards.

It prints only the "Start print" text when I run it. I assume that you see that text too

Terrypin:
But why would my code deliver any result? I would now expect it to print nothing, because the IF is not satisfied and there are no further commands afterwards.

When I ran your original code all I got was "Start print". Are you saying it went into the "if" even though millis()<3000 and printed a smaller value?

@UKHeliBob
@sayHovis

My bad. Trying too many suggestions in quick succession and I'd changed 3000UL to 10UL temporarily. I now get the same result as you both.

Still head scratching over the 2s v 5s puzzle though. Maybe mushrooms-on-toast for lunch will sort it...

Terry, East Grinstead, UK, 13:05

Terrypin:
Still head scratching over the 2s v 5s puzzle though.

Now I'm confused.... what 2 vs 5s puzzle?

Terrypin:
'shrooms-on-toast for lunch will sort it...

... or maybe you had too many already :wink:

@sayHovis:

I'm not surprised you're confused. Instead of fewer mushroom maybe I should implement fewer suggestions so quickly. They got scrambled.

Answering your question:
In post #7 you said:

"Run it again now that it's uploaded: just close and re-open the monitor. Result in the monitor will be the same, but total elapsed time will be closer to the 5s."

In post #12 I replied:

"...after doing what you suggest the delay before print appears is consistently about 2s, not 5s, and I don't see why."

But I'm now sure that instead of running your "it" (by which I assume you meant my original code) I ran either the change suggested by @DangerToMyself or the "slight modification" suggested by @GolamMostafa.


I'm going to methodically test my original again followed by your suggestion about re-opening the monitor and I'll report back shortly.

Terry, East Grinstead, UK

Re-opening the monitor causes a reset so millis() starts at 0 again. But since the time between you clicking to open the monitor and the program starting is very short, the 5s reported in the monitor will be very close to the time you would see on your watch after you click.

But hitting upload causes the sketch to re-compile (takes time) and upload afresh (takes time) so when millis() starts counting and displays your 5000ms, some extra seconds for the compile and upload have to be added to your elapsed (watch) time.

Let me run OP's original code having added this line: Serial.print(millis()); before going to loop() function, I get 0 on the Serial Monitor -- that is what the OP was saying.

void setup()
{
  Serial.begin(9600);
  Serial.println("Start print");
  if (millis() > 3000UL)
  {
    Serial.print("millis is now -> ");
    Serial.println(millis());
  }
  Serial.println(millis());
}
void loop() {}

smnxa.png

That means that the elapsed time from clicking the upload button and arriving at the end of of setup() function is less than 1 ms and greater than 0 which can not be known by the millis() function. How much it is? The following program has calculated it as: 101.625 us.

void setup()
{
  Serial.begin(9600);
  //----------------------------
  TCCR1A = 0x00;   //Normal UpCounting Mode
  TCCR1B = 0x00;  //T1 is OFF
  TCNT1 = 0x00;   //Initial Value
  TCCR1B = 0x01;  //16 MHz TC1 is ON
  //-------------------------------
  Serial.println("Start print");
  if (millis() > 3000UL)
  {
    Serial.print("millis is now -> ");
    Serial.println(millis());
  }
  TCCR1B = 0x00;  //TC1 is OFF
  Serial.println(TCNT1, DEC);  //execution time as cycles --> 1626*1/16000000 = 101.625 us.
  Serial.println(millis());
}
void loop() {}

smnxa.png