ADC στον ATmega16

 

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

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

electronics@porlidas.gr

Facebook

Linkedin


 

 

Οι AVR διαθέτουν αναλογικές εισόδους για σύγκριση ή μετατροπή σε ψηφιακή τιμή. Ο ATmega16 διαθέτει δύο εισόδους σύγκρισης, ΑΙΝ0 ΑΙΝ1 (PB2PB3) και οκτώ εισόδους για μετατροπή ADC0ADC7 (PA0PA7). Η σύγκριση μπορεί να γίνει είτε μεταξύ των ΑΙΝ0ΑΙΝ1 είτε μεταξύ της ΑΙΝ0 και μιας από τις οκτώ αναλογικές εισόδους ADC0 ADC7. Η θετική είσοδος του συγκριτή είναι είτε η ΑΙΝ0 είτε η τάση αναφοράς του μικροελεγκτή. Η αρνητική είσοδος μπορεί να είναι η ΑΙΝ1 ή μια από τις οκτώ αναλογικές. Για όσο η θετική είσοδος είναι μεγαλύτερη από την αρνητική, η έξοδος του συγκριτή είναι τοποθετημένη ενώ καθαρίζει όταν η αρνητική γίνει μεγαλύτερη. Κατά την αλλαγή η έξοδος μπορεί να προκαλέσει διακοπή[1] ή να ενεργοποιήσει τη λειτουργία Timer/Counter1 Input Capture. Οι ρυθμίσεις του συγκριτή γίνονται από τους καταχωρητές SFIOR και ACSR.

Οι οκτώ αναλογικές είσοδοι μπορούν λειτουργήσουν ως μονές είσοδοι, μόνο για θετικές τάσεις ως προς τη γείωση (αρνητική τροφοδοσία του συστήματος) ή ανά δύο ως διαφορικοί είσοδοι,[2] όπου θετική – αρνητική καθορίζονται από τον αντίστοιχο καταχωρητή ADMUX και είναι ανεξάρτητες από την τροφοδοσία του συστήματος. Η ψηφιακή έξοδος του μετατροπέα είναι 10bit και μετά τη μετατροπή το αποτέλεσμα αποθηκεύεται στους καταχωρητές ADCL και ADCH. Όταν γίνεται χρήση μονών εισόδων το αποτέλεσμα των 10bit είναι μη προσημασμένος αριθμός[3] και συνεπώς μπορεί να πάρει τιμές 0 – 1023. Όταν γίνεται χρήση διαφορικών εισόδων είναι δυνατό να υπάρξουν αρνητικές τιμές και για αυτό το αποτέλεσμα των 10bit είναι προσημασμένος αριθμός[4] και μπορεί να πάρει τιμές -512 – 511. Η μετατροπή γίνεται ως προς την τάση αναφοράς,[5] η οποία μπορεί να είναι η AVCC (τάση τροφοδοσίας του αναλογικού τμήματος του μικροελεγκτή) ή η εσωτερική τάση αναφοράς VREF[6] ή μια εξωτερική τάση αναφοράς συνδεδεμένη στο pin AREF.[7]

Ο τρόπος που γίνεται η αποθήκευση των 10bit εξαρτάται από την αντίστοιχη σημαία ADLAR του καταχωρητή ADMUX και μπορεί να είναι με δεξιά στοίχιση ή αριστερή. Κατά τη δεξιά στοίχιση τα 8 LSB του αποτελέσματος καταχωρούνται στον ADCL και τα δύο MSB στα bit0 και bit1 του ADCH (με το MSB στο bit1) ενώ όλα τα υπόλοιπα bit του ADCH είναι 0. Κατά την αριστερή στοίχιση τα 8 MSB του αποτελέσματος καταχωρούνται στον ADCH και τα δύο LSB στα bit7 και bit6 του ADCL (με το LSB στο bit6) ενώ όλα τα υπόλοιπα bit του ADCL είναι 0. Στον Πίνακα Ι παρουσιάζεται ένα παράδειγμα με το περιεχόμενο των καταχωρητών για προσημασμένους και μη αριθμούς στους δύο τρόπους στοίχισης.

                  Πίνακας Ι. Παράδειγμα καταχωρητών ADCL και ADCH.

ADCH

ADCL

 

0000 0011

0100 1011

Δεξιά στοίχιση, μη προσημασμένος δεκ. αρ. 843

1101 0010

1100 0000

Αριστερή στοίχιση, μη προσημασμένος δεκ. αρ. 843

0000 0011

0100 1011

Δεξιά στοίχιση, προσημασμένος δεκ. αρ. -181

1101 0010

1100 0000

Αριστερή στοίχιση, προσημασμένος δεκ. αρ. -181

Η δυνατότητα των δύο τρόπων στοίχισης μας επιτρέπει να απορρίπτουμε τα δύο bit από τα δέκα και να κάνουμε χρήση των υπόλοιπων οκτώ, έτσι ώστε να γίνεται πιο εύκολα η διαχείριση του αποτελέσματος. Αν για παράδειγμα δε μας ενδιαφέρει τόσο η ακρίβεια μπορούμε να επιλέξουμε αριστερή στοίχιση και να αγνοήσουμε τα 2 LSB διαβάζοντας μόνο τον ADCH. Πρέπει όμως να λάβουμε υπόψη ότι η μέγιστη τιμή[8] των 8bit αντιστοιχεί στην VREF. Στη συνέχεια παρουσιάζεται ένα παράδειγμα προετοιμασίας του ADC και μετατροπής, γραμμένο σε γλώσσα C.

uint8_t AdcOut1;

 

void InitADC (void)

{

ADCSRA = ((1 << ADEN) | (7 << ADPS0));   // ADC Enable, single conversion, 62.5kHz sample

ADMUX = ((1 << REFS0) | (1 << ADLAR));   // AVcc(REFS0:1 = 0->AREF, 1->AVCC, 3->IntRef 2.54V),

                       // left adjust result, PA0 (MUX0=0 by default)

}

 

void GetADC (void)

{

ADCSRA |= (1 << ADSC);                // Start conversion

while (!(ADCSRA & (1 << ADIF)));      // Wait for conversion to complete

ADCSRA |= (1 << ADIF);                // Set complete flag

AdcOut1 = ADCH;                       // Write data to variable

}

 

Η πρώτη ρουτίνα είναι για την προετοιμασία του ADC. Mε την πρώτη εντολή γίνεται η ενεργοποίηση των κυκλωμάτων του μαζί με την επιλογή εκκίνησης μετατροπής[9]  (επιλέγεται απλή μετατροπή) και συχνότητας λειτουργίας του κυκλώματος διαδοχικής προσέγγισης[10] (επιλέγεται 62.5kHz). Με τη δεύτερη εντολή γίνεται η επιλογή της τάσης αναφοράς και αριστερής στοίχισης.

Η δεύτερη ρουτίνα είναι για τη μετατροπή. Με την πρώτη εντολή τοποθετείται η σημαία ADSC και αυτό σηματοδοτεί την εκκίνηση της μετατροπής. Η δεύτερη εντολή είναι για αναμονή του επεξεργαστή ώσπου να ολοκληρωθεί η μετατροπή, με την επόμενη, στη συνέχεια, τοποθετείται η σημαία ολοκλήρωσης και με την τελευταία εντολή γίνεται η ανάγνωση του αποτελέσματος από τον ADCH. Αν θέλουμε να χρησιμοποιήσουμε και τα 10bit του αποτελέσματος της μετατροπής θα πρέπει να γίνει ανάγνωση και του ADCL και μάλιστα η ανάγνωση του ADCL πρέπει να γίνεται πάντα πρώτα γιατί ο επεξεργαστής θεωρεί ότι μετά την ανάγνωση του ADCH ολοκληρώνονται οι διαδικασίες ανάγνωσης και απαγορεύει την πρόσβαση στους καταχωρητές. Στη συνέχεια παρουσιάζεται το παραπάνω παράδειγμα τροποποιημένο ώστε να γίνεται ανάγνωση και καταχώρηση του αποτελέσματος των 10bit σε μεταβλητή 16bit.       

uint8_t AdcOut1;

uint8_t AdcOut0;

int16_t AdcOut10;

//int16_t AdcOut10n;

 

void InitADC (void)

{

ADCSRA = ((1 << ADEN) | (7 << ADPS0));  // ADC Enable, single conversion, 62.5kHz sample

ADMUX = ((1 << REFS0) | (1 << MUX4));   // AVcc(REFS0:1 = 0->AREF, 1->AVCC, 3->IntRef 2.54V),

                       // right adjust result, PA0-PA1

}

 

void GetADC (void)

{

ADCSRA |= (1 << ADSC);               // Start conversion

while (!(ADCSRA & (1 << ADIF)));     // Wait for conversion to complete

ADCSRA |= (1 << ADIF);               // Set complete flag

AdcOut0 = ADCL;                      // Write data to variable

AdcOut1 = ADCH;                      // Write data to variable

AdcOut10 = 0;

AdcOut10 = AdcOut1<<8;               // Write high byte to 16bit variable

AdcOut10 |= AdcOut0;                 // Write low byte to 16bit variable

if (bit_is_set(AdcOut1,1))           // Check 10bit result sign

AdcOut10 |= 0b1111110000000000;      // if negative do sign extension

//  AdcOut10n = AdcOut10 + 3;            // Reject CMV if necessary

}

 

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


[1] Η διακοπή μπορεί να προκληθεί από το ανερχόμενο, το κατερχόμενο ή την αλλαγή λογικής στάθμης της εξόδου του συγκριτή.

[2] Τα ζευγάρια ADC0 – ADC1 και ADC2 – ADC3 μπορούν να προγραμματιστούν ώστε να έχουν απολαβή x10 ή x200.

[3] Δεν είναι δυνατό να συνδέσουμε τάση αρνητικότερη από τη γείωση (αρνητικό της τροφοδοσίας του συστήματος) και συνεπώς δε γίνεται να έχουμε αρνητικό αποτέλεσμα.

[4] Οι αρνητικές τιμές δίνονται με τη μορφή του συμπληρώματος ως προς 2.

[5] Η μέγιστη τιμή της μετατροπής αντιστοιχεί στην τάση αναφοράς που χρησιμοποιείται.

[6] Bandgap reference voltage: VREF=2.56V για τον ATmega16.

[7] Όταν δε χρησιμοποιείται εξωτερική τάση αναφοράς το pin πρέπει να είναι συνδεδεμένο σε έναν πυκνωτή προς τη γείωση.

[8] Η μέγιστη τιμή για τα 8bit είναι -128 ή 127 ή 255 ανάλογα με το αν είναι αρνητικός ή θετικός προσημασμένος αριθμός ή μη προσημασμένος αντίστοιχα.

[9] Ο ADC μπορεί να κάνει αυτόματη μετατροπή (Auto Trigger mode) ή απλή -μετά από αίτημα- (Single Conversion mode), ανάλογα με την τιμή της σημαίας ADATE. Στην αυτόματη μετατροπή η εκκίνηση μπορεί να γίνει από τον αναλογικό συγκριτή, εξωτερική διακοπή στο ΙΝΤ0 ή από τον Timer/Counter1, ανάλογα με την τιμή του ADTS2:0 του καταχωρητή SFIOR.

[10] Γίνεται με διαίρεση (prescaler) του ρολογιού συστήματος ανάλογα με την τιμή του  ADPS2:0 του καταχωρητή ADCSRA.

 

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

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