Increment and decrement counters with rollover

This tip submitted by Lee Walker on 2011-08-16 10:45:39. It has been viewed 22809 times.
Rating of 7.9 with 76 votes

When using counters, programmers very rarely need to count all the way up to, say, 254 (0xFF with an 8-bit counter). implementing a clock, for example, would require a counter that increments to 59 then rolls over to zero.

A counter like this:


for example would have to be tested at every increment to see if the value had reached '59' and subsequently clear the counter if it had. A simple if-else statement would be enough to do this:

if(ucCounter++ >= 59)
  ucCounter = 0;

There is another 'neat' way to achieve the same thing. A commonly known method to implement an incrementing counter is to increment the counter of interest then divide by some limiting constant and return only the remainder:

ucCounter = (ucCounter + 1) % 60;

The line above first increments the counter then divides by 60 and returns the remainder (using the modulus operator, %).

Once the value in the counter reaches 60 the result of the division is 1 with a remainder of zero, so the 'zero' remainder is stored in ucCounter. The count has rolled over and the process can start again.

But what if we wanted our clock to run backwards? (can't imagine why). If we wanted to decrement the counter from, say, '59' down to zero then roll over from zero to 59, a similar trick can be used.

This particular down-counter decrements the counter to zero then rolls over to the pre-determined upper limit:

ucCounter=(ucCounter + (60 - 1)) % 60;

After each iteration of this line the value of ucCounter is decremented. When the counter reaches zero, the next iteration returns 59 (in this case) and the process starts again.

There is a down-side to these methods, these techniques take much longer to process than a simple if-else statement.

I have compared the increment code in a PIC micro-controller running at 5MHz. The 'divide and return remainder' method took 73uS to complete where an if-else statement that does the same job took only 7.2uS. The extra time being taken up during the 8-bit division.

More tips

Help your fellow programmers! Add a tip!