Hot answers tagged

126

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


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() ...


21

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


16

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


15

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


15

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


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

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

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


8

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


7

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


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


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


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

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() ...


5

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


5

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


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

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


5

First thing: you should call pulseIn() right after sending the TRIG pulse. If you wait too much, you will miss the start of the echo pulse. For instance, here: int distance = pulseIn(ECHO, HIGH, 26000); int distance1 = pulseIn(ECHO1, HIGH, 26000); the second pulseIn() is starting too late, because of the time taken by the first one. Next, the general ...


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

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

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 += ...


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.


3

Currently your code is not working, because Arduino is fast enough to check the closed switch state many times before it opens again, so before calculating a new speed value, you need to see LOW on the input. Still, there are at least 2 better ways to do what you want. pulseIn() - a function intended just for what you are trying to do: measuring lenght of ...


3

It has been suggested to you to save the millis value in the EEPROM. Although this can work, there is a big issue with the frequency at which you save it. If you save too often, you will burn your EEPROM, as it is only rated to 105 writes. If you do not save often enough, you will have most of the time a very outdated value in EEPROM. The problem can be ...


3

You might try a real-time clock module instead of the millis() function. They keep time in external hardware and are battery backed so continue through a power down, you get calendar date and clock time instead of milliseconds since restart, and they don't overflow every 50 days.


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