16 Bit Tim.& Coun.
16 Bit Tim.& Coun.
Three separate comparison registers exist. Thus, three separate outputs are
available: OCxA, OCxB, OCxC
16-Bit Timer/Counter 1 and 3
An input capture register (ICRx) is available for capturing the counter value at
the occurrence of external (edge) events such as an external pin change or
comparator state change.
16-Bit Timer/Counter 1 and 3
Five possible interrupt sources exist for each counter/timer:
-overflow (counter register over or under flows)
-output compare (counter register = a compare register
-input capture (something happened externally, capture the present count)
16-Bit Timer/Counter 1 and 3
TCNT1/3 can be clocked internally, via a prescaler, or by an external clock.
16-Bit Timer/Counter 1 and 3
TCNT1/3 counter register and control registers:
16-bit counter
control registers
16-Bit Timer/Counter 1 and 3
Each register is 16 bits wide. Access is taken care of by our library (iom128.h):
....
....
/* Timer Counter 1 */
#define TCNT1 _SFR_IO16(0x2C)
#define TCNT1L _SFR_IO8(0x2C)
#define TCNT1H _SFR_IO8(0x2D)
....
....
The input capture unit can detect events and give them a time stamp.
-can calculate frequency
-duty cycle Vth
If equal, the output compare flag is set (OCFnx) and an interrupt can be
issued.
Normal Mode
-simplest mode
-count up to 0xFFFF and wrap around to 0x0000
-no clear is ever performed
-TOV flag is set when the wrap around occurs (overflow)
-to reset TOV, must execute ISR or clear flag manually
-no output pins are used
16-Bit Timer/Counter 1 and 3
Modes of Operation:
Clear Timer on Compare Match (CTC) Mode
-resolution of counter is manipulated by output compare register A
(OCRnA) or input capture register (ICRn)
-counter is cleared to zero when its value equals either ICRn or OCRnA
-TOP is defined by ICRn or OCRnA
-interrupt can be generated at compare point
-output pins (OCnx) can be utilized
-toggle, set, or clear on match
OCR0=0xF000
OCR0=0x7F00
OCR0=0x00FF
OCR0=0x003F
while(1) {
if (TIFR & (1<<TOV1)) { //if overflow bit TOV1 is set
TIFR |= (1<<TOV1); //clear it by writing a one to TOV1
PORTB ^= (1<<PB0); //toggle PB0 each time this happens
} //if
} //while
} // main
16-Bit Timer/Counter 1 and 3
Code examples
// tcnt1_ctc.c
// setup TCNT1 in ctc mode
// set OC1A (PB5) to toggle on compare
// blink frequency ~= (16,000,000)/(2^15 * 64 * 2) = 3.8 cycles/sec
//
#include <avr/io.h>
int main()
{
DDRB = 0x20; //set port B bit five to output
while(1) {
if (TIFR & (1<<OCF1A)) //if output compare flag is set
TIFR |= (1<<OCF1A); //clear it by writing a one to OCF1A
} //while
} // main
16-Bit Timer/Counter 1 and 3
Code examples
// tcnt1_pwm.c
// setup TCNT1 in pwm mode
// set OC1A (PB5) as pwm output
// pwm frequency: (16,000,000)/(1 * (61440 + 1)) = 260hz
//
#include <avr/io.h>
int main()
{
DDRB = 0x20; //set port B bit five to output
} // main
16-Bit Timer/Counter 1 and 3
Code examples
Counter/Timers are one of the most valuable resources at your disposal.
When timer_tick reaches 0xFF, it will advance to 0x00. As long as the MOD
operation is by a power of two, we are OK. However, if the MOD operation is not a
power of two, the function calls will not occur at regular intervals once every roll-over
of timer_tick.
This technique is convenient for multiple, repetitive events that occur at regular times.
16-Bit Timer/Counter 1 and 3
Code examples
timer_tic function calls
From the previous example: k
0 do_this();do_that();
Each call is separated by either 8 do_this();
8 or 16 timer_ticks. 16 do_this(); do_that();
24 do_this();
32 do_this(); do_that();
40 do_this();
48 do_this(); do_that();
.........
.
240 do_this(); do_that();
248 do_this();
255
0 do_this(); do_that();
8 do_this();
16-Bit Timer/Counter 1 and 3
Code examples
What if the timer ticks were on different intervals?
ISR(xxx_vect){
static uint8_t timer_tick;
As a general rule the maximum count for timer_tick in this case would need to be
multiple of (2n-1) where n is the value of the biggest MOD operator divisor.
16-Bit Timer/Counter 1 and 3
Code examples
Now lets look at another way to generating multiple timed function calls off one timer.
ISR(xxx_vect){
static uint8_t timer_tick;
Here we place functions at specific, non-reoccurring times. There may be many entries
in the case statement, making for many code lines in the ISR but the execution will be
much faster than a bunch of mod operations applied for many time checks. Case is
usually implemented as a relative jumps or a jump table in assembly.