How to set a value for millis()?

millis() returns the "time passed" since the last boot/upload/restart.
I would like to change its value in runtime.

I cannot use a variable to solve this because it would cause the breaking/modification of existing code.

Is it possible to set the current value of millis()?

Since that isn't the intended use for millis(), I guess a question would be why do you need to change it?

Create a MyMillis() function like this, may be wrapped in a class

unsigned long MMdelta = 0L;

unsigned long MyMillis()
{
  return millis()- MMdelta;
}

void MMReset(unsigned long val = 0L)
{
  MMdelta = millis() - val;  
}
////////////////////////////////////////////
void setup()
{
  Serial.begin(115200);
  Serial.println("MyMillis demo");
  
  for(int i=0; i< 10; i++)
  { 
    delay(10);
    Serial.println(MyMillis());
  }
  delay(1000);
  MMReset();
  for(int i=0; i< 10; i++)
  { 
    delay(10);
    Serial.println(MyMillis());
  } 
  MMReset(1000);
  for(int i=0; i< 10; i++)
  { 
    delay(10);
    Serial.println(MyMillis());
  } 
}

void loop()
{
}

Thanks for the replies.

I intend to use power-down sleep mode. When sleeping, the current value of millis is frozen. Therefore, if we know exactly how much time passed during sleep mode, we can adjust millis() as desired.

The proposed function is a good approach but I still need to change many existing programs that are migrating from non-sleep to sleep mode. Probably, I will go in this way if there is no way to direct change the variable used by millis().

Thanks

Hi Ionito,

Inspired by your question I wrote a simple StopWatch Class based upon millis(), See - Arduino Playground - StopWatchClass . It will not work for your question but nevertheless I thought you might be interested.

Thanks again for the inspiration :wink:

Rob

Rob,

Nice code!! Thanks!!

If you have a look at wiring.c, you'll see that millis() reads variable timer0_millis. If you take the right precautions you can update this variable. I've amended my SleepDelay library to do this and I'm currently testing it out. So far, it seems ok but I'm going to test it for a few days first.

@Cloudy,

Will you be able to write a playground article about it?

If you have a look at wiring.c, you'll see that millis() reads variable timer0_millis

timer0_millis is only part of the value. The other part is the timer itself. It is extremely difficult to change the millis value without introducing an offset.

@robtillaart Yes I will once I'm happy with it.

@Coding Badly Not sure what you mean by introducing an offset. The timer doesn't work in power down sleep mode.

Kind of off thread, but it's funny how frequently people ask or want to be able to preset a value for millis(), seems to be a very popular request. And while I'm certainly not a guru software type, none of the reasons given for needing this seem to not be better handled in a different and better matter?

Lefty

@Lefty
One of my CS teachers told me that software is made from the same the stuff dreams are made of, if you can dream it you can make it :slight_smile:

The "problem" is often that people don't have a formal training in algorithmic - OO or realtime design which often leads to "if the only tool is a hammer, every problem is a nail" thinking. A very common pattern. People have a timing problem, they know millis() is about time, so millis() can/should solve it, and often it just can solve it, but sometimes not. Even knowing this pattern I find myself doing it too :slight_smile:

Rob

Not sure what you mean by introducing an offset.

If you change timer0_millis without also considering TCNT0 and the hidden / unreachable value within the timer, your change introduces an error into the millis value (an offset from the correct value).

It worked!!!

This is the code:

...
#include <Wire.h>
...

 
    // timer0_millis can change inside the ISR process for timer0
    // 2 options: disable interrupts OR make 2 consecutive readings and 
    //                compare. I am using the second option here:

    unsigned long reading1;
    unsigned long reading2;
    boolean readingOK = false;
    int k=0;
    while (k<1000 && !readingOK) {
      reading1 = timer0_millis;
      reading2 = timer0_millis;
      if (reading1 == reading2) { readingOK = true; }
      k++;
    }
    
    timer0_millis = 2000 + reading1; // e.g. 2000: time elapsed while sleep
    nint++;
    Serial.print("Going to sleep. Count # " );
    Serial.println(nint );
    Serial.print("Time: millis() " );
    Serial.println(millis() );
    delay(2);               // wait until the last serial character is send

It completely solved my problem. There is a small error in the process. However, if the process is always the same after returning from sleeping, we can determine its value with great accuracy and adjust.

Thanks

It worked!!!

Only because you're lucky. Let the code run long enough and it will fail.

have you seen this thread?

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1167861718

in one place Member macsimski suggests this declaration

extern volatile unsigned long timer0_overflow_count;

and this code to reset

timer0_overflow_count = 0;

this resets to 0... maybe it can be coaxed to set to a specific value.

have you seen this thread?

I have. And there is a nasty subtle bug in what was proposed as a solution.

@ Coding Badly:

may you help me to understand better the issues you mentioned? I tried to run the code for hours, and it continue working.

Sometimes, the comparison returns false and it is probably caused my the "on going" modification of the variable. But, I only realize the mentioned operation just after the "true", that is after the modification if this is the case.

Thanks