Στην προηγούμενη ενότητα χρησιμοποιήσαμε τους timers του AVR για να παράγουμε χρονικές καθυστερήσεις. Ο AVR timer μπορεί να χρησιμοποιηθεί για να μετρήσει, να αναγνωρίσει και να απαριθμήσει τα γεγονότα που δημιουργούνται εξωτερικά του AVR. Η χρήση του timer σαν απαριθμητή γεγονότων παρουσιάζεται σε αυτή την ενότητα. Όταν ο timer χρησιμοποιείται σαν timer ο ταλαντωτής του AVR χρησιμοποιείται για σήμα ρολογιού. Εάν ο timer χρησιμοποιείται σαν counter (απαριθμητής) οι εξωτερικοί παλμοί χρησιμοποιούνται για την αύξηση των περιεχομένων του καταχωρητή TCNTx. Στην κατάσταση λειτουργίας counter οι καταχωρητές όπως οι TCCR, OCR0 και TCNT έχουν την ίδια λειτουργικότητα όπως αναφέραμε σε προηγούμενες ενότητες και έχουν τα ίδια ονόματα
CS00, CS01 και CS02 στον καταχωρητή TCCR0
Όπως μάθαμε σε προηγούμενη ενότητα τα CS bits (επιλογή σήματος ρολογιού) στον καταχωρητή TCCR0 ορίζει την πηγή του σήματος ρολογιού που θα τροφοδοτήσει τον timer. Εάν CS02:00 είναι μεταξύ 1 και 5 ο timer παίρνει παλμούς από τον κρυσταλλικό ταλαντωτή. Σε αντίθεση όταν οι CS02:00 είναι 6 ή 7 ο timer λειτουργεί σαν counter και παίρνει τους παλμούς από μια εξωτερική συσκευή. Επομένως όταν CS02:00 είναι 6 ή 7 ο TCNT0 counter απαριθμεί προς τα πάνω καθώς οι παλμοί τροφοδοτούν το πιν Τ0 (Timer/Counter 0 External Clock input) Στον ATmega328 το πιν Τ0 είναι η εναλλακτική λειτουργία του PORTD.4 Στην περίπτωση του Timer0 όταν τα CS02:00 είναι 6 ή 7 το πιν Τ0 παρέχει το σήμα ρολογιού και ο counter απαριθμεί προς τα πάνω σε κάθε παλμό που εφαρμόζεται σε αυτό το πιν. Όμοια για τον Timer1 όταν τα CS12:10 είναι 6 ή 7 οι παλμοί ρολογιού προέρχονται από το πιν Τ1 (Timer / Counter1 External Clock input) κάνει τον TCNT1 να απαριθμεί προς τα πάνω. Όταν CS12:10 έχει την τιμή 6 o counter απαριθμεί προς τα πάνω με την αρνητική (πτωτική) ακμή. Όταν CS12:10 έχει την τιμή7 ο counter απαριθμεί προς τα πάνω στην θετική (ανοδική) αιχμή. Στον ATmega328 το πιν Τ1 είναι η εναλλακτική λειτουργία του PORTD.5
Παράδειγμα : Βρες την τιμή που πρέπει να έχει ο TCCR0 εάν θέλουμε να έχουμε τον Timer0 στη λειτουργία Normal mode counter. Χρησιμοποίησε εξωτερική πηγή σήματος ρολογιού και με αύξηση με την θετική (ανοδική) ακμή
Απάντηση: TCCR0 = 0000 0111 Normal, external clock source, no prescaler.
Στο ακόλουθο παράδειγμα χρησιμοποιούμε τον Timer0 σαν απαριθμητή γεγονότων που μετρά προς τα πάνω για κάθε παλμό που εισέρχεται στο PD4. Αυτοί οι παλμοί ρολογιού θα μπορούσαν να αντιπροσωπεύουν τον αριθμό των ατόμων που περνούν μια είσοδο ή οι στροφές ενός τροχού ή οποιοδήποτε άλλα γεγονότα που παράγουν παλμούς.
Παράδειγμα: Υποθέστε ότι με συχνότητα 1Ηz παλμοί ρολογιού εισέρχονται στο pin Τ0 (ΡD4). Γράψτε ένα πρόγραμμα για τον Counter0 στην Normal mode το οποίο να απαριθμεί τους παλμούς στην πτωτική ακμή και εμφάνισε την κατάσταση του TCNT0 στην PORTD
Απάντηση:
CBI DDRD, 4 ; make T0 (PD4) input
LDI R20, 0xFF
OUT DDRB, R20 ; make PORTB output
LDI R20, 0x00
OUT TCCR0A, R20
LDI R20, 0x06
OUT TCCR0B, R20 ; counter, falling edge
AGAIN:
IN R20, TCNT0
OUT PORTB, R20 ; PORTB = TCNT0
RJMP AGAIN ; keep doing it
Στο προηγούμενο παράδειγμα τα περιεχόμενα του TCNT0 εμφανίζονται στο δυαδικό. Στο ακόλουθο παράδειγμα ο TCNT0 καταχωρητής επεκτείνεται σε ένα 16bit counter χρησιμοποιώντας τη σημαία TOV0.
Παράδειγμα: Θεωρήστε ότι 1Hz συχνότητα παλμών ρολογιού τροφοδοτεί το pin T0. Χρησιμοποίησε τη σημαία TOV0 για να επεκτείνεις τον Timer0 σε ένα 16bit counter και εμφάνισε το περιεχόμενο του counter στους PORTC και PORTD.
Απάντηση
LDI R19, 0 ; R19 = 0
CBI DDRB, 0 ; make T0 (PB0) input
LDI R20, 0xFF
OUT DDRC, R20 ; make PORTC output
OUT DDRB, R20 ; make PORTB output
LDI R20, 0x00
OUT TCCR0A, R20
LDI R20, 0x06
OUT TCCR0B, R20 ; counter, falling edge
AGAIN:
IN R20, TCNT0
OUT PORTC, R20 ; PORTC = TCNT0
SBIS TIFR0, TOV0
RJMP AGAIN
LDI R16, 1<<TOV0 ; clear TOV0 flag
OUT TIFR0, R16
INC R19 ; R19 = R19 + 1
OUT PORTB, R19 ; PORTB = R19
RJMP AGAIN
Παράδειγμα: Θεωρήστε ότι παλμοί ρολογιού τροφοδοτούν το pin T1 (PD5). Γράψε ένα πρόγραμμα για τον Counter1 στη Normal mode που να απαριθμεί τους παλμούς στην πτωτική ακμή και εμφάνισε τα περιεχόμενα του TCNT1 στις θύρες PORTC και PORTB.
Απάντηση
CBI DDRD, 5 ; make T1 (PD5) input
LDI R20, 0xFF
OUT DDRC, R20 ; make PORTC output
OUT DDRB, R20 ; make PORTB output
LDI R20, 0x00
OUT TCCR1A, R20
LDI R20, 0x06
OUT TCCR1B, R20 ; counter, falling edge
AGAIN:
LDS R20, TCNT1L ; R20 = TCNT1L, TEMP = TCNT1H
OUT PORTC, R20 ; PORTC = TCNT1L
LDS R20, TCNT1H ; R20 = TEMP
OUT PORTB, R20 ; PORTB = TCNT1H
SBIS TIFR1, TOV1
RJMP AGAIN
LDI R16, 1<<TOV1 ; clear TOV1 flag
OUT TIFR1, R16
RJMP AGAIN
Παράδειγμα: Θεώρησε ότι παλμοί ρολογιού τροφοδοτούν το pin Τ1 (PD5) και ένας βομβητής είναι συνδεμένος στο pin PORTC.0 Γράψε ένα πρόγραμμα για τον Counter1 σε CTC mode για να ηχεί ο βομβητής κάθε 100 παλμούς.
Απάντηση: Για να ηχεί ο βομβητής κάθε 100 παλμούς, φορτώνουμε τον OCR1A με την τιμή 99 (63 στο δεκαεξαδικό) και τότε ο counter απαριθμεί προς τα πάνω μέχρι να φτάσει στον OCR1A. Όταν συμβεί ισότητα, μπορούμε να κάνουμε τον βομβητή να ηχεί, με εναλλαγή του pin PORTC.0
CBI DDRD, 5 ; make T1 (PD5) input
SBI DDRC, 0 ; PC0 as an output
LDI R16, 0x01
LDI R17, 0
LDI R20, 0x00
OUT TCCR1A, R20
LDI R20, 0x0E
OUT TCCR1B, R20 ; CTC, counter, falling edge
AGAIN:
LDI R20, 0
OUT OCR1AH, R20 ; TEMP = 0
LDI R20, 99
OUT OCR1AL, R20 ; OCR1AL = R20, OCR1H = TEMP
L1: SBIS TIFR1, OCF1A
RJMP L1
LDI R20, 1<<OCF1A ; clear OCF1A flag
OUT TIFR1, R20
EOR R17, R16 ; toggle D0 of R17
OUT PORTC, R17 ; toggle PC0
RJMP AGAIN