Showing posts with label Arduino. Show all posts
Showing posts with label Arduino. Show all posts

Sunday, 17 March 2024

Avoiding Arduino millis() Rollover Bugs

If you are using the millis() function to measure time on an Arduino, you might be tempted to do something like this:-

unsigned long timer_expires_at = millis() + SOME_DURATION; while (millis() < timer_expires_at) { [do other stuff while waiting for the timer to expire] } [do stuff that should happen after the timer expires]

For the most part, that will work well. But after around 49.7 days (4,294,967,296 a.k.a 232 milliseconds, to be exact), you might run into a problem. If millis() + SOME_DURATION exceeds 4,294,967,295, it will rollover and your comparison will match prematurely. Of course, you would have to be pretty unlucky for this to occur in practice, but - as Mary Chapin Carpenter put it - Sometimes you're the Louisville Slugger, sometimes you're the ball.

I had plans sketched out for a small C++ class to handle this elegantly when I decided to do a quick bit of Googling to see if I was reinventing the wheel entirely here and I came across the most beautiful simple, and elegant solution to the problem in https://arduino.stackexchange.com/questions/12587/how-can-i-handle-the-millis-rollover/12588#12588. It is a long, detailed reply and well-worth reading, but the gist of it is to just change the logic very slightly:-

unsigned long timer_started_at = millis(); while (millis() - SOME_DURATION < timer_started_at) { [do other stuff while waiting for the timer to expire] } [do stuff that should happen after the timer expires]

It should be pretty clear how this avoids the problem after ~49.7 days, but it may be less obvious why it doesn't just shift the problem to the other end.  Imagine that your Arduino has been powered on for 30 seconds, so a call to millis() will return a value of 30,000. You want to wait for 40 seconds, so you set SOME_DURATION to 40,000. Subtracting 40,000 from 30,000 in the condition of the while() loop will indeed cause a rollover (30,000 - 40,000 mod 4,294,967,296 = 4,294,957,296), but the result of that rollover will still satisfy the condition in the way we want.

Monday, 6 August 2012

Arduino-based Audio Cable Tester

I love the Arduino platform - it makes it so quick and easy to get things done.

The local music school had a need to test a bunch of audio cables (1/4" and XLR) in a hurry in preparation for the annual students' concert.  Yes, it can be done with a multimeter but if you have lots of them to do this becomes very tedious very quickly.  Sounds like a job for an Arduino





It does XLRs also...



The work is all done by an Atmel Atmega mircocontroller



All of the development work is done in the Arduino environment.  Once it was all working I just transferred the microcontroller onto a piece of perfboard (so that I could reuse the Arduino board for my next project).  The connectors on the far-left of the board (connected to pins 1,2,3,7 and 8 ) allow the Arduino board to be used as a programmer (see http://arduino.cc/en/Tutorial/ArduinoToBreadboard). That link explains how to configure the Arduino to use the built-in 8MHz RC clock in the Atmega so no external crystal is required (neither accuracy nor flat-out CPU speed are remotely important in this application).

I also stuck a normal ICSP connector on it so that it can be programmed using a normal programmer (bottom-left corner).  This is handy:  once the code was complete I was able to blow the Arduino boot-loader away so that the sketch starts immediately rather than after a pause.  The downside is that if I want to use an Arduino to program it again I need to reinstall the boot-loader (for which that ICSP header will be very useful !)

The source-code is posted here.  The comments in the code list the required connections.  I haven't bothered to draw a circuit-diagram but if anyone wants one just leave a note in the comments below and I will post it here.