Timers/Counters - PWM στον ATmega2560

 

Συγγραφέας: Πορλιδάς Δημήτριος

Βιογραφικό Σημείωμα

electronics@porlidas.gr

Facebook

Linkedin


 

 

Οι 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 Πορλιδάς Δημήτριος

 


[1] Η διακοπή προκαλείται αν είναι ενεργοποιημένη από το bit TOIEn του καταχωρητή TIMSKn.

[2] Η διακοπή προκαλείται αν είναι ενεργοποιημένη από το bit OCIEnx του καταχωρητή TIMSKn.

[3] Η διακοπή προκαλείται αν είναι ενεργοποιημένη από το bit OCIEnx του καταχωρητή TIMSKn.

[4] Η διακοπή προκαλείται αν είναι ενεργοποιημένη από το bit TOIEn του καταχωρητή TIMSKn.

[5] Ο ICRn είναι ένας καταχωρητής όπου μπορεί να πάρει την τιμή του TCNTn όταν υπάρχει εξωτερική ενεργοποίηση στο pin ICPn ή από την έξοδο του αναλογικού συγκριτή ώστε να αποδοθεί χρονικό αποτύπωμα σε ένα γεγονός.   

 

Σας ευχαριστώ για την υποστήριξή σας ώστε να γίνει η ιστοσελίδα μου καλύτερη.

© 2019 Πορλιδάς Δημήτριος