How does a microcontroller counter work?

A “microcontroller counter” is usually just a timer/counter peripheral inside the MCU that automatically counts clock pulses or external events for you – so you don’t have to do it in software loops.
Let’s break it down in plain language.
1. The basic idea
Inside the microcontroller there is a small hardware block:
A clock input (can be an internal clock or an external pin)
A prescaler (can divide the clock: /2, /8, /64, …)
A counter register (a number that increments or decrements)
Optional compare / auto-reload registers
Optional interrupts when certain events happen
Every time a tick comes in:
The counter register = counter register + 1
(or −1 if it counts down)
When it reaches its maximum value (e.g. 255 for 8-bit, 65535 for 16-bit), it overflows and starts again at 0.
2. Timer mode vs. Counter mode
Most MCUs use the same peripheral both as a timer and as a counter:
Timer mode (time-based)
Clock source: internal clock (e.g. CPU clock or a derived clock)
Use: measure time, create delays, generate periodic interrupts.
Example:
If the clock is 1 MHz and the prescaler is 1000:
Timer tick = 1 MHz / 1000 = 1000 Hz → 1 ms per increment
Every 1 ms the counter increases by 1.
When it reaches a certain value (e.g. 1000), you can trigger an interrupt → 1 second passed.
Counter mode (event-based)
Clock source: external signals (e.g. pulses on a pin)
Use: count things that happen in the real world:
Motor encoder pulses
Button presses
Frequency of a signal
Every pulse on the input pin makes the counter increment.
So the same hardware can either:
“Tick” with time (timer), or
“Tick” when events happen (counter).
3. Key building blocks inside a timer/counter
1) Prescaler
Divides the input clock so the counter doesn’t increment too fast.
Example: Input clock 16 MHz, prescaler = 16000 → counter sees 1 kHz (= every 1 ms).
2) Counter register (CNT)
Holds the current count (e.g. from 0 to 65535).
You can read it in software (to see the count).
You can write it (to reset or set a starting value).
3) Auto-reload / period register (ARR)
Defines when the counter should wrap or trigger an event.
Example: ARR = 999 → counter counts 0…999 then rolls over.
4) Compare register (CCR)
Lets you trigger an action when CNT == CCR.
Used for:
Generating PWM
Creating precise time points (e.g., toggle a pin at a specific count).
5) Interrupts
You can enable an interrupt on:
Overflow (update event)
Compare match
The CPU can then run an ISR (interrupt service routine) whenever that event happens.
4. What can you do with a microcontroller counter?
A lot:
Measure time intervals
Start counter at 0
Wait for an event (e.g. input pulse)
Read CNT; the value tells you how much time passed.
Generate periodic events
Configure ARR so overflow happens every 1 ms/10 ms/etc.
On each overflow interrupt, do something (update a variable, run control loop).
Count external events
Connect a sensor/output to the counter input pin.
Configure timer in external clock mode.
CNT now equals the number of pulses.
Measure frequency
Two common methods:Count how many pulses arrive on an input in a fixed time window.
Or measure the time between two pulses using the timer.
Generate PWM signals
Counter runs from 0 to ARR (period).
CCR defines duty cycle:
- Output pin is high while CNT < CCR, and low otherwise.
5. A tiny pseudo-code example (generic)
Imagine a 16-bit timer, internal clock at 1 MHz, prescaler = 1000:
// Pseudo-code, not tied to a specific MCU
TIMER.PRESCALER = 1000 - 1; // 1 MHz / 1000 = 1 kHz -> 1 ms per tick
TIMER.ARR = 999; // Overflow every 1000 ticks = 1 second
TIMER.CNT = 0;
TIMER.ENABLE_INTERRUPT_ON_OVERFLOW();
TIMER.START();
Interrupt handler:
void TIMER_IRQHandler(void) {
if (TIMER.OVERFLOW_FLAG) {
TIMER.CLEAR_OVERFLOW_FLAG();
seconds++; // we now have a 1-second software counter
}
}
Here the hardware counter gives you a reliable 1-second tick without busy-loops.
6. In one sentence
A microcontroller counter is just a little hardware machine that adds 1 on every clock/event, and lets you react (via registers or interrupts) when certain counts or overflows occur — you use it to measure time, count pulses, and generate precise timings without wasting CPU cycles.




