Timer using millis()

PaulS: There was a long thread a while ago that explained why subtraction involving unsigned variables was guaranteed to work. You could try to find that thread, if you are interested in why it works.

But, think about your watch. It rolls over every 12 hours. If you had lunch at 11:30, you don't have any trouble determining that, at 1:30, it's been two hours since you've eaten, even though then (1130) is larger than now (130). The Arduino doesn't either.

I got it now. Since unsigned dosnt handle negative number the propper intervall remains. Its easilly verified with this:

unsigned long MyValue = 4294967290; // 5 under max amount

void setup() 
{
  Serial.begin(9600);
}

void loop() 
{
   Serial.println(millis()-MyValue);
   delay(1000);
}

Are you saying that 5 - 4294967290 = 10, amusing that they are all unsigned long?

Feeling a bit silly if that is the case :blush:

Are you saying that 5 - 4294967290 = 10, amusing that they are all unsigned long?

4294967290 is functionally equivalent to -5.

5 - (-5) = 10 using my calculator.

How does that work ... It clearly does but I am at a loss to understand it. I get the 5 - (-5) part but I don't understand how the functionally equivalent part works. Can you explain? Is there a name for this behaviour?

I can see it also works for int's the reference mentions it and I tested it. however when I tested a byte it rolled from 255 to 0 just fine but the maths doesn't work the same way as above. 5 - 250 is -245 which is what a normal calculation would tell you.

Why the difference?

Dyslexicbloke:
5 - 250 is -245 which is what a normal calculation would tell you.

Why the difference?

It matters whether you are using signed or unsigned variables.

That doesn't appear to be it ..... It works just fine with int or unsigned int:-

Iterated value - original value = difference (Or not)

unsigned int 65531 - 65530 = 1 65532 - 65530 = 2 65533 - 65530 = 3 65534 - 65530 = 4 65535 - 65530 = 5 0 - 65530 = 6 1 - 65530 = 7 2 - 65530 = 8 3 - 65530 = 9 4 - 65530 = 10 5 - 65530 = 11

int 32763 - 32762 = 1 32764 - 32762 = 2 32765 - 32762 = 3 32766 - 32762 = 4 32767 - 32762 = 5 -32768 - 32762 = 6 -32767 - 32762 = 7 -32766 - 32762 = 8 -32765 - 32762 = 9 -32764 - 32762 = 10 -32763 - 32762 = 11

Doing this with a byte returns negative numbers byte 251 - 250 = 1 252 - 250 = 2 253 - 250 = 3 254 - 250 = 4 255 - 250 = 5 0 - 250 = -250 1 - 250 = -249 2 - 250 = -248 3 - 250 = -247 4 - 250 = -246 5 - 250 = -245

Dyslexicbloke: That doesn't appear to be it .....

You're comparing the behaviour of a [u]signed[/u] byte against an [u]unsigned[/u] int. The word size doesn't affect the behaviour, it only affects the value at which rollover occurs. Whether it is signed or unsigned does affect the behaviour, though.

Please allow me to repeat what I wrote earlier: having a signed type makes this so much easier.

Gents ... I dont understand how this works, which is exactly why I was asking ...

You're comparing the behaviour of a signed byte against an unsigned int.

NO I compared a signed byte to a signed int, the last two sets of figures, and they behave differently.

I also compared the signed int to an unsigned int, which you say should differ because one is signed and the other isnt. They both work the same. Obviously when they roll-over the values differ, one is negative, but the subtraction to find the change works.

-32763 - 32762 = -65525 whether you use a calculator or a spreadsheet, Unless its an int ... -32763 - 32762 = 11

The same is true of unsigned ints where:- 5 - 65530 = 11

bytes and chars however:- 5 - 250 = -245

Dyslexicbloke: NO I compared a signed byte to a signed int...

You are actually not comparing the two numbers. You are subtracting one from the other. From a human's perspective it's a difference without a distinction. From a computer's perspective subtraction is sign agnostic.

I'll start with single bit integers. We can store a zero or a one. Addition is...

0 + 0 = 0 1 + 0 = 1 0 + 1 = 1 1 + 1 = 10

That last entry is a problem. We only have one bit to store numbers. Because we have no place to store that extra bit it gets tossed in the waste bin. Addition becomes...

0 + 0 = 0 1 + 0 = 1 0 + 1 = 1 1 + 1 = 0

Subtraction is...

0 - 0 = 0 1 - 0 = 1 0 - 1 = 11 (in "human" subraction we borrow from the place to the left; the computer does the same) 1 - 1 = 0

That third entry is a problem. We only have one bit to store numbers. Because we have no place to store those extra bits they get tossed in the waste bin. Subtraction becomes...

0 - 0 = 0 1 - 0 = 1 0 - 1 = 1 1 - 1 = 0

Looks like the addition truth table. Let's continue with two bits...

00 + 00 = 00 01 + 00 = 01 10 + 00 = 10 11 + 00 = 11

00 + 01 = 01 01 + 01 = 10 10 + 01 = 11 11 + 01 = 100 --> 00

00 + 10 = 10 01 + 10 = 11 10 + 10 = 100 --> 00 11 + 10 = 101 --> 01

00 + 11 = 11 01 + 11 = 100 --> 00 10 + 11 = 101 --> 01 11 + 11 = 110 --> 10

Now for subtraction...

00 - 00 = 00 01 - 00 = 01 10 - 00 = 10 11 - 00 = 11

00 - 01 = 111 --> 11 01 - 01 = 00 10 - 01 = 01 11 - 01 = 10

00 - 10 = 110 --> 10 01 - 10 = 111 --> 11 10 - 10 = 00 11 - 10 = 01

00 - 11 = 101 --> 01 01 - 11 = 110 --> 10 10 - 11 = 111 --> 11 11 - 11 = 00

Stil looks like the addition truth table.

-32763 - 32762 = -65525 whether you use a calculator or a spreadsheet, Unless its an int ... -32763 - 32762 = 11

This is a perfect example of subtraction overflowing (the subtraction examples above with "-->"). -65525 requires 17 bits to store. But only 16 bits are available. The right-most bit goes in the trash and, in the remaining 16 bits, we have 11.

OK that makes sense and I very much appreciate the time you have spent explaining it. I was aware that it happened but didn't know the mechanism.

I know that signed and unsigned ints have a different structure with the most significant bit holding the sign. They are the same size but the signed version is 50% negative. (Possibly not the best way to phrase that, there must be a proper way) Overflowing for addition or subtraction works in both cases.

It still leaves me with one question though ...

Why doesn't it work for bytes? or chars for that matter, which are signed bytes arn't they?

Al

Dyslexicbloke: Why doesn't it work for bytes? or chars for that matter, which are signed bytes arn't they?

What is "it"?

The concept applies no matter how wide the variable.

Dyslexicbloke:
They are the same size but the signed version is 50% negative.

And 50% positive. The values are offset by half the total range…

unsigned: 0 to 65535 (the range is 65536 so half of that is 32768)

int: (0-32768) to (65535-32768) or -32768 to +32767

(Possibly not the best way to phrase that, there must be a proper way)

Use whatever phrasing you can remember.

Why doesn’t it work for bytes? or chars for that matter, which are signed bytes arn’t they?

I believe char’s signage can be positive or negative depending on the compiler and the defaults. In the Arduino / AVR world it is signed.

Anything smaller than an int (or unsigned) is “sign extended” to an int (or unsigned) before any operations are applied. A byte becomes unsigned. A char becomes int. That is probably why the expressions are not working the way you expect.

Anything smaller than an int (or unsigned) is "sign extended" to an int (or unsigned) before any operations are applied.

Now it starts to make sense ... The 'it' I was talking about was an addition or subtraction, the result of which would-be outside the bounds of the type. Specifically remembering a previous value and subtracting it from the current value to get the change, but doing this with a roll-over in between.

Now if the maths involved in doing this to a byte is actually performed on 16 bits ... Well suffice to say I probably don't understand the finer points but the rational is now far clearer.