Σε πολλές εφαρμογές θέλουμε να απαριθμούμε γεγονότα ή να παράγουμε χρονικές καθυστερήσεις. Ένας τρόπος που μπορούμε να το κάνουμε είναι με τη χρήση μικροελεγκτών. Όταν θέλουμε να απαριθμούμε παλμούς (γεγονότα), συνδέουμε την εξωτερική πηγή παλμών στον ακροδέκτη ρολογιού του counter καταχωρητή που υπάρχει μέσα στον μικροελεγκτή. Έτσι με κάθε παλμό αυξάνονται τα περιεχόμενα του counter και με αυτό τον τρόπο τα περιεχόμενα του counter παριστάνουν πόσες φορές έχει συμβεί ένα γεγονός.
Όταν θέλουμε να παράγουμε χρονικές καθυστερήσεις, συνδέουμε το σήμα του ταλαντωτή στην είσοδο του απαριθμητή (counter). Έτσι με κάθε παλμό του ταλαντωτή τα περιεχόμενα του counter αυξάνονται. Με αυτό τον τρόπο τα περιεχόμενα του καταχωρητή counter δείχνουν πόσοι παλμοί του ταλαντωτή έχουν απαριθμηθεί από την χρονική στιγμή που έχουμε μηδενίσει τον counter. Επειδή γνωρίζουμε την συχνότητα του ταλαντωτή, γνωρίζουμε και την περίοδο των παλμών και έτσι από την τιμή του καταχωρητή counter μπορούμε να υπολογίσουμε την χρονική καθυστέρηση.
Σύμφωνα με την προηγούμενη ανάλυση, ένας τρόπος για να παράγουμε χρονικές καθυστερήσεις είναι να μηδενίσουμε τον counter στην αρχή και να περιμένουμε τον counter να πάρει κάποια τιμή. Στους μικροελεγκτές υπάρχει μια σημαία (flag) για καθένα από τους counters. Η σημαία OCFn τίθεται σε ένα όταν ο counter φτάσει σε μια συγκεκριμένη τιμή από όπου μετά μπορεί να μηδενιστεί από το λογισμικό. Η δεύτερη μέθοδος για να ορίσουμε χρονική καθυστέρηση, είναι να φορτώσουμε στον καταχωρητή counter μια κατάλληλη τιμή και να περιμένουμε μέχρι ο καταχωρητής counter να υπερχειλίσει και η αντίστοιχη σημαία TOVn να τεθεί σε 1.
Στους μικροελεγκτές AVR μερικοί από τους timers/counters είναι 8bit και άλλοι 16bit. Στον ATmega328 υπάρχουν τρεις timers οι Timer0, Timer1 και Timer2. Οι Timer0 και Timer2 είναι 8bit timers ενώ ο Timer1 είναι 16bit timer.
Εάν μάθεις να χρησιμοποιείς τους timers του ATmega328 μπορείς εύκολα να χρησιμοποιείς τους timers και των άλλων AVRs. Μπορείς να χρησιμοποιείς τους 8bit timers όπως τον Timer0 του ATmega328 και τους 16bit timers όπως τον Timer1 του ATmega328
Βασικοί καταχωρητές που χρησιμοποιούμε στους timers
Κάθε timer χρειάζεται παλμούς ρολογιού για να λειτουργήσει. Η πηγή των παλμών μπορεί να είναι εσωτερική ή εξωτερική. Εάν χρησιμοποιούμε εσωτερική πηγή παλμών, τότε οι παλμοί του εσωτερικού κρυσταλλικού ταλαντωτή τροφοδοτούν τον timer. Επειδή η συχνότητα αυτών των παλμών είναι σταθερή μπορούμε να παράγουμε καθορισμένες χρονικές καθυστερήσεις και συνεπώς λέμε ότι έχουμε ένα timer. Συνδέοντας την εξωτερική πηγή παλμών να τροφοδοτεί τον ακροδέκτη του απαριθμητή του AVR, λέμε ότι έχουμε ένα counter.
Παρατήρησε την άνω εικόνα. Σε καθένα από τους timers του AVR υπάρχει και ένας TCNTn (timer/counter) καταχωρητής. Για παράδειγμα, στον ATmega328 έχουμε τους TCNT0, TCNT1 και TCNT2. Ένας καταχωρητής TCNTn είναι ένας counter. Κατά την επανεκκίνηση του AVR ο καταχωρητής TCNTn έχει την τιμή μηδέν. Όταν τροφοδοτούμε τον counter με παλμούς, αυτός αυξάνει τα περιεχόμενα του κατά ένα σε κάθε παλμό που δέχεται. Έχουμε πρόσβαση στα περιεχόμενα του timer/counter φορτώνοντας μια τιμή στον καταχωρητή TCNTn ή διαβάζοντας τα περιεχόμενα του.
Κάθε timer έχει μια TOVn (Timer Overflow) σημαία. Όταν ο timer υπερχειλίζει η TOVn σημαία τίθεται σε ένα. Επίσης κάθε timer έχει καταχωρητές TCCRn (timer/counter control register) για να επιλέξουμε την επιθυμητή κατάσταση λειτουργίας. Για παράδειγμα μπορούμε να θέσουμε τον Timer0 να δουλέψει σαν timer ή counter φορτώνοντας τις κατάλληλες τιμές στους καταχωρητές TCCR0A και TCCR0B.
Κάθε timer έχει καταχωρητές OCRn (Output Compare Register). Τα περιεχόμενα των καταχωρητών OCRn συγκρίνονται με εκείνα του TCNTn. Όταν γίνουν ίσα η σημαία OCFn (Output Compare Flag) τίθεται σε ένα.
Οι καταχωρητές του Timer0 βρίσκονται στη μνήμη των I/O καταχωρητών. Επομένως μπορούμε να διαβάσουμε ή να γράψουμε σε αυτούς τους καταχωρητές χρησιμοποιώντας τις εντολές ΙΝ και OUT όπως τους άλλους Ι/Ο καταχωρητές. Για παράδειγμα οι επόμενες εντολές φορτώνουν στον TCNT0 την τιμή 35.
LDI R18, 35 ; R18 = 35
OUT TCNT0, R18 ; TCNT0 = R18
Με την εντολή ”IN R20, TCNT0” αντιγράφουμε τον I/O καταχωρητή TCNT0 στον καταχωρητή γενικού σκοπού R20.