Μερικές φορές χρειάζεται να εκτελεστεί μια εργασία περιοδικά, όπως στα παραδείγματα των προηγούμενων ενοτήτων. Αυτά τα προγράμματα μπορούν να γραφούν χρησιμοποιώντας CTC mode και με τη χρήση της αντίστοιχης διακοπής. Για να το κάνουμε, θα πρέπει να φορτώσουμε τον καταχωρητή OCF με την κατάλληλη τιμή και να διαμορφώνουμε τον timer στην CTC mode.
Έτσι όταν τα περιεχόμενα του TCNT γίνουν ίσα με εκείνα του OCR, η σημαία OCF τίθεται σε HIGH, το οποίο προκαλεί την αντίστοιχη διακοπή. Επειδή ο timer είναι σε CTC mode, αυτός μπορεί να αρχικοποιηθεί με την τιμή 0 και έτσι η διακοπή μπορεί να συμβαίνει περιοδικά. Ας σημειώσουμε ότι, η CPU μηδενίζει τη σημαία OCF καθώς μεταβαίνει στον interrupt vector table.
Παράδειγμα: Χρησιμοποίησε τον Timer0 και γράψε ένα πρόγραμμα που να εναλλάσσει το πιν PORTB.5 κάθε 15μs, ενώ την ίδια στιγμή να μεταφέρονται δεδομένα από την PORTC στην PORTD. Θεώρησε XTAL=16MHz
Απάντηση: 1/16ΜΗz = 0,0625μs και 15μs/0,0625μs = 240. Αυτό σημαίνει οτι θα πρέπει να έχουμε OCR0A = 240-1 = 239
.ORG 0x0 ;θέση για το reset
JMP MAIN
.ORG 0x1C
JMP T0_CM_ISR ;θέση ρουτίνας εξυπηρέτησης διακοπής
;-----κυρίως πρόγραμμα
MAIN: LDI R20, HIGH(RAMEND)
OUT SPH, R20
LDI R20, LOW(RAMEND)
OUT SPL, R20 ;αρχικοποίηση σωρού
SBI DDRB,5 ; ΡΒ5 σαν έξοδος
LDI R20, 239
OUT OCR0A, R20 ;φόρτωση καταχωρητή OCR0A με την τιμή 239
LDI R20, (1<<WGM01)
OUT TCCR0A, R20
LDI R20, 0x01
OUT TCCR0B, R20 ;ξεκίνημα του Timer0, CTC mode, no prescaler, int clk
LDI R20, (1<<OCIE0A)
STS TIMSK0, R20 ;ενεργοποίηση διακοπής compare match
SEI ;καθολική ενεργοποίηση διακοπών
LDI R20, 0x0
OUT DDRC, R20 ;κάνε την PORTC είσοδος
LDI R20, 0xFF
OUT DDRD, R20 ;κάνε την PORTD έξοδος
;------ ατέρμον βρόγχος
HERE: IN R20, PINC ;διάβασε την PORTC
OUT PORTD, R20 ;και στείλε τα δεδομένα στην PORTD
JMP HERE ;κράτα την CPU απασχολημένη περιμένοντας για διακοπή
;------- ρουτίνα εξυπηρέτησης διακοπής
T0_CM_ISR:
IN R16, PORTB ;διάβασε την PORTB
LDI R17, (1<<5)
EOR R16, R17 ;εναλλαγή του ΡΒ5
OUT PORTB, R16
RETI ;επιστρέφοντας από διακοπή
Παράδειγμα: Χρησιμοποιήστε τον Timer1 και γράψτε ένα πρόγραμμα που να εναλλάσσει το πιν PORTB.5 κάθε δευτερόλεπτο, ενώ ταυτόχρονα δεδομένα μεταφέρονται από την PORTC στη PORTD. Θεώρησε XTAL=16MHz
Απάντηση: Για prescaler=1024 έχουμε Tclock=(1/16MHz)x1024 = 64μs και 1s/64μs=15625. Αυτό σημαίνει ότι θα πρέπει να έχουμε OCR1A = 15624 = 0x3D08
.ORG 0x0 ;θέση για το reset
JMP MAIN
.ORG 0x16 ;θέση για την ρουτίνα εξυπηρέτησης διακοπής
JMP T1_CM_ISR
;-------κυρίως πρόγραμμα
MAIN: LDI R20, HIGH(RAMEND)
OUT SPH, R20
LDI R20, LOW(RAMEND)
OUT SPL, R20 ;αρχικοποίηση του σωρού
SBI DDRB,5 ;το ΡΒ5 σαν έξοδος
LDI R20, HIGH(15624) ;το υψηλότερο byte
STS OCR1AH, R20 ;Temp = 0x3D (το υψηλότερο byte του 15624)
LDI R20, LOW(15624) ;το χαμηλότερο byte
STS OCR1AL, R20 ;OCR1A=15624
LDI R20, 0x00
STS TCCR1A, R20
LDI R20, 0x00
STS TCCR1B, R20 ;prescaler 1:1024, CTC mode
LDI R20, (1<<OCIE1A)
STS TIMSK1, R20 ;ενεργοποίηση της διακοπής σύγκρισης του Timer1
SEI ;καθολική ενεργοποίηση διακοπών
LDI R20, 0x00
OUT DDRC, R20 ;κάνε την PORTC σαν είσοδο
LDI R20, 0xFF
OUT DDRD, R20 ;κάνε την PORTD σαν έξοδο
;-------ατέρμον βρόγχος
HERE: IN R20, PINC ;διάβασε από την PORTC
OUT PORTD, R20 ;PORTD = R20
JMP HERE
;-------ISR για τον Timer1
T1_CM_ISR:
IN R16, PORTB
LDI R17, (1<<5)
EOR R16, R17
OUT PORTB, R16 ;εναλλαγή του ΡΒ5
RETI ;επέστρεψε από την διακοπή