문제

I need to detect the overflowing of an unsigned long.

This variable holds the amount of milliseconds since the device is running (it's an Arduino). Doing sizeof(unsigned long), I have come to see it's indeed a 32-bit number. Now, since it increments every millisecond, which means the device will run for about 49 days before this value overflows.

Since it's for a home system, it isn't really advisable. Now what I'm using the number for, is comparing if the current time is larger than the previous time plus an amount of debouncing.

if(timeChanged + amountOfMs < currentTime){ ... }

Needless to say, once overflow occurs this isn't going to work anymore. What's an efficient way to solve this? I've thought about also having a second-timer as well to check if the milliseconds one has overflowed, but in the end I'll have the same problem.

도움이 되었습니까?

해결책

This rollover issue seems to cause quite a bit of confusion...

The right answer is that you need not worry about the millis() rollover, as long as you do your calculation properly.

This is bad:

if (timeChanged + amountOfMs < currentTime) { ... }

This is good (rollover-safe):

if (currentTime - timeChanged > amountOfMs) { ... }

The reason it works is that arithmetics with unsigned integers (unsigned long in your case) reliably works modulo max+1 (ULONG_MAX+1 is 232). Thus, currentTime, timeChanged and their difference always have the correct value, modulo 232. As long as you test your button more often than once every 49 days (which is likely) the difference will be in the range of an unsigned long, and your test will be correct.

Let put it another way: if millis() rolls over between timeChanged and currentTime, then the difference currentTime - timeChanged will be negative. But since the difference is actually computed with unsigned numbers, it will underflow and roll-over to the correct result. I do not like this explanation though, as it sounds like an error compensating another error. The truth is: if you think of unsigned numbers in terms of modular arithmetics, there is no error anywhere.

다른 팁

This is such a common mistake (and one that I've made myself) that the Arduino Playground has a nice, thorough, and correct answer. See https://playground.arduino.cc/Code/TimingRollover

You can create a new if loop checking the condition : if(currentTime == 0xFFFFFFFE)

If this is the condition, next millisecond will overflow your variable. So at this point you can manually reset it to zero and goto loop where it starts from zero.

This might or might not help your situation. I can't say for sure because you haven't shared any further details about your code.

Define two variables, I'm going to call them 'now' and 'lastNow'.

unsigned long now;
unsigned long lastNow = 0;

In your loop you can now do this:

now = millis();
if (now < lastNow) {
    // rollover!
}
lastNow = now;

Nice and reliable regardless of how frequently (or infrequently) you loop.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top