5. Compare match CTC mode programming

Σε αυτή την ενότητα θα μάθουμε για τον καταχωρητή OCR0A, ο οποίος συνοδεύει τον Timer0. Ο OCR0A καταχωρητής χρησιμοποιείται στην κατάσταση λειτουργίας CTC. Όπως στην κατάσταση λειτουργίας Normal έτσι και στην κατάσταση CTC o timer αυξάνει με τους κύκλους ρολογιού. Στη λειτουργία CTC ο timer απαριθμεί προς τα πάνω μέχρι η τιμή του TCNT0 να γίνει ίση με εκείνη του καταχωρητή OCR0A (compare match occurs). Στον επόμενο κύκλο ρολογιού η τιμή του timer θα μηδενιστεί ενώ ταυτόχρονα η σημαία OCF0A θα τεθεί σε 1. Η σημαία OCF0A βρίσκεται στον καταχωρητή TIFR0. Δες την ακόλουθη εικόνα και μελέτησε τα ακόλουθα παραδείγματα.

Παράδειγμα: Στο επόμενο πρόγραμμα, παράγουμε ένα τετραγωνικό σήμα με 50% duty cycle (με ίσα τμήματα high και low) στο PORTB.3 bit. Χρησιμοποιείται ο Timer0 για την παραγωγή της χρονικής καθυστέρησης. Μελετήστε το πρόγραμμα.

         INITSTACK
         LDI  R16, (1<<3)
         SBI  DDRB, 3     ;  PB3 as an output
         LDI  R17, 0
BEGIN:   OUT  PORTB, R17  ;  PORTB = R17
         RCALL DELAY
         EOR  R17, R16    ;  toggle D3  of R17
         RJMP BEGIN
;------------ Timer0  Delay
DELAY:   LDI  R20, 0
         OUT  TCNT0, R20
         LDI  R20, 9
         OUT OCR0A, R20        ;  load OCR0A
         LDI R20, (1<<WGM01)   ;  CTC mode
         OUT TCCR0A, R20
         LDI R20, 1
         OUT TCCR0B, R20     ; CTC mode, int clk
AGAIN:   SBIS TIFR0, OCF0A   ; if OCF0A is set skip next instruction
         RJMP AGAIN
         LDI R20, 0x00
         OUT TCCR0B, R20  ;  stop Timer0
         LDI R20, (1<<OCF0A)
         OUT TIFR0, R20   ;  clear OCF0A flag
         RET

Απάντηση: Για το προηγούμενο πρόγραμμα σημειώστε τα ακόλουθα βήματα:

1] Η τιμή 9 φορτώνεται στον OCR0A
2] O TCCR0 φορτώνεται και ο Timer0 ξεκινά την απαρίθμηση
3] Ο Timer0 απαριθμεί προς τα πάνω σε κάθε κύκλο ρολογιού ο οποίος παράγεται από κρυσταλλικό ταλαντωτή. Καθώς ο Timer απαριθμεί προς τα πάνω, πηγαίνει από τις καταστάσεις 00, 01, 02, 03 κ.ο.κ. μέχρι να φτάσει στην τιμή 9. Με τον επόμενο κύκλο ρολογιού κυλίεται στο 0 ανεβάζοντας σε 1 την σημαία OCF0A. Σε αυτή την στιγμή εδώ η εντολή «SBIS  TIFR0, OCF0A» παρακάμπτει την εντολή «RJMP  AGAIN»
4] Σταματά η λειτουργία του Timer0
5] Η σημαία OCF0A μηδενίζεται

Παράδειγμα: Βρες την χρονική καθυστέρηση που παράγεται από τον Timer0 στο προηγούμενο παράδειγμα. Μη λάβετε υπόψη τις καθυστερήσεις που παράγονται με τις άλλες εντολές. Θεωρείστε XTAL=16MHz

Απάντηση: Ο καταχωρητής OCR0A φορτώνεται με την τιμή 9 και ο TCNT0 μηδενίζεται. Επομένως μετά από 9 κύκλους ρολογιού, ο TCNT0 γίνεται ίσος με τον OCR0A. Στον επόμενο κύκλο η σημαία OCF0A γίνεται 1 και μηδενίζεται ο TCNT0. Αυτό σημαίνει ότι ο TCNT0 μηδενίζεται έπειτα από 9+1 κύκλους ρολογιού. Επειδή XTAL=16MHz ο απαριθμητής μετρά κάθε 0,0625μs. Επομένως έχουμε 10 x 0,0625μs = 0,625μs

Παράδειγμα: Βρες την χρονική καθυστέρηση που παράγεται από τον Timer0 για το ακόλουθο πρόγραμμα. Μην συμπεριλάβετε τις καθυστερήσεις που παράγονται με τις εντολές. (XTAL=16MHz)

           LDI  R16,  (1<<3)
           SBI  DDRB, 3      ;  PB3 as an output
           LDI  R17, 0
           OUT  PORTB, R17
           LDI  R20, 89
           OUT  OCR0A, R20   ;  load Timer0
BEGIN:     LDI  R20, (1<<WGM01)
           OUT  TCCR0A, R20  ;  CTC mode
           LDI  R20, 0x03
           OUT  TCCR0B, R20   ;  CTC mode, prescaler=64
AGAIN:     SBIS TIFR0, OCF0A  ;  if OCF0 flag is set skip next instruction
           RJMP AGAIN
           LDI  R20, 0x00
           OUT  TCCR0B, R20 ; stop Timer0
           LDI  R20, 1<<OCF0A
           OUT  TIFR0, R20  ;  clear  OCF0 flag
           EOR  R17, R16    ;  toggle D3 of R17
           OUT  PORTB, R17  ;  toggle PB3
           RJMP BEGIN

Απάντηση: Επειδή έχουμε prescaler=64 κάθε κύκλος ρολογιού διαρκεί 64 x 0,0625μs = 4μs . Ο καταχωρητής OCR0A φορτώνεται με την τιμή 89. Επομένως μετά από 90 κύκλους ρολογιού, η σημαία OCF0A τίθεται σε 1. Συνεπώς έχουμε 90 x 4μs = 360μs

Παράδειγμα: Θεωρήστε XTAL=16MHz. Γράψε ένα πρόγραμμα που να παράγει χρονική καθυστέρηση 12,8ms. Χρησιμοποίησε Timer0, CTC λειτουργία και prescaler=1024

Απάντηση: Επειδή έχουμε prescaler=1024 κάθε κύκλος του timer διαρκεί 1024 x 0,0625μs = 64μs. Επομένως για να παράγουμε καθυστέρηση 12,8ms θα πρέπει να έχουμε καθυστέρηση 12,8ms/64μs=200 κύκλους ρολογιού. Συνεπώς ο καταχωρητής OCR0A θα πρέπει να φορτωθεί με την τιμή 200-1=199

DELAY:  LDI  R20, 0
        OUT TCNT0, R20
        LDI  R20, 199
        OUT  OCR0A, R20
        LDI  R20, (1<<WGM01)
        OUT  TCCR0A, R20
        LDI  R20, 0x05
        OUT  TCCR0B, R20
AGAIN:  SBIS TIFR0, OCF0A
        RJMP AGAIN
        LDI  R20, 0x00
        OUT  TCCR0B, R20
        LDI  R20, (1<<OCF0A)
        OUT  TIFR0, R20
        RET

Παράδειγμα: Υποθέτουμε XTAL=16MHz. Γράψτε ένα πρόγραμμα που να παράγει χρονική καθυστέρηση 1ms.

Απάντηση: Επειδή XTAL=16MHz οι διάφοροι έξοδοι από τον prescaler είναι οι εξής:

Prescaler Timer Clock             Timer Period        Timer Value
None      16MHz                   1/16MHz=0,0625μs    1ms/0,0625μs=16000
8         16MHz/8=2MHz            1/2MHz=0,5μs        1ms/0,5μs=2000 
64        16MHz/64=250kHz         1/250kHz=4μs        1ms/4μs=250
256       16MHz/256=62,5kHz       1/62,5kHz=16μs      1ms/16μs=62,5
1024      16MHz/1024=15,625kHz    1/15,625kHz=64μs    1ms/64μs=15,625

Από τους προηγούμενους υπολογισμούς, μπορούμε να επιλέξουμε ένα από prescaler=64, prescaler=256, prescaler=1024. Θα χρησιμοποιήσουμε την επιλογή prescaler=64 από την στιγμή που δεν μπορούμε να χρησιμοποιήσουμε δεκαδικά ψηφία. Για καθυστέρηση 250 κύκλων ρολογιού θα πρέπει να φορτώσουμε τον OCR0A με την τιμή 250-1=249.

DELAY:  LDI  R20, 0
        OUT  TCNT0, R20     ;  TCNT0 = 0
        LDI  R20,  249
        OUT  OCR0A, R20     ;  OCR0A = 249
        LDI  R20, (1<<WGM01)
        OUT  TCCR0A, R20    ;  CTC mode
        LDI  R20, 0x03
        OUT  TCCR0B, R20    ;  CTC mode, prescaler = 64
AGAIN:  SBIS TIFR0, OCF0A   ;  if OCF0A is set skip next instruction
        RJMP AGAIN
        LDI  R20, 0x00
        OUT  TCCR0B, R20    ;  stop Timer0
        LDI  R20, (1<<OCF0A)
        OUT TIFR0, R20      ;  clear OCF0A flag
        RET

Σημείωση: Ο εσωτερικός συγκριτής ελέγχει για ισότητα, επομένως εάν φορτώσουμε τον καταχωρητή OCR0A με μια τιμή που να είναι μικρότερη από την τιμή του TCNT0, o counter θα ξεπεράσει την κατάσταση ισότητας και θα απαριθμήσει μέχρι την μέγιστη τιμή $FF και μετά θα κυλήσει στο 0. Αυτό θα προκαλέσει μια μεγάλη καθυστέρηση που δεν είναι επιθυμητή σε πολλές περιπτώσεις.

Παράδειγμα: Στο επόμενο πρόγραμμα, πόσο χρόνο παίρνει για το ΡΒ3 να γίνει 1; Μην λάβετε υπόψη τους χρόνους εκτέλεσης των εντολών.

           SBI  DDRB, 3      ; PB3 as an output
           CBI  PORTB, 3     ; PB3 = 0
           LDI  R20, 89
           OUT  OCR0A, R20   ; OCR0A = 89
           LDI  R20, 95
           OUT  TCNT0, R20   ; TCNT0=95
BEGIN:     LDI  R20, (1<<WGM01)
           OUT  TCCR0A, R20  ;  CTC mode
           LDI  R20, 1
           OUT  TCCR0B, R20  ;  CTC mode, prescaler = 1
AGAIN:     SBIS TIFR0, OCF0A  ; if OCF0A flag is set skip next instruction
           RJMP AGAIN
           LDI  R20, 0x00
           OUT  TCCR0B, R20     ; stop Timer0
           LDI  R20, (1<<OCF0A)
           OUT  TIFR0, R20      ; clear OCF0A flag
           EOR  R17, R16        ; toggle D3 of  R17
           OUT  PORTB, R17      ; toggle  PB3
           RJMP BEGIN   

Απάντηση: Επειδή η τιμή του TCNT0 (95) είναι μεγαλύτερη από την τιμή του OCR0A (89) ο timer θα απαριθμήσει προς τα πάνω μέχρι την τιμή $FF και μετά θα κυλήσει στο 0. Η σημαία TOV0 θα γίνει 1 με την υπερχείλιση. Μετά ο timer θα απαριθμήσει από την τιμή 0 μέχρι την 89 όπου μια ισότητα με τον OCR0A θα συμβεί. Συνεπώς η πρώτη ισότητα θα συμβεί μετά από 161+90=251 κύκλους ρολογιού (όπου 161 = 256-95) που σημαίνει μετά από χρόνο 251 x 0,0625μs = 15,6875μs. Η επόμενη ισότητα θα συμβεί μετά από 90 κύκλους που σημαίνει μετά από 90 x 0,0625μs = 5,625μs