sâmbătă, 27 august 2011

Porturile

Porturile unui microcontroler sunt cele mai folosite dispozitive de schimb de date cu exteriorul.Avantajul cel mare este că ele sunt paralele, putându-se astfel relaiza schimbul a mai multor biţi de date simultan.În viziunea programatorului porturile nu sunt altceva decât niste regiştrii prin care se pot scrie şi citi date.Lungimea unui port este influenţată de numărul de biţi pe care procesorul îi poate executa la un moment dat.În cazul nostru, microcontrolerul ATMega8 este pe 8 biţi deci şi dimensiunea regiştrilor va fi tot de 8 biţi.De obicei unui port sunt asociaţi 2 regiştrii, unul care setează direcţia pinilor iar altul care realizează schimbul de date între unitatea centrală a microcontrolerului şi exterior.
Microcontrolerului ATMega8 are asociat unui port 3 regiştrii,DDR care setează direcţia pinilor,PORT care setează datele de ieşire ale portului la nivel de pin şi PIN care memorează intrările microcontrolerului la nivel de pin.Numărul porturilor este tot 3 şi sunt numite B,C şi D.Dacă ne uităm pe schema generală avem următoarea configuraţie:
Pinii PB0-PB7 corespund portului B,PC0-P6 portului C iar PD0-PD7 portului D.Observăm că portul C are doar 7 intrări.Ei bine ultimul bit din regiştrii asociaţi portului nu este flosit.Pentru a vă face o imagine mai bună asupra legăturii dintre pinii microcontrolerului şi regiştri asociaţi portului urmăriţi figura de mai jos:
Observăm că pinului 0 îi corespunde locaţiei 0 a portului, pinului 1 locaţiei 1 şi tot aşa.În cazul de faţă pinii sunt notaţi cu P, pentru portul B avem PB , pentru portul C avem PC iar pentru portul D avem PD.
Pentru a exemplifica modul de configurare şi de utilizare a porturilor din ATMega8 voi crea un exempu simplu în care vom avea setaţi primii 4 pini ai portului B ca pini de intrare iar primii 4 pini ai portului C ca pini de ieşire.La pinii de intrare vor fi legate 4 butoane iar la pinii de ieşire ai portului C vom lega 4 LED-uri.La apăsarea butoanelor vom dori ca led-urile corespunzătoare butoanelor apăsate să se aprindă.
Programul şi schema electrică le puteţi downloada de la secţiunea Download-Porturi-Aplicaţie1.
Schema electrică în Proteus a aplicaţiei este următoarea:
Programul din memoria microcontrolerului nu va face alceva decât să preia informaţia de la portul B şi să o transmită la portul C.

Pentru scrierea programului în CodeVision AVR procedaţi exat cum v-am arătat mai înainte la prezentarea generală a programului însă la secţiunea de setare mergeţi la Ports>Port C şi setaţi primii 4 biţi de direcţie ca în figura de mai jos apoi daţi din meniul File, Generate ,Save and exit:
După cum am mai spus, direcţia pinilor se setează cu ajutorul registrului DDR(Data Direction Register).Dacă veţi urmări în secţiunea de setare a programului la începutul funcţiei main veţi observa că DDRB =0x00,adică toţi pinii sunt setaţi ca intrare, iar DDRC = 0x0F, adică doar primii 4 pini sunt setaţi ca ieşiri, restul fiind setaţi ca intrări.Reprezentarea valorii 0x0F este o reprezentare în hexazecimal şi este echivalentă cu 0b00001111 în binar şi cu 15 în zecimal.Dacă nu sunteţi familiarizaţi cu sistemul binar şi hexazecimal puteţi afla cum se fac conversile aici:http://ro.wikipedia.org/wiki/Sistem_binar
În bucla while,bucla de ciclare infinită, vom avea o singură linie care va transfera datele de la intrarea portului B la ieşirea portului C adică vom transfera conţinutul registrului PINB în registrul PORTC:
PORTC = PINB;
Programul este gata putând fi deja compilat.Pentru încărcarea programului în schema din Proteus daţi dublu click pe micorocontroler.Ca rezultat veţi deschide o fereastră cu titlul Edit Component.Mergeţi la câmpul Program File şi adăugaţi fişierul program.Acest fişier se găseşte în locţia în care aţi salvat anterior proiectul din Code Vision AVR, în directorul Exe.Dacă compilarea codului a decurs normal ar trebui să aveţi ca rezultat un fişier cu extensia *.hex.
Dacă totul a decurs bine până aici puteţi simula aplicaţia fără nici o problemă.La apăsarea butoanelor ar trebui să se aprindă LED-urile corespunzătoare.Fizic aplicaţia o puteţi vedea aici:


Următoarea aplicaţie este ceva mai complexă, ea având rolul simulării unei instalaţii luminoase pentru pomii de crăciun la care vom avea posibilitatea alegerii unui program de funcţionare prin apăsarea unor butoane.De data asta vom folosi tot portul B ca port de intrare la care vom lega la primii 4 pini, 4 butoane cu care vom alege modul de funcţionare iar ca port de ieşire vom folosi portul D la pinii căruia vom lega 8 LED-uri.Dacă se apasă primul buton, adică bitul 0 al registrului PINB este 1 logic, vom avea modul 1 de funcţionare,dacă se apasă butonul 2, adică bitul 1 al registrului PINB este 1 logic,vom avea modul 2 de funcţionare şi tot aşa până la butonul 4.Dacă nu este apăsat nici un buton se vor activa pe rând toate cele 4 moduri.Dacă se apasă două sau mai multe butoane nu se va întâmpla nimic.
Programul şi schema electrică le puteţi downloada de la secţiunea Download-Porturi-Aplicaţie 2.
Schema elecrtrică a aplicaţiei în Proteus va fi următoarea:

Pentru scrierea codului procedaţi exact ca la primul exerciţiu însă setaţi de data aceasta toţi pinii portului D ca fiind pini de ieşire.
Pentru o lizibilitate mai buna a codului am ales să am câte o funcţie pentru fiecare mod de funcţionare,funcţii care sunt plasate înaintea funcţiei main.Pentru modul 1 codul este următorulul:

void
mod1(void)
{
PORTD = 0b00000001;
while(PORTD)
{
delay_ms(100);
PORTD = PORTD<<1;
}
}

La început iniţializăm PORTD-ul cu valoarea 0b00000001 deoarece dorim ca primul led să fie aprins.Pentru ca al doilea LED să se aprindă şi să se stingă primul trebuie să mutăm 1-ul de pe prima poziţie pe poziţia a doua.Acest lucru se face prin codul PORTD = PORTD<<1 care reprezintă şiftare bitului 1.După execuţia primului ciclu while noua valoare a PODRTD-ului va fi 0b00000010.Pentru a vă face o idee cum funcţionează funcţia urmăriţi codul de mai jos:
Iniţializare :PORTD = 0b00000001
Ciclu 1:PORTD = 0b00000010
Ciclu 2:PORTD = 0b00000100
Ciclu 3:PORTD = 0b00001000
Ciclu 4:PORTD = 0b00010000
Ciclu 5:PORTD = 0b00100000
Ciclu 6:PORTD = 0b01000000
Ciclu 7:PORTD = 0b10000000
Ciclu 8:PORTD = 0b00000000
Deoarece la ciclul 8 valoarea PORTD va fi 0 se va ieşi din ciclu while şi totodată şi din funcţia mod1.

Observăm că aici apare o funcţie pe care nu am avut ocazia să o folosesc mai înainte şi anume delay_ms.Aceasta are rolul de a întârzia programul cu n milisecunde, în cazul nostru 100 de milisecunde.Pentru a folosi această funcţie trebuie să includeţi librăria delay.h.Probabil că vă întrebaţi de ce este nevoie de aşa ceva.Ei bine dacă nu am avea un timp între schimbările portului am vedea toate LED-urile aprinse datorită vitezei mari de comutare.

Pentru modul 2 de funcţionare codul este asemănător însă operaţia de şiftare se face de la stânga la dreapta.

void mod2(void)
{
PORTD = 0b10000000;
while(PORTD)
{
delay_ms(100);
PORTD = PORTD>>1;
}
}

În modul 3 vom aprinde mai întâi led-urile din mijloc (pinii 3 şi 4), apoi vom stinge led-urile din mijloc aprinzând led-urile următoare( pinii 2 şi 5) şi tot aşa până la aprinderea led-urilor 1 şi 8(pinii 0 şi 7).

void mod3(void)
{
PORTD = 0b00011000;
delay_ms(100);
PORTD = 0b00100100;
delay_ms(100);
PORTD = 0b01000010;
delay_ms(100);
PORTD = 0b10000001;
delay_ms(100);
}

Modul 4 se va comporta exact invers modului 3,aprinzând ledurile din exterior spre interior.

void mod4(void)
{
PORTD = 0b10000001;
delay_ms(100);
PORTD = 0b01000010;
delay_ms(100);
PORTD = 0b00100100;
delay_ms(100);
PORTD = 0b00011000;
delay_ms(100);
}

În bucla de ciclare infinită vom face o selecţie a acestor 4 moduri în funcţie de butoanele pe care le-am apăsat.

while(1)
{
switch(PINB)
{
//se apasa primul buton si se seteaza modul 1 de functionare
case 0b00000001:
mod1();
break;
//se apasa al doilea buton si se seteaza modul 2 de functionare
case 0b00000010:
mod2();
break;
//se apasa al treilea buton si se seteaza modul 3 de functionare
case 0b00000100:
mod3();
break;
//se apasa al patrulea buton si se seteaza modul 4 de functionare
case 0b00001000:
mod4();
break;
//daca nu s-a apasat nici un buton se vor parcurge toate cele 4 moduri
case 0b00000000:
mod1();
mod2();
mod3();
mod4();
//daca s-a apasat mai multe butoane nici un mod va fi activ
default:
PORTD = 0x00;
}
};

Pentru a vedea ce butoane au fost apăsate trebuie să verificăm pinii portului B.Această verificare se face prin swhitch care verifică valorile registrului PINB.Dacă s-a apăsat butonul 1 vom avea valoarea 0b00000001 şi se execută funcţia mod1,dacă s-a apăsat butonul 2 vom avea valoarea 0b00000010 şi se execută funcţia mod2, şi tot aşa până la butonul 4.Dacă nu s-a apăsat nici un buton ,adică PINB = 0b00000000 atunci se vor executa pe rând cele 4 funcţii,iar dacă avem altă combinaţie a registrului PINB valoarea lui PORTD va fi 0.

Din păcate programul nostru are un neajuns şi anume atunci când este apăsat un buton nu se rulează rapid modul selectat ci trebuie să aşteptăm teminarea modului anterior.Acest lucru se poate rezolva prin întreruperi după cum vom vedea mai târziu.

Implementarea fizică a aplicaţiei o puteţi urmări aici:

1 comentarii:

cristi spunea...

Interesante explicatiile. Cautam de mult asa ceva.
Oare cum as putea sa fac un microcontroler sa functioneza ca un driver - 8 intrari cu coduri binare si 10 iesiri binare.
Ca exemplu: intrare avem codul 10011001
iar pe iesire avem 1110110111 .

va multumesc

Trimiteți un comentariu

Twitter Delicious Facebook Digg Stumbleupon Favorites More