Hot answers tagged

154

Short answer: do not try to “handle” the millis rollover, write rollover-safe code instead. Your example code from the tutorial is fine. If you try to detect the rollover in order to implement corrective measures, chances are you are doing something wrong. Most Arduino programs only have to manage events that span relatively short durations, like debouncing ...


29

TL;DR Short version: An unsigned long is 0 to 4,294,967,295 (2^32 - 1). So lets say previousMillis is 4,294,967,290 (5 ms before rollover), and currentMillis is 10 (10ms after rollover). Then currentMillis - previousMillis is actual 16 (not -4,294,967,280) since the result will be calculated as an unsigned long (which can't be negative, so itself will roll ...


25

It is not an exclusive property of millis(). Any counter with a limited number of digits eventually returns to zero. For example, a 4 digit tally counter returns to zeros after 9999. Under the hood, the variable for millis() is of type unsigned long, which is 32 bits on the Arduino. In this case, the 32 bits (binary 0's and 1's) are similar to the digits (...


21

If you want to know exactly how long something will take, there is only one solution: Look at the disassembly! Starting with the minimal code: void setup(){}; volatile uint16_t x; void loop() { x = millis(); } This code compiled and then fed into avr-objdump -S produces a documented disassembly. Here are the interesting excerpts: void loop() ...


18

The other answers are very good, but I want to elaborate on how micros() works. It always reads the current hardware timer (possibly TCNT0) which is constantly being updated by the hardware (in fact, every 4 µs because of the prescaler of 64). It then adds in the Timer 0 overflow count, which is updated by a timer overflow interrupt (multiplied by 256). ...


16

You do not need an RTC to build a clock: the ATmega chip has all the hardware needed to perform the duties of the RTC itself. Here is how: Get a 32768 Hz watch crystal: either buy it or disassemble an old clock. These crystals, specifically designed for time keeping, have an extremely small temperature drift. You would also need one of those if you ...


16

Note: although my answer was accepted and has a higher vote score, make sure you read Edgar Bonet's great answer on how to make your Arduino keep time without an RTC. I've been quite successful in using the DS1307 Real Time Clock. Here's a link to its datasheet. Below are some of its features: It uses IC interface for communication with Arduino, making it ...


10

The Arduino framework does some initializing for you before going into setup() and loop(), for example configuring Timer0 correctly for millis(), delay() and siblings. This is done in the main() function, which then after the first initializing calls setup() and loop(). But the creation of globally defined objects (and thus the execution of their ...


8

After some digging around in the core, it seems like Arduino updates millis() with a 8 bit timer: it uses overflow with a prescaler value of 64. In simpler terms, it has it set up so a certain piece of code (the ISR) is run approximately once per millisecond on a 16MHz system (and proportionately less frequently on slower clocked systems). When that ISR is ...


8

Write a sketch that millis 1000 times, not by making a loop, but by copy and paste. Measure that and compare it to the actual expected time. Mind you that that the results may vary with different versions of the IDE (and its compiler in particular). Another option is to toggle an IO pin before and after the millis call, then measure the time for a very ...


8

Whenever you write an equation in C/C++, the data types being operated on have a very real effect on the equation's output. Each type like int, float, and unsigned long have different behaviors, and take a certain amount of space in memory to store. int (on arduino) is store in 16 bits, with half of its values being given to negative numbers, half-1 ...


8

It is not wrong to use millis() or micros() within an interrupt routine. It is wrong to use them incorrectly. The main thing here is that while you are in an interrupt routine "the clock isn't ticking". millis() and micros() won't change (well, micros() will initially, but once it goes past that magic millisecond point where a millisecond tick is required ...


7

You need to define the parameters of the problem more clearly. First, and most importantly, what is the shutterspeed you'll be using? If it's longer than 1 ms, then you can't use a 7-segment display to show the MS count, since the camera shutter would be open for multiple values. Even if your shutterspeed is a single MS, your shutter won't be ...


7

So I was wondering if I could attach an ISR to timer0 without affecting the above Arduino functions, Yes. A few ways, depending on your level of comfort: You can declare the stock Arduino Timer0 OVF "weak" and write your own where you can insert your ISR. But you have to handle the interaction between the millis() / micros() related variables. You can ...


7

One microsecond is only 16 CPU cycles. The CPU needs 4 cycles to prepare itself for servicing the interrupt (save the program counter, load the interrupt vector and clear the I bit in SREG). The interrupt vector itself is a jmp instruction that takes 2 cycles. When the ISR is done, it executes the reti instruction (return from interrupt) that takes 4 cycles....


6

They do not conflict as millis() strictly reads the immediate value in TCNT0 whereas PWM via timer 0 uses the hardware's ability to compare the value of TCNT0 with the values in OCR0x without affecting the value of any of them.


6

The resonator you specified has a 0.3% stability, where the crystal or crystal oscillator (as mentioned by Ricardo) is 50ppm. Many times more stable. Not to even mention the temperature drift of resonator is horrible. Heating by sunlight will change it. Hence a resonator should not be used for keeping time over long periods. Hence using either a crystal or ...


6

The quoted phrase is not a warning, it is merely a statement about how things work. There's nothing intrinsically wrong with using millis() or micros() within a properly-written interrupt routine. On the other hand, doing anything at all within an improperly-written interrupt routine is by definition wrong. An interrupt routine that takes more than a ...


6

millis() and micros() overflow periodically. However, this is not a problem: as long as you compare durations instead of timestamps you can forget about the overflows. The liked answer also gives the trick for resetting millis(). Can be handy for testing purposes, but you do not need this to handle the millis() rollover problem. Notice that there is no ...


6

should I be declaring last_ms as a global variable instead of static? Local static is better, as it limits the scope of the variable to just where it is needed. Consider making it global only if the code is part of a tutorial meant for beginners which may be confused by the keyword static. should this code be at the beginning or end of loop? The ...


5

Just to add to @Ignacio's answer which has directly answered your question. The "conflict" you speak of is in relation to Timer0's prescaler. For the most part, you can use those pins (incidentally pins 5 and 6 on the UNO) with PWM without an issue, and read the correct value of millis() (as well as get the expected delay from delay) Where you run into ...


5

I loved this question, and the great answers it generated. First a quick comment on a previous answer (I know, I know, but I don't have the rep to comment yet. :-). Edgar Bonet's answer was amazing. I've been coding for 35 years, and I learned something new today. Thank you. That said, I believe the code for "What if I really need to track very long ...


5

Overflow is never really an issue if you always calculate time difference. (Unless the time difference is more that 50 days.) unsigned long previousTime = millis(); ... wait for some event to happen ... unsigned long elapsedTime = millis() - previousTime; Even if previousTime was before the overflow, and millis() is after the overflow (so essentially ...


5

Use the concept of blink without delay. Instead of using delay() to set the timeout you use a timestamp and check micros() against that to see whether your interval has passed: const unsigned long READ_PERIOD = 4000; // 4000 us: 250 Hz void loop() { static unsigned long lastRead; if (micros() - lastRead >= READ_PERIOD) { lastRead += ...


5

If I understand correctly, you wrote an example code that switches an LED between two states (on and off), and you are stuck because the actual problem you want to solve is more complex than that. And indeed, it seems to me that you want to manage a system with three possible states: it can be on or off but, when it is off, it can be ready to turn on if the ...


4

If you don't want to use extra hardware like an Real Time Clock (eg. DSDS1307), you can significantly improve timing accuracy by disabling all unused interrupts. By default Arduino sketches come with various interrupt routines enabled and often they are not used for actually your sketch. Quickest way to find out if you can do without it to try and disable ...


4

Fixing the timekeeping functions with your PWM settings is not so simple. You should at least try to rewrite ISR(TIMER0_OVF_vect), micros(), and probably delay(). Here is why: First, there is a rounding problem. Time is kept using two global variables: volatile unsigned long timer0_millis; static unsigned char timer0_fract; The first one is what millis() ...


4

The primary downside to calling a function each time is that it may take more CPU cycles to complete the overall loop. The difference in CPU cycles, if any, depends on the actual implementation of the function and how the compiler optimises the call. For low-CPU sketches, this difference is probably unnoticeable. Generally speaking, it is good programming ...


4

You declare interval as an integer, while onTime and offTime are unsigned long. Change int interval = onTime; to unsigned long interval = onTime; The maximum value of int is only 32767 (215-1), which is only 33 seconds. An unsigned long can be as high as 4294967296 (232-1). Which is around 49.7 days worth of milliseconds.


Only top voted, non community-wiki answers of a minimum length are eligible