13. Σημαία σύγκρισης OCF και διακοπές

Μερικές φορές χρειάζεται να εκτελεστεί μια εργασία περιοδικά, όπως στα παραδείγματα των προηγούμενων ενοτήτων. Αυτά τα προγράμματα μπορούν να γραφούν χρησιμοποιώντας 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                         ;επέστρεψε από την διακοπή