AVR-GCC. ADC (Analog to Digital Converter).

Ο αναλογικο-ψηφιακός μετατροπέας μετατρέπει αναλογικά σήματα σε ψηφιακές τιμές. Μερικά μοντέλα των AVR έχουν ενσωματωμένους πολυκάναλους ADCs. Η ακρίβεια με την οποία αποδίδεται ένα αναλογικό σήμα εξαρτάται από την ανάλυση του ADC. Η ανάλυση είναι ο αριθμός των bit με τον οποίο o ADC διαβάζει το αναλογικό σήμα. Έτσι έχουμε ADC των 8-bit, των 10-bit ή περισσότερο. Οι ADCs που υπάρχουν τώρα στους AVR έχουν μέγιστη ανάλυση των 10-bit.

Τεκμηρίωση του ATmega8.
* Άρθρο της WikiPedia για τους ADC.

Ένας ADC με ανάλυση των 8-bit μπορεί να αποδώσει το αναλογικό σήμα με ακρίβεια 1/256 της μέγιστης τιμής. Αν υποθέσουμε πως έχουμε ένα σήμα από 0 έως 5 volts και ανάλυση 3-bit οι τιμές μπορεί να είναι 0v, 0.625v, 1.25v, 1.875v, 2.5v, 3.125v, 3.75v, 4.37v, 5v.
Οι παραπάνω τιμές είναι κατά προσέγγιση. Τώρα, όσο ποιο μεγάλη είναι η ανάλυση (περισσότερα bits) του ADC τόσο ποιο ακριβής θα είναι η τιμή της μέτρησης.

Ο εσωτερικός ADC των AVR.
Για να είμαστε ποιο ακριβείς οι AVR με εσωτερικό ADC έχουν πολλά κανάλια. Τα πολλά κανάλια σημαίνουν πως μπορεί να έχουμε μέχρι και 10 αναλογικές εισόδους αλλά μόνο έναν ADC. Πριν την πραγματοποίηση μίας μέτρησης σε κάποιο pin το κανάλι του ADC συνδέεται με το με το συγκεκριμένο pin.

Η μετατροπή μέσα στον AVR βασίζεται στις διαδοχικές προσεγγίσεις. Για ακριβείς μετρήσει το pin AVcc πρέπει να συνδέετε στην Vcc με ένα δικτύωμα L-C ώστε ώστε να απομονώνεται ο ADC από τυχόν αιχμές και τα βυθίσματα τάσης. Στην τεκμηρίωση των AVR (σελίδα 196 για τον atmega8) συστήνεται η χρήση πηνίου 10 uH και πυκνωτή 100 nF.

Το αποτέλεσμα της μετατροπής σχετίζεται με την τάση αναφοράς. Οι τωρινοί AVRs προσφέρουν τρεις επιλογές.

ADCL, ADCH. ADC Data Register.
Όταν ολοκληρωθεί μία μετατροπή η τιμή της λαμβάνεται από αυτούς τους δύο καταχωρητές. Από τα bit του ADCH μόνο τα δύο λιγότερο σημαντικά χρησιμοποιούνται. Πρέπει πάντα να διαβάζονται και οι δύο καταχωρητές και πάντα με την σειρά. Ο ADCL πρώτα και μετά ο ADCH. Η τιμή της μέτρησης λαμβάνεται ως εξής.

  • Μία εξωτερική τάση αναφοράς με μέγιστο την τιμή της Vcc στο pin AREF. Η ελάχιστη τιμή δεν μπορεί να είναι οποιαδήποτε. Δείτε σχετικά στην τεκμηρίωση του μικροελεγκτή.
  • Μια εσωτερική τάση αναφοράς. Οι AVRs που έχουν εσωτερικό DAC έχουν την επιλογή για την εσωτερική αυτή τάση (2.56 ή 1.1 volt. Εξαρτάτε από τον τύπο. Δείτε στην τεκμηρίωση του μικροελεγκτή). Στην τεκμηρίωση υπάρχει και η ακρίβεια για την τάση αυτή.
  • Την τάση AVcc σαν τάση αναφοράς.

Όταν χρησιμοποιείτε η εσωτερική τάση ή η τάση στο AVcc συνίσταται η χρήση ενός πυκνωτή μεταξύ του pin AREF και της γείωσης. Το ποια τάση αναφοράς θα χρησιμοποιηθεί καθορίζεται από τα bit REFS1/REFS0 του καταχωρητή ADMUX. Η προς μέτρηση τάση πρέπει να είναι μεταξύ του ορίου που θεσπίζει η AREF (εσωτερική ή εξωτερική) με το AGND.

Ο ADC μπορεί να χρησιμοποιηθεί σε δύο διαφορετικού ρυθμούς λειτουργίας:

Απλή Μετατροπή (Single Conversion)
Σε αυτή την λειτουργία ο DAC ξεκινά από το πρόγραμμα για κάθε μέτρηση.

Ελεύθερη λειτουργία (Free Running)
Σε αυτή την λειτουργία ο DAC ανιχνεύει συνεχώς την εφαρμοζόμενη τάση και εκχωρεί την τιμή στο ADC Data Register.

Οι καταχωρητές του ADC.
Ο ADC έχει τους δικούς του καταχωρητές. Παρακάτω είναι μία περιγραφή του ADC καταχωρητή του atmega8. Οι διαφορές με τους άλλους AVR είναι μικρές. Δείτε στην τεκμηρίωση του μικροελεγκτή.

ADCSRA. ADC Control Status Register A.
Σε αυτόν τον καταχωρητή προσδιορίζουμε πως θέλουμε να χρησιμοποιήσουμε τον καταχωρητή. Η δομή του καταχωρητή είναι η ακόλουθη.

ADEN. ADC Enable.
Για να χρησιμοποιηθεί ο ADC πρέπει να ενεργοποιηθεί (1) το bit αυτό. Διαφορετικά τα pins θα χρησιμοποιούνται σαν είσοδοι/έξοδοι γενική χρήσης (GPIO General Purpose I/O).

ADSC. ADC Start Conversion.
Σε ρυθμό λειτουργίας Single Conversion ενεργοποιούμε (1) το bit για να γίνει η κάθε μέτρηση. Σε ρυθμό λειτουργίας Free Running ενεργοποιούμε (1) το bit για να ξεκινήσει η πρώτη μέτρηση. Από την στιγμή που θα ενεργοποιηθεί για πρώτη φορά ο ADC θα χρειαστούν κάποιες επιπρόσθετες μετατροπές πριν την κυρίως μετατροπή. Αυτό γίνεται για λόγους αρχικοποίησης του ADC. Όσο διαρκεί η μετατροπή το bit παραμένει σε λογικό 1 και μετά επιστρέφει σε λογικό 0.

ADFR. ADC Free Running select.
Το bit αυτό καθορίζει τον τρόπο λειτουργίας του ADC. Αν είναι 1 ο ADC είναι σε λειτουργία Free Running και ο καταχωρητής δεδομένων ενημερώνετε συνεχώς. Αν είναι μηδέν ο ADC εκτελεί μία μόνο μετατροπή Single Conversion.

ADIF. ADC Interrupt Flag.
Το bit αυτό είναι 1 όταν μία μετατροπή του ADC έχει ολοκληρωθεί και έχει ενημερωθεί ο ADC Data Register. Το ADC Conversion Interrupt εκτελείτε αν το bit ADIE και το I-bit στον SREG είναι 1. Το ADIF “καθαρίζεται” (λογικό 0) όταν εκτελείτε το interrupt ή εναλλακτικά όταν το γράψουμε σε λογικό 1.

ADIE. ADC Interrupt Enable.

Όταν το bit αυτό το γράψουμε σε λογικό ένα και το I-bit στον SREG είναι 1 τότε ενεργοποιείται το ADC Conversion Interrupt.

ADPS2..ADPS0. ADC Prescaler Select bits.
Τα bits αυτά καθορίζουν τον συντελεστή διαίρεσης μεταξύ της συχνότητας λειτουργία του μικροελεγκτή (clock) και την είσοδο στο clock του ADC. Ο ADC απαιτεί ξεχωριστό χρονισμό, που μπορεί να παραχθεί από αυτό του μικροελεγκτή. Ο χρονισμός του ADC πρέπει να είναι μεταξύ 50 και 200 kHz. Ο prescaler λοιπόν πρέπει να πάρει τέτοια τιμή ώστε η συχνότητα χρονισμού της cpu προς τον συντελεστή διαίρεσης να είναι μεταξύ 50 και 200 kHz. Αν έχουμε για παράδειγμα συχνότητα λειτουργίας 4 MHz θα έχουμε:

Οπότε ο συντελεστής μας μπορεί να είναι 32 ή 64. Αν θέλουμε την γρηγορότερη μετατροπή επιλέγουμε 32.

ADCL, ADCH. ADC Data Register.
Όταν ολοκληρωθεί μία μετατροπή η τιμή της λαμβάνεται από αυτούς τους δύο καταχωρητές. Από τα bit του ADCH μόνο τα δύο λιγότερο σημαντικά χρησιμοποιούνται. Πρέπει πάντα να διαβάζονται και οι δύο καταχωρητές και πάντα με την σειρά. Ο ADCL πρώτα και μετά ο ADCH. Η τιμή της μέτρησης λαμβάνεται ως εξής.

x = ADCL;       // Για x uint16_t
x += (ADCH<<8); // Συνολικά 10 bit
                // Τα 2 lsb του ADCH πρέπει να γίνουν
                // msb στον x οπότε << 8 (bitwise left 8 θέσεις)
// ή

x = ADCW; // εξαρτάτε από τον κάθε AVR(δείτε στο avr/ioxxx.h πχ. iom8.h)

ADMUX. ADC Multiplexer Select Register.
Με τον καταχωρητή αυτόν επιλέγεται ποιο κανάλι θα μετρηθεί.

REFS1, REFS0. Reference Selection bits.
Με αυτά τα bit ρυθμίζουμε την τάση αναφοράς. Κατά την αλλαγή παρατηρούνται κάποιες καθυστερήσεις μερικών msec μέχρι να “ετοιμαστεί” ο ADC.

ADLAR. ADC Left Adjust Result.
Το bit αυτό καθορίζει την μορφή του αποτελέσματος του ADC. Αν είναι σε λογικό 1 το αποτέλεσμα ρυθμίζεται αριστερά (Left Adjust). Αν είναι ο ρυθμίζεται δεξιά (Right Adjust). Αλλαγή στο bit επηρεάζει το αποτέλεσμα άμεσα. Ακόμη και στην μέση μία μετατροπής.

MUX4 … MUX0.
Αυτά τα 5 bit επιλέγουν ποιο κανάλι θα μετρηθεί. Πχ. Για το ADC3 του atmega8 που έχει 8 κανάλια (στην έκδοση TQFP) θα είναι 0011. Αν τα bit αλλάξουν κατά την διάρκεια μίας μετατροπής τότε δεν θα έχουν καμιά επίδραση μέχρι το τέλος της μετατροπής. Αυτό πρέπει να λαμβάνεται σοβαρά υπόψιν όταν θέλουμε σε λειτουργία Free Running. Συνίσταται να γίνεται χρήση της λειτουργίας Free Running μόνο κατά την χρήση ενός καναλιού.

Χρήση του ADC.
Για να ενεργοποιήσουμε τον ADC θέτουμε το ADEN bit του ADSRC. Στο ίδιο βήμα επιλέγουμε και τρόπο λειτουργίας.
Ένα μικρό παράδειγμα για ρυθμό λειτουργίας Single Conversion για τον ATmega8 και χρήση της εσωτερική τάσης αναφοράς (2.56 volts για τον atmega8). Η τάση εισόδου δεν πρέπει να ξεπερνά την τιμή αυτή. Μπορούμε να χρησιμοποιήσουμε διαιρέτη τάσης για μεγαλύτερες τιμές στην είσοδο. Το αποτέλεσμα του ADC θα είναι 0 για τάση 0 και 1023 (10 bit = 10^2 = 1024 καταστάσεις. 0..1023) για τάση ίση με την τάση αναφοράς V_REF.
Σε μία εφαρμογή στην πράξη θα ξεκινούσαμε τον ADC και μετά να μετράει στα διάφορα κανάλια. Αυτό το κάνουμε διότι η ενεργοποίηση του ADC και κυρίως η τάση αναφοράς χρειάζεται μερικές δεκάδες usec. Επίσης το πρώτο αποτέλεσμα του ADC είναι άκυρο και δεν χρησιμοποιείτε.

#include <avr/io.h>
#include <stdio.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "uart.h"

/*Η παρακάτω δήλωση ελέγχει αν στον compiler έχουμε βάλει την παράμετρο F_CPU.
Αν όχι, την περνά. */

#ifndef F_CPU
#warning "H F_CPU den exei oristei 8a parei thn timh 1000000"
#define F_CPU 1000000UL  //  Use unsigned long
#endif

#define BAUD 4800UL //Ρυθμός Baud

// Υπολογισμοί.
#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1) // ”Έξυπνη” στρογγυλοποίηση
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))   // Πραγματικός Ρυθμός Baud
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD)    // Σφάλμα ανά 1000 μέρη.

#if ((BAUD_ERROR<990) || (BAUD_ERROR>1010))
#error To sfalma ston ry8mo Baud einai megalytero toy 1%, mataiosh!
#endif

//adjust UARTsendChar() function for stream
static int UARTsendstream(char c, FILE *stream);
//----set output stream to UART----
static FILE uart_str = FDEV_SETUP_STREAM(UARTsendstream, NULL, _FDEV_SETUP_WRITE);

static int UARTsendstream(char c , FILE *stream){
uart_putc(c);
return 0;
}


void adc_init(void);
uint16_t adc_read(uint8_t ADC_channel);


int main(void){

// Αρχικοποίηση του UART.
uart_init(UART_BAUD_SELECT(BAUD,F_CPU));

sei(); // Ενεργοποίηση των interrupt;

stdout = &uart_str;                           // Stream initialization.
uart_init( UART_BAUD_SELECT(BAUD,F_CPU) );    // UART initialization.

adc_init();


while(1){

printf("Potentiometer: %d ",adc_read(5));
printf("LDR: %d\n",adc_read(4));
_delay_ms(800);

};

return 0;
}

void adc_init(){

ADMUX |= (1<<REFS0);              // AVCC with external capacitor at AREF pin.

ADCSRA |= (1<<ADPS1)|(1<<ADPS0);  // Prescaler 8 (4 MHz/8=125KHz).

ADCSRA |= (1<<ADEN);              // Enable ADC.

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

}

uint16_t adc_read(uint8_t ADC_channel){

int16_t adc_val;


ADMUX = (ADMUX & 0xF0) | (ADC_channel & 0x0F);

ADCSRA |= (1<<ADSC);

while( ADCSRA & (1<<ADSC) );// wait until ADC conversion is complete

adc_val = ADC;

return adc_val;
}

Advertisements
This entry was posted in AVR, Electronics and tagged , , , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s