One of the requested items I found was handling 'rollover' from 'millis()' and also, 'micros()'. This is actually not a very difficult matter to deal with, and it's something I've needed to address a lot of times in various contexts, from kernel drivers to applications, and of course, micro-controllers.
First, I shall explain two's complement mathematics, and signed vs unsigned integers.
Two's complement is a way to represent negative numbers in binary. It requires that you sacrifice one bit of precision (the most significant bit), to handle negative values.
For a 16-bit integer, a two's complement value can represent any number between -32768 and 32767, inclusive. For now, this is what I will focus on.
By definition, if you subtract a binary 1 from a binary zero, you should end up with a binary -1. Conversely, if you add a binary 1 to a binary -1, you should get zero.
Doing a little atmospheric extrapolation, it's pretty obvious that the following is true.
If there were another bit shown (i.e. the 'carry' bit) you would see a 17-bit number with the high bit set. But this is the consequence of using a fixed-length binary value. You get 'rollover'.
Consequently to adding binary 1 to "all 1's" to get zero, the following will also be true:
So the representation of a -1 must be 'all 1 bits' for any two's complement integer, given a fixed-length integer size in bits.
Now it is important to distinguish 'unsigned' from 'signed' integer math. If you want to subtract two unsigned values, and have a negative result if the second is larger, you have to cast the result to a signed integer. This will treat the unsigned result as if it were two's complement, like so:
unsigned int i,j;
...
And, this is the heart of the solution to 'rollover'. In the case where the value of 'i' has not yet 'crossed' the value of 'j', the result of 'i - j' (cast to a signed integer) will be NEGATIVE. If 'i' crosses 'j', the result will be POSITIVE.
Example: Assuming that 'millis()' returned a 16-bit integer (for simplicity), if the current 'millis()' time is 65500 and you want to wait for 1000 milliseconds, you can use unsigned math to add 1000 to 65500 and get a result of 964 (rolling over to zero at what would be 65536). When the '16-bit' millis() 'rolls over' to zero, it will continue to increment until it, too, reaches the value 964. At that point, your timer code can recognize the 'crossing' by subtracting the wait time from millis(), converting it to a signed integer, and checking that it's greater than or equal to zero.
The following code checks to see if you have 'crossed' a 1000 millisecond 'delay point', and initiate's another timer delay of 1000 milliseconds after some kind of periodic processing.
static unsigned long lWaitMillis;
void setup()
{
lWaitMillis = millis() + 1000; // initial setup
}
void loop()
{
if( (long)( millis() - lWaitMillis ) >= 0)
{
// millis is now later than my 'next' time
{ do something }
lWaitMillis += 1000; // do it again 1 second later
}
else
{
// millis is still 'before' my 'next' time
// so I continue waiting
delay(1); // one possible thing you can do }
}
The same kind of code can be applied to 'micros()' as well.