Οι AVR διαθέτουν μετρητές
(Timers/Counters) με δυνατότητα
σύγκρισης και διακοπής. Ο χρονισμός τους μπορεί να είναι σύγχρονος ή ασύγχρονος,
από το ρολόι συστήματος ή από εξωτερική πηγή και υπάρχει δυνατότητα διαίρεσης
της συχνότητας χρονισμού με prescaler ώστε να επιτευχθεί ο επιθυμητός ρυθμός μέτρησης. Οι μετρητές
χρησιμοποιούνται για ακριβή χρονισμό ή διακοπή μετά το πέρας κάποιου
συγκεκριμένου χρονικού διαστήματος και για παραγωγή παλμών διαμόρφωσης πλάτους
(PWM).
Ο ATmega2560 διαθέτει έξι μετρητές Timer/Counter0:5. Οι Timer/Counter0 και Timer/Counter2 είναι 8-bit και ο καθένας διαθέτει δύο μονάδες σύγκρισης Α και Β, ενώ οι υπόλοιποι είναι 16-bit ο καθένας
διαθέτει
τρεις μονάδες σύγκρισης A, B και C. ΟTimer/Counter2 έχει
ασύγχρονη λειτουργία, μπορεί δηλαδή να χρονιστεί από εξωτερικό κρύσταλλο ή από το ρολόι συστήματος. Σε περίπτωση που ο χρονισμός γίνεται από εξωτερικό κρύσταλλο, η λειτουργία του είναι ανεξάρτητη από το ρολόι συστήματος. Όλοι οι υπόλοιποι μετρητές έχουν σύγχρονη λειτουργία, χρονίζονται από το ρολόι συστήματος, εναλλακτικά μπορούν να δεχτούν χρονισμό από εξωτερική λογική πηγή, όμως η λειτουργία τους σε αυτή την περίπτωση είναι σύγχρονη με το ρολόι συστήματος. Οι μετρητές κάνουν μέτρηση
και
σύγκριση μεταξύ των καταχωρητών τους. Ο καταχωρητής μέτρησης είναι ο TCNTn (n=0:5) και μεταβάλλει το
περιεχόμενό του προς τα πάνω ή προς τα κάτω, από το ελάχιστο όριο Bottom έως το μέγιστο Max ή Top,
ανάλογα με τον τρόπο λειτουργίας του μετρητή. Το περιεχόμενό του συγκρίνεται με
το περιεχόμενο του καταχωρητή σύγκρισης OCRnx (n=0:5, x=A:C) και όταν υπάρξει ισότητα ή κατά την υπερχείλιση του TCNTn, προκαλείται μια διακοπή. Η διακοπές που
προκαλούνται και οι σημαίες που τοποθετούνται στα όρια διαμορφώνουν κάποιες
λειτουργίες. Το όριο Bottom είναι
σε όλους τους μετρητές 0 (0x0), το όριο Max εξαρτάται από τα bit του μετρητή και το Top από τον τρόπο λειτουργίας του
και από τον OCRnx.
Οι τρόποι λειτουργίας των μετρητών καθορίζονται από τα WGMni bit (i=0:2 για τους 8bit, i=0:3 για τους 16bit) του καταχωρητή TCCRnA/B για τους 8bit και TCCRnA/B/C για τους 16bit. Ο πιο απλός τρόπος λειτουργίας είναι ο
Normal Mode όπου
ο TCNTn μετράει προς τα
πάνω μέχρι το μέγιστο και ξεκινάει πάλι από την αρχή. Όταν φτάσει στο μέγιστο
τοποθετείται η σημαία υπερχείλισης TOVn και προκαλείται η αντίστοιχη διακοπή[1], η οποία
μηδενίζει την TOVn.
Στη λειτουργία Clear Timer on Compare Match (CTC) Mode ο TCNTn
μετράει προς τα πάνω και συγκρίνεται με το περιεχόμενο του καταχωρητή OCRnx. Όταν υπάρξει ισότητα τοποθετείται η σημαία OCnx και προκαλείται η αντίστοιχη
διακοπή[2],
ενώ ταυτόχρονα μηδενίζει ο TCNTn και ξεκινάει το
μέτρημα ξανά. Την κατάσταση της OCnx μπορούμε να
πάρουμε ως κυματομορφή στο αντίστοιχο pin του PORT, εφόσον το ενεργοποιήσουμε ως
έξοδο και ρυθμίσουμε την OCnx από
τα bit COMnx του καταχωρητή TCCRnx να αλλάζει την λογική της κατάσταση στο σημείο σύγκρισης (Toggle). Η κυματομορφή εξόδου θα είναι συμμετρικοί παλμοί
όπου η συχνότητα εξαρτάται από τη συχνότητα του ρολογιού του συστήματος, τον prescaler και από την τιμή του OCRnx. Στη συνέχεια παρουσιάζεται ένα παράδειγμα χρήσης
του Timer/Counter0A γραμμένο σε γλώσσα
προγραμματισμού C (η ρουτίνα της διακοπής εκτελείται με
συχνότητα 125Hz):
#include <avr/io.h>
#include <avr/interrupt.h>
void Timer0_init() //
Initialize Timer0A
{
TCCR0A |= (1 << WGM01); // Configure timer 0 for CTC
mode
TCCR0B |= (5 << CS00); // clk/1024
TIMSK0 |= (1 << OCIE0A); // Enable CTC interrupt
OCR0A = 125; // Set CTC for 125Hz at 16MHz clock
sei(); // Enable global interrupts
}
ISR(TIMER0_COMPA_vect)
{
/* Your code here */
}
int main(void) // Main program
{
/* Your code here */
Timer0_init();
While (1)
{
/* Your code here */
}
}
Η ρουτίνα Timer0_init() είναι υπεύθυνη για το initialization του Timer, όπου ρυθμίζεται να
λειτουργεί σε CTC κατάσταση, ο
χρονισμός να είναι από το ρολόι συστήματος διαιρεμένος με το 1024, ενεργοποιείται
η διακοπή από CTC, ενεργοποιούνται οι διακοπές γενικά
και ορίζεται τιμή σύγκρισης στον OCR0A 125 ώστε να προκαλούνται διακοπές με συχνότητα 125Hz. Ακολουθεί το διάνυσμα της διακοπής ISR(TIMER0_COMPA_vect)
όπου ο κώδικας που είναι γραμμένος στο μπλοκ κάτω από τον τίτλο του εκτελείται
κάθε φορά που προκαλείται διακοπή από τη σύγκριση. Στο κυρίως πρόγραμμα τέλος,
καλείται η ρουτίνα για το initialization πριν τον κυκλικό βρόχο.
Στη λειτουργία Fast PWM Mode ο TCNTn
μετράει προς τα πάνω και συγκρίνεται με το περιεχόμενο του καταχωρητή OCRnx. Όταν υπάρξει ισότητα τοποθετείται (ή μηδενίζει στην
ανάστροφη λειτουργία) η σημαία OCnx και
προκαλείται η αντίστοιχη διακοπή[3]
χωρίς να μηδενίζει ο TCNTn, ο οποίος συνεχίζει
το μέτρημα μέχρι το Max. Όταν φτάσει στο Max μηδενίζει (ή τοποθετείται) η OCnx,
μηδενίζει ο TCNTn και ξεκινάει το μέτρημα ξανά,
τοποθετείται η σημαία υπερχείλισης TOVn και προκαλείται η αντίστοιχη διακοπή[4] η οποία
μηδενίζει την TOVn. Την κατάσταση της OCnx μπορούμε να πάρουμε ως κυματομορφή στο αντίστοιχο pin του PORT,
εφόσον το ενεργοποιήσουμε ως έξοδο και ρυθμίσουμε κατάλληλα την OCnx από τα bit COMnx1:0 του
καταχωρητή TCCRnx σε
κανονική, ανάστροφη ή Toggle λειτουργία.
Η κυματομορφή εξόδου θα είναι παλμοί με σταθερή συχνότητα και διαμόρφωση εύρους
(duty cycle)
από 0-100% (PWM). Η συχνότητα εξαρτάται από τη
συχνότητα του ρολογιού του συστήματος και τον prescaler ενώ το duty cycle από την τιμή του OCRnx. Στη συνέχεια παρουσιάζεται ένα παράδειγμα παραγωγής
παλμών PWM στο pin PB7
γραμμένο σε γλώσσα προγραμματισμού C:
#include <avr/io.h>
unsigned char pwmout;
void PWM0_init() // Initialize PWM0
{
DDRB |= (1 << PB7); // PWM PB7
TCCR0A |= (3 << WGM00); // FPWM
TCCR0A |= (2 << COM0A0); // Clear OC0A on Compare Match (3->Set)
TCCR0B |= (5 << CS00); // clk/1024
}
int main(void) // Main program
{
/* Your code here */
PWM0_init();
While (1)
{
/* Your code here */
OCR0A = pwmout; // Set PWM duty cycle
/* Your code here */
}
}
Η ρουτίνα PWM0_init() είναι υπεύθυνη για το initialization του Timer, όπου ρυθμίζεται το PB3 ως
έξοδος για το PWM,
ρυθμίζεται να λειτουργεί σε FPWM κατάσταση,
κανονική λειτουργία (η έξοδος να γίνεται 1 κατά την ταύτιση) και ο χρονισμός να
είναι από το ρολόι συστήματος διαιρεμένος με το 64. Στο κυρίως πρόγραμμα
τέλος, καλείται η ρουτίνα για το initialization πριν τον κυκλικό βρόχο. Μέσα στον κυκλικό βρόχο μπορούμε να
δίνουμε τιμές στον OCR0 ώστε να μεταβάλλεται το duty cycle των
παλμών PWM.
Η λειτουργία Phase Correct PWM Mode είναι
σχεδόν ίδια με την Fast PWM με τη διαφορά ότι όταν ο TCNTn φτάσει στην ανώτερη τιμή δε
μηδενίζει, αλλά αρχίζει να μετράει αντίστροφα (ελαττώνεται) μέχρι να φτάσει στο
μηδέν όπου ξεκινάει να αυξάνει ξανά. Όταν υπάρξει ισότητα τοποθετείται (ή μηδενίζει
στην ανάστροφη λειτουργία) η OCnx όταν ο TCNTn βρίσκεται στην ανοδική φάση και το αντίθετο στην
καθοδική. Η TOVn τοποθετείται
όταν κατά την ελάττωση φτάσει στο μηδέν.
Οι Timers 16bit διαθέτουν περισσότερους τρόπους λειτουργίας από τους Timers 8bit και για αυτό το λόγο ο έλεγχος γίνεται από 4 bit (WGMn3:0). Οι επιπλέον
τρόπου λειτουργίας εντοπίζονται κυρίως στις PWM λειτουργίες όπου ο TCNTn
αυξάνει μέχρι το Top το οποίο
μπορεί να είναι 8, 9 ή 10 bit ή
να εξαρτάται από τον OCRnx ή ICRn[5]. Υπάρχει
επίσης η λειτουργία Phase and Frequency Correct PWM Mode όπου η μοναδική
διαφορά της με την Phase Correct PWM Mode είναι
ότι στην πρώτη ο καταχωρητής OCRnx ενημερώνεται
από τον αντίστοιχο buffer όταν
ο TCNTn βρίσκεται στο Top ενώ στη δεύτερη στο Bottom.
©2019 Πορλιδάς Δημήτριος
|