So a trick I use in my code and libraries is to use typedef's for variables.
typedef uint32_t milliseconds_t;
milliseconds_t getMillis();
Then I use milliseconds_t to define all variables. This allows me to change it to uint64_t in one location depending on the project.
I have started using more typedef's like this as a form of documentation. That is code is easier to read and follow when variables are defined based on the use/type.
A neat fixed point unsigned math trick is when doing comparisons...
milliseconds_t start=
getMillis();
// This is bad
while( getMillis()<(start +10) ){ //wait for 10ms
....
}
To understand why assume milliseconds_t is uint8_t. Now we get start and say it is 255, this means (start+10) = 9, now getMillis() on the first loop is still 255... So the comparison becomes while (255<9). So you exit while loop early
A better way to do this is
milliseconds_t start=
getMillis();
// This is good
while( (getMillis()-start)<10 ){ //wait for 10ms
....
}
Here you if start and getMills() are 255 the first loop is while(0<10). Now next millisecond we have
(getMillis()-start) = (0-255) =1 to understand this look at the math as in binary:
0000 0000
-1111 1111
= 1 0000 0001 where the first 1 is the negative bit, but since we are 8 bit unsigned the value is 1. This means when doing unsigned subtraction you end up with a modulo absolute difference.
Now with that said the code works but other developers might not understand it, and you risk them adding code or modifying that breaks things. Therefore often I just use uint64_t just to make sure other developers do not break the code. If speed becomes an issue I can optimize the code to use the fixed point math tricks, but only as a last resort.
Note I know many developers that refuse to use unsigned variables due to math issues like above. So they try to use signed integers for most everything. You still have overflow issues but you do not have math issues.
Here is a blog article I wrote on embedded systems and time:
Trampas