AVR-GCC. Βασικές είσοδοι/έξοδοι (I/O).

Οι Είσοδοι και Έξοδοι (I/O, In/Out) των AVR μικροελεγκτών είναι χωρισμένες σε ομάδες. Το όνομα κάθε ομάδας ακολουθεί τον όρο PORTx. Όπου x A, B, C, D. Στον ATmega8 για παράδειγμα έχουμε τις PORTB, PORTC, PORTD. Κάθε PORT περιέχει από 3 έως 8 εισόδους/εξόδους (pins/ακίδες).

Κάθε PORT σε έναν AVR έχει τρεις καταχωρητές ελέγχου. Τους DDRx, PORTx, PINx. Ο καταχωρητής PORTx δεν πρέπει να συγχέεται με τον γενικό όρο PORT που αναφέρεται στις εισόδους/εξόδους (στις ακίδες του μικροελεγκτή). Στο εξής θα αναφερόμαστε στις φυσικές εξόδους/εισόδους με πεζά Portx και στον καταχωρητή με κεφαλαία.

DDRx. Επιλογή για είσοδο ή έξοδο.
Ο καταχωρητής DDRx καθορίζει ποιο pin του μικροελεγκτή θα είναι είσοδος και ποιο έξοδος.Όταν κάποιο bit στον καταχωρητή αυτόν είναι σε λογικό 1 τότε το αντίστοιχο pin της Port θα είναι έξοδος. Όταν είναι σε λογικό 0 το pin θα είναι είσοδος.

Στο παραπάνω γράφημα για παράδειγμα έχουμε 5 εξόδους και 3 εισόδους. Στο πρόγραμμά μας θα το πετυχαίναμε για την (PortD του ATmega8) με την εξής δήλωση.

Απευθείας ανάθεση στον DDRD.

DDRD = 0b01110101; //Δυαδικό.
ή
DDRD = 117;       //Δεκαδικό.
ή
DDRD = 0x75;      //Δεκαεξαδικό.

Ποιο “σωστός” τρόπος.

DDRD |= (1<<PD0)|(1<<PD2)|(1<<PD4)|(1<<PD5)|(1<<PD6);

/*Δεν χρειάζεται να κάνουμε 0 τα bit των εισόδων
  αφού η αρχική κατάσταση του DDRD είναι 0b00000000 */

PORTx. Έξοδοι σε λογικό 0 ή 1.
Ο καταχωρητής PORTx ελέγχει αν μία έξοδος θα είναι σε λογικό 1 (Vcc) ή σε λογικό 0 (GND). Όταν κάποιο bit στον καταχωρητή αυτόν είναι σε λογικό 1 τότε η αντίστοιχη έξοδος θα είναι σε λογικό 1. Όταν είναι σε λογικό 0 η έξοδος θα είναι σε λογικό 0.

Στο παραπάνω γράφημα για μία Port που είναι όλα τα pins ορισμένα να είναι έξοδοι, 5 βρίσκονται σε λογικό 1. Αν είχαμε μερικά leds σε όλες τις εξόδους, μόνο τα 5 θα ήταν αναμμένα. Ο κώδικας για την PortD.

PORTD |= (1<<PD0)|(1<<PD2)|(1<<PD4)|(1<<PD5)|(1<<PD6);

PORTx. Είσοδοι και Pull-Up αντιστάσεις.
Όταν ένα pin σε έναν μικροελεγκτή είναι ορισμένο ως είσοδος είναι ευαίσθητο σε εξωτερικούς θορύβους (παράσιτα) που κάνει την ανάγνωση της κατάστασή του δύσκολη. Για τον λόγο αυτό υπάρχουν οι λεγόμενες Pull-Up* αντιστάσεις. Οι αντιστάσεις αυτές βρίσκονται εσωτερικά στον μικροελεγκτή. Όταν ενεργοποιηθεί για μία είσοδο τότε η είσοδος αυτή συνδέεται μέσω της αντίσταση με την Vcc και βρίσκεται σε λογικό 1. Στην συνέχεια με κάποιον διακόπτη μπορεί να πάρει στο GND και να βρίσκεται σε λογικό 0. Όταν δούμε μέσω του κώδικα μας λοιπόν πως κάποια είσοδος είναι σε λογικό 0 πάει να πει πως κάποιος ενεργοποίησε κάποιο διακόπτη.

Στο παραπάνω γράφημα για μία Port που είναι όλα τα pins ορισμένα να είναι είσοδοι, 5 βρίσκονται σε λογικό 1 αφού έχουν ενεργοποιημένες τις Pull-Up αντιστάσεις. Η κατάσταση των άλλων εισόδων δεν είναι εύκολο να προβλεφτεί αφού αλλάζει συνεχώς πολύ εύκολα. Ο κώδικας για την PortD.

PORTD |= (1<<PD0)|(1<<PD2)|(1<<PD4)|(1<<PD5)|(1<<PD6);

Pull-Up Resistors.

PINx. Ανάγνωση κατάστασης εισόδων.

Ο καταχωρητής PINx μας δείχνει την κατάσταση που βρίσκεται μία είσοδος του μικροελεγκτή. Όταν κάποιο bit στον καταχωρητή αυτόν είναι σε λογικό 1 σημαίνει πως η αντιστοιχεί είσοδος βρίσκεται σε λογικό 1 (Vcc). Όταν είναι σε λογικό μηδέν σημαίνει πως η αντίστοιχει είσοδος βρίσκεται σε λογικό 0 (GND).

Στο παραπάνω γράφημα για μία Port που είναι όλα τα pins ορισμένα να είναι είσοδοι, 5 βρίσκονται σε λογικό 1 και 3 σε λογικό 0. Ο κώδικας για την PortD.

uint8_t status;
status = PINx;

Ένα παράδειγμα.

Ας δούμε το παρακάτω κύκλωμα. Έχουμε συνδέσει 6 LED στα PC0 έως PC5 ενός μικροελεγκτή ATmega8 και ένα μπουτόν στο PB0. Θέλουμε να ανάβουν και να σβήνουν διαδοχικά τα LED όσο κρατάμε πατημένο το μπουτόν (παρατηρήστε πως το μπουτόν συνδέετε στην γη του κυκλώματος).

#include <avr/io.h>
#include <util/delay.h>  //Header file που περιέχει την _delay_ms()

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

int main(void){

    //PC0 έως PC5 ως έξοδοι.
    DDRC |= (1<<PC0)|(1<<PC1)|(1<<PC2)|(1<<PC3)|(1<<PC4)|(1<<PC5);

    //PB0 ως είσοδος
    DDRB |= (1<<PB0);

    //Ενεργοποίηση της Pull-Up αντίστασης για το PB0.
    PORTB |= (1<<PB0);

    //Βρόχος επανάληψης.
    while(1){

        /* Δευτερεύον βρόχος επανάληψης. Όσο το μπουτόν
           στο PB0 είναι πατημένο (δηλαδή σε λογικό 0)
           εκτελούνται οι εντολές.*/

        while ((PINB&(1<<PB0){
            PORTC = 0b00000001;     // Άναμμα του LED στο PC0. Σβήσιμο των άλλων.
            _delay_ms(100);         // Καθυστέρηση 0,1 δευτερόλεπτα (100 msec).
            PORTC = 0b00000010;     // Άναμμα του LED στο PC1.Σβήσιμο των άλλων.
            _delay_ms(100);
            PORTC = 0b00000100;     // Άναμμα του LED στο PC2. Σβήσιμο των άλλων.
            _delay_ms(100);
            PORTC = 0b00001000;     // Άναμμα του LED στο PC3. Σβήσιμο των άλλων.
            _delay_ms(100);
            PORTC = 0b00010000;     // Άναμμα του LED στο PC4. Σβήσιμο των άλλων.
            _delay_ms(100);
            PORTC = 0b00100000;     // Άναμμα του LED στο PC5. Σβήσιμο των άλλων.
            _delay_ms(100);
        };

        PORTC = 0b00000000;         // Σβήσιμο όλων των LED.

    };

    return 0;
}

Η παράσταση PINB&(1<<PB0) εκτελεί στην ουσία την λογική πράξη PINB&0b00000001. Έτσι το αποτέλεσμα θα είναι 0 ή 1. Ο AVR-GCC παρέχει έτοιμε συναρτήσεις για τον έλεγχο των bit.

Την bit_is_clear(PINx,Pxy) που επιστρέφει 1 αν το υπό εξέταση bit είναι 0. Την bit_is_set(PINx,Pxy) που επιστρέφει 1 αν το υπό εξέταση bit είναι 1. Όπου x A, B, C, D και y 0 έως 7.

Προκαθορισμένος αριθμός bit για I/O καταχωρητές.
Ο αριθμός των bit (πχ. PDx, DDDx και PINDx για την port D) στο αρχείο io.h από την avr-libc. Αυτό γίνεται μόνο για την βελτίωση της αναγνωσιμότητας του κώδικα. Για τον μεταγλωττιστή οι εκφράσεις (1<<PC7), (1<<DDC7), (1<<PINC7) είναι ίδιες με την (1<<7). Συγκεκριμένα ο μεταγλωττιστής αντικαθιστά το (1<<PC7) με το (1<<7). Ένα τμήμα για τις δηλώσεις τις πόρτας C του atmega8 στο αρχείο iom8.h.

...
/* PORTB */
#define PB7     7
#define PB6     6
#define PB5     5
#define PB4     4
#define PB3     3
#define PB2     2
#define PB1     1
#define PB0     0

/* DDRB */
#define DDB7    7
#define DDB6    6
#define DDB5    5
#define DDB4    4
#define DDB3    3
#define DDB2    2
#define DDB1    1
#define DDB0    0

/* PINB */
#define PINB7   7
#define PINB6   6
#define PINB5   5
#define PINB4   4
#define PINB3   3
#define PINB2   2
#define PINB1   1
#define PINB0   0
Advertisements
This entry was posted in AVR, Electronics. 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