duminică, 28 august 2011

Timer-ele - Timer 0

Timer-ele sunt sisteme integrate în microcontroler care au ca scop măsurarea unor intervale fixe de timp şi de a genera întreruperi la expirarea intervalului măsurat.Tot cu ajutorul timer-elor se pot genera trenuri de impulsuri de o anumită frecvenţă sau compararea a 2 intervale de timp.Timer-ele funcţionează independent de unitatea centrală a micrcontrolerului astfel eliminându-se momentele de timp în care microcontrolerul este blocat într-o buclă de aşteptare.
Timer-ele conţin un numărător liber central(NLC) care are rolul de a număra fiecare impuls de tact.Acest NLC este de fapt un registru de 8 sau 16 biţi care la fiecare impuls este incrementat cu o unitate.Numărătorului i se poate da o valoare de start cuprinsă între 00h/0000h şi FFh/FFFFh.Dacă NLC-ul are valoarea FFh/FFFFh şi primeşte un impuls el se resetează,noua valoare fiind 00h/0000h.Tot în momentul resetării numărătorul trimite un semnal către sistemul de întreruperi.
Microcontrolerul ATMega8 oferă 3 timere:Timer 0,Timer 1 şi Timer 2 însă momentan ne vom concentra asupra Timer-ului 0.

Timer/Counter 0
Timer-ul 0 este un timer de uz general pe 8 biţi care are următoarea schemă bloc:
În cazul de faţă NLC-ul este reprezentat de registrul TCNT0 la care avem acces de citire şi scriere.Observăm din schemă că o dată ce s-a atins valoarea 0xFF se trimite un semnal către logica de control care poate genera o cerere de întrerupere.Sursa semnalului care incrementază NLC-ul poate fi externă(T0) sau internă(semnalul de tact al microcontrolerului) care poate fi prescalată.La fiecare tact clkT0 numărătorul TCNT0 este incrementat:
Registrul TCCR0 are rolul de a selecta şi prescala susra semnalului de tact, el având forma:
Din acest registru vom folosi numai ultimii 3 biţi (CS02, CS01, CS00) pentru setare.Valorile pe care le poate lua şi seminificaţiile lor sunt următoarele:
000– nu se selectează nici o sursă de tact;
001– foloseşte ceasul intern fără prescalare;
010– foloseşte ceasul intern cu prescalarea 8 (clkT0/8);
011– foloseşte ceasul intern cu prescalarea 64 (clkT0/64);
100– foloseşte ceasul intern cu prescalarea 256 (clkT0/256);
101– foloseşte ceasul intern cu prescalarea 1024 (clkT0/1024);
110– foloseşte o sursă externă de tact la pinul T0.Se ia în considerare frontul descrescător;
111– foloseşte o sursă externă de tact la pinul T0.Se ia în considerare frontul crescător;
Pentru a se putea genera o cerere de întrerupere a timer-ului 0 trebuie ca cel mai semnificativ bit al registrului SREG(bitul I) să fie 1 şi cel mai nesemnificativ bit al registrului TIMSK, bitul TOIE0 să fie tot 1.
Cererea de întrerupere este semnalizată în registrul TIFR în cel mai nesemnificativ bit,TOV0.Dacă registrul TCNT0 a fost umplut,TOV0 devine 0 şi atunci sistemul va genera o întrerupere executându-se codul de la adresa 0x009.
În majoritatea aplicaţiilor cu timere se foloseşte prescalarea sursei de tact.Calcului prescalării se face în felul următor:
Mai întâi calculăm frecvenţa la care dorim să se genereze o întrerupere.Frecvenţa va fi raportul dintre o secundă şi intervalul la care dorim să primim semnalul de la timer.
În funcţie de această frecvenţă vom alege frecvenţa externă sau vom prescala ceasul intern.Prescalarea ceasului intern se face în aşa fel încât frecvenţa rezultantă să fie egală sau mai mică cu frecvenţa dorită.
Dacă prescalând timerul nu obţinem o frecvenţă egală cu cea dorită şi obţinem o frecvenţă mai mică, atunci se calculează valoarea de start a NLC-ului.Această valoare va fi raportul dintre frecvenţa internă şi prescalarea aleasă la pasul anterior înmulţită cu frecvenţa dorită:
Pentru a înţelege mai bine cum se calculează frecvenţa vom calcula prescalarea şi n-ul pentru timpul de 0,2 secunde.Ceasul folosit va fi cel intern.Datele de pornire sunt: tdorit = 0.2s,fint =1MHz.

Observăm ca această frecvenţă este mai mică decât frecvenţa pe care dorim să o scoată timerul(5Hz), în consecinţă vom calcula valoarea de pormire a lui TCNT0.
Din păcate în numărător nu se pot reţine date în virgulă mobilă aşa că lui TCNT0 i se va atribui valoarea 195.Acest lucru va duce însă la o mică eroare de măsurare a timpului care totuşi este insesizabilă la o funcţionare pe termen scurt.
Pentru acest exempu configurarea regiştrilor va fi următoarea:

TCNT0=195;
TCCR0=0x05;
TIMSK=0x01;

Vom considera că la generarea unei întreruperi se va schimba starea unui pin la care avem legat un LED.Pinul de care vom lega LED-ul este PB0.
Programul îl puteţi downloada de la secţiunea Download-Timer0-Aplicaţie 1.

Schema electrică este una simplistă:
Când creaţi proiectul în CodeVision AVR,la secţiunea de setare a caracteristicilor, veţi seta pinul PB0 ca pin de ieşire iar pentru setarea parametrilor timer-ului veţi merge la Timers-Timer 0 şi veţi alege la Clock Source: System Clock, la Clock Value:0.977Hz,selectaţi Owerflow Interrupt şi la Time value treceţi C3h(195 în decimal).Observăm că frecvenţa aleasă nu este cea calculată de noi însă aceată alegere va seta TCCR0=0x05, adică prescalarea cu 1024.
Observăm că la generare avem următoarele setări:

TCCR0=0x05;
TCNT0=0xC3;
TIMSK=0x01;


În concsecinţă setările sunt bine făcute.Ce a mai apărut nou în program este funcţia de tratarea a întreruperilor generate de timer,funcţie în care vom iniţializa de fiecare dată TCNT0 şi în care vom schimba valoarea PORTB-ului:

interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
// Reinitializam valoarea timerului
TCNT0=0xC3;
// Schimbam starea PORTB-ului
PORTB =~PORTB;
}

Bun, probabil aţi observat că acest program se putea face şi fără timere de aceea următorul exemplu va fi unul mai complex şi anume un ceas digital reglabil.Aplicaţia va avea un LCD pe care vom putea citi ceasul şi 2 butoane prin care se va regla minutul şi ora,butoane care vor fi legate la pinii INT0 şi INT1.Aplicaţia o puteţi downloada de la secţiunea Download- Timer 0- Aplicaţie 2.
Schema electrică este următoarea:
Următorul lucru pe care trebuie să îl facem este să calculăm frecvenţa timerului astfel încât să avem o întrerupre la o secundă.Pentru aceasta frecvenţa dorită este 1 MHz.Dacă folosim ceasul intern şi prescalăm cu maximul adică cu 1024 observăm că noua frecvenţă obţinută este de 3.81Hz, frecvenţă care este mai mare decât frecvenţa pe care dorim să o folosim.Pentru a elimina acest neajuns vom folosi o variabilă suplimentară în program care se incrementează la fiecare 0,1 secunde,adică la 10Hz.Când se ajunge la valoarea 10, variabila care reţine secundele se incrementează iar valoarea variabilei suplimentare va deveni 0.Momentan vom calcula valorile regiştrilor pentru frecvenţa dorită de 10Hz.În consecinţă vom folosi iar prescalarea cu 1024 însă vom calcula n-ul pentru 10Hz:
Pentru a mai diminua din erori vom rotunji n-ul la 98 şi nu 97.Configurarea pentru generarea programului în CodeVision AVR se face la fel ca mai înainte însă la Timer Value treceţi 62(98 în decimal).De asemenea nu uitaţi să configuraţi LCD-ul pe portul B şi să activaţi întreruperile externe.

Programul va avea 3 funcţi de tratare a cererilor de întrerupere,două pentru tratarea butoanelor care modifică ora şi minutul şi una pentru tratarea întreruperii generate de timerul 0.Funcţia care tratează întreruperea externă INT0 are rolul de a incrementa minutul iar funcţia care tratează întreruperea externă INT1 are rolul de a incrementa ora.Dacă minutul a ajuns la valoarea 60 sau ora la valoarea 24 , ele trebuiesc resetate.Funcţia care tratează timerul 0 are rolul de a incrementa o variabilă suplimentară până la valoarea 10 , adică echivalentul unei secunde,la această valoare ea resetându-se şi incrementând variabila secundă(sec) cu o unitate.În aceste funcţii sunt verificate variabilele de ceas dacă au ajuns la valoarea maximă şi dacă da ele sunt resetate şi totodată sunt incrementate variabilele care le urmează.

În cele trei funcţii se are grijă ca după fiecare modificare a variabilelor să se scrie noua stare a ceasului pe LCD.Acest lucru se face prin modificarea sirului de caractere linie1.
Din păcate ceasul nostru nu este unul exact, existând erori de măsurare a timpului, erori care pot fi înlăturate folosind un oscilator extern special pentru ceas.
Aplicaţia realizată fizic o puteţi vedea aici:

sâmbătă, 27 august 2011

Afişajul LCD

Până acum ieşirile microcontrolerului reprezentau nişte LED-uri care puteau lua două valori, 1 sau 0.Acest mod de afişare a informaţiilor de ieşire ale unui microcontroler nu este întotdeauna mulţumitor deoarece există cazuri în care dorim să afişăm un număr sau un text.Acest lucru se poate realiza cu ajutorul unui afişaj LCD.Dimensiunea LCD-ului pe care îl vom folosi în acest tutorial este de 2 linii şi 16 coloane şi se numeşte LM016L.Acesta se alimentează cu 5 volţi şi permite scrierea caracterelor alfanumerice principale.

Transferul de date între microcontroler şi LCD se poate face pe 4 sau 8 biţi printr-un bus de date.Pe lângă linile de date vom avea nevoie şi de 3 linii de control:
-E(Enable) care permite sau nu transmiterea de date şi comenzi.Setând acestă linie 1 poate începe schimbul de date şi comenzi între LCD şi microcontroler.
-R/W (Read/Write) are rolul de a stabili direcţia datetelor,0 fiind pentru scrierea datelor iar 1 fiind pentru citirea datelor din LCD.
-RS(Register Selec) foloseşte la selectarea regiştrilor interni ai LCD-ului.Dacă ia valoarea 0 înseamnă că trimitem LCD-ului o instrucţiune iar dacă scriem valoarea 1 înseamă că trimitem date.
De exemplu pentru scrierea unor date în LCD trebuie ca: E=1,R/W=0,RS=1.
Toate aceste lucruri sunt mascate în CodeVision AVR singurul lucru pe care trebuie să îi facem este să setăm la începutul proiectului portul prin care realizăm conexiunea LCD-ului cu microcontrolerul şi să includem biblioteca lcd.h.Se foloseşte trasferul de date pe 4 biţi deoarece această metodă salvează 4 pini ai microcontrolerului.Legarea pinilor unui port cu pinii LCD-ului se face în felul următor:

RS (pin4)--------bit 0
RD (pin 5)--------bit 1
EN (pin 6)--------bit 2
DB4 (pin 11)-----bit 4
DB5 (pin 12)-----bit 5
DB6 (pin 13)-----bit 6
DB7 (pin 14)-----bit 7

Funcţiile cele mai utilizate pentru controlul şi scrierea LCD-ului sunt următoarele:

unsigned char lcd_init(unsigned char lcd_columns)– realizează iniţializarea LCD-ului, lcd_columns reprezentând numărul de coloane ale LCD-ului, în cazul nostru 16;

void _lcd_ready(void) – aşteaptă până când lcd-ul este gata să primească date.Avem nevoie de această funcţie deoarece LCD-ului îi trebuie un timp de iniţializare după ce a fost pus în funcţiune;

void lcd_clear(void) – şterge tot ce este scris pe LCD şi duce cursorul la linia şi coloana 0;

void lcd_gotoxy(unsigned char x, unsigned char y) – setează cursorul la poziţia x,y.Aţienie, x reprezintă coloana iar y reprezintă linia;

void lcd_putchar(char c) – afişează un caracter la poziţia x,y curentă.Dacă avem mai multe comenzi de acest gen nu însemnă că va scrie caracterul unul peste altul şi va scrie pe coloana sau linia următoare.

void lcd_puts(char *str) - afişează un şir de caractere începând de la poziţia x,y curentă;

Pentru a vă face o idee cam cum se conectează şi scrie pe LCD vom crea un exemplu simplu în care vom avea microcontrolerul ATMega8 şi un LCD LM016.Codul şi schema aplicaţiei o puteţi downloada de la secţiunea Download-LCD-Aplicaţie 1.Schema electrică este următoarea:
În cazul de faţă folosim portul D pentru transmisia de date şi comenzi.La crearea proiectului în CodeVision AVR ,la partea de setare din wizard trebuie să mergem la panoul LCD , să alegem portul D şi să selectăm numărul de coloane al LCD-ului precum în figura de mai jos:
În program nu vom face altceva decâ să afişăm nişte caractere înainte de intrarea în bucla infinită while:

lcd_init(16); //initializam LCD-il
_lcd_ready(); //asteptam ca lcd-ul sa poata primi date
lcd_gotoxy(1,4); //megem la coloana a 2-a pozitia 5
lcd_puts(mesaj1); //afisam primul mesaj
delay_ms(2000); //asteptam 2 secunde
lcd_clear(); //stergem caracterele de pe lcd
lcd_puts(mesaj2); //afisam mesajul 2 pe linia si coloana 1
delay_ms(1000); //asteptam o secunda
lcd_clear(); //stergem caracterele de pe lcd
lcd_puts(mesaj3); //afisam mesajul 3
lcd_putchar('x'); //afisam caracterul x
lcd_putchar('y'); //afisam caracterul y
lcd_putchar(80); //afisam caracterul cu codul 80(P)

Puteţi observa că pentru afişarea unor şiruri de caractere am folosit o variabilă de şir, mesaj, deoarece compilatorul nu ne lasă să scriem direct în funcţie sirul.Declararea şirurilor de caractere se poate face în program ,la începutul funcţiei main sau în exterior ca variabile globale.În programul nostru avem:

unsigned char* mesaj1 = "Test LCD";
unsigned char* mesaj2 = "LCD curatat";
unsigned char* mesaj3 = "Afisarea a 3 caractere:";

Funcţionarea fizică a aplicaţiei o puteţi vedea aici:

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:

Structura unui program scris pentru un microcontroler

Structura unui program scris pentru un microcontroler este puţin diferită de structura programelor scrise pentru un calculator de uz general.Primele linii dintr-un program vor reprezenta bibliotecile pe care le utilizăm în cadrul aplicaţiei.Următoarea secţiune va fi reprezentată de declararea variabilelor globale şi de declararea/definirea funcţiilor program.Apoi urmează funcţia main, funcţia principală din program, cea care este prima executată la rularea programului.În această funcţie mai întâi se declară variabilele locale, dacă este nevoie ,apoi se fac setările diferitelor funcţii ale microcontrolerului.În ultima parte a funcţiei main se va crea o buclă infinită lucru care în mod normal nu ar fi dorit în programele scrise pentru calculatoarele personale.În această buclă are loc întreaga parte de prelucrare a datelor, restul fiind partea de setare.Atenţie mare, funcţiile microcontrolerului nu însemnă acelaş lucru cu funcţiile programului.De exempu pentru chipul ATMega8 programul ar trebui să urmeze modelul:

//partea de includere a bibliotecilor utilizate

#include ‹mega8.h›
//declararea/definirea functiilor si variabilelor globale
void main(void)
{
//declarea variabilelor locale
//realizarea setarilor microcotrolerului prin registrii de setare
while(1)
{
//partea de prelucrare a datelor
}
}

Când microcontrolerul este pornit mai întâi se va realiza setările funcţiilor chip-ului prin regiştrii de setare apoi el va cicla codul din bucla while până când apare un eveniment neaşteptat cum ar fi oprirea sursei de alimentare sau apariţia unei întreruperi.
Avatajul folosirii wizardului din CodeVision AVR este că el generează cod pentru structura de mai sus ,setările micorcontrolerului putând fi făcute vizual.De asemenea wizardul oferă şi explicaţii referitoare la setările pe care le-a realizat.

Încărcarea programului în microcontroler

Copierea programului în memoria flash a microcontrolerului se face cu ajutorul programului PonyProg , program pe care puteţi să îl descărcaţi de la secţiunea Download.Înainte de a deschide programul şi de a alimenta placa se vor face conexiunile între pinii microcontrolerului şi pinii programatorului după schema următoare:
Pinii microcontrolerului la care va trebui să legaţi pinii programatorului îi veţi putea găsi în schema de mai jos:
După cum vedem pinul PC6 trebuie legat la RESET,PB5 la SCK,PB4 la MISO,PB3 la MOSI,+5V la tensiunea de alimentare iar GND la masă.

După ce aţi făcut toate conexiunile urmează să conectăm placa la portul serial.Acest lucru se face printr-un cablu de legătură serial.Portul COM1 îl găsiţi în spatele calculatorului el arătând cam aşa:
Acum când toate conexiunile sunt făcute puteţi alimenta placa şi porni programul PonyProg.
După ce aţi deschis programul va trebui să îl configuraţi pentru a putea face legătura serială cu placa.Pentru configurare megeţi în meniu la Setup>Interface Setup.Aici selectaţi modul Serial şi COM1(sau COM2 , depinde pe care doriţi să îl folosiţi).
Acum că setările sunt făcute urmează să copiem programul nostru in memoria microcontrolerului.Mai întâi va trebui să încărcăm codul în PonyProg apăsând File>Open Program Flash File selectând extensia *.hex şi aleagând fişierul din directorul Exe corespunzător.Aici am folosit numele directorului Exe deoarece am presupus că programul a fost compilat cu Code Vision AVR , el generând codul într-un astfel de director.
Următorul pas este selectarea chip-ului pe care vom încărca programul.Această setare se face din bara plasată sub meniu.
În prima casetă selectaţi AVR micro iar în a doua Atmega8.Înainte de încărcare mergeţi în meniu la Command > Erase pentru a şterge toate datele din memoria microcontrolerului.
Operaţia de încărcare propriuzisă pe chip se face tot din meiniu prin alegerea Command >Write All.Dacă totul a decurs cum trebuie veţi primi un mesaj cum că totul este ok.

Realizarea fizică a aplicaţiei

Pentru simularea fizică a aplicaţiilor puteţi alege două căi, una uşoară şi mai scumpă şi una grea şi puţin mai ieftină.Prima ar fi să achiziţionaţi de la o firmă de componente electronice o placă de dezvoltare gata făcută pe care să puteţi monta un microcontroler ATMega8.Totuşi unele diferenţe vor exista între posibilităţile pe care le oferă placa pe care sunt simulate aplicaţiile în acest tutorial şi plăcile achiziţionate din magazin, însă nu foarte mari, fiecare placă putând fi adaptată pentru diferite sarcini.A doua posibilitate ar fi să vă creaţi propria placă de dezvoltare asemănătoare cu placa pe care se testează aplicaţiile din acest tutorial.Dacă doriţi să creaţi o placă identică cu placa mea puteţi încerca să o creaţi după detalile pe care vi le voi prezenta mai jos.

Prima dată aveţi nevoie de schema de imprimare şi o placă de plastic care are una sau două pelicule( faţă verso sau doar faţă) de cupru.Mai aveţi nevoie şi de o bucată de smirghel fin cu care să smirgheluiţi placa foarte bine.După această operaţie ea trebuie curăţată cu spirt industrial.Toate aceste operaţii sunt necesare deoarece pe placă vom imprima un circuit.La final placa ar trebui să arate cam aşa:
Schema pe care o veţi imprima o puteţi descărca de la sectiunea Download -Tutoriale AVR -Schemă Placă.
Trebuie să precizez că această schemă NU trebuie imprimată în oglidă,ea fiind plasată direct aşa cum e pe placă, fiind deja în oglindă.Acest lucru este important să îl spuneţi dacă mergeţi la o firmă de imprimeuri.
Imprimarea este o operaţie dificilă dacă doriţi să o faceţi acasă.Se poate face cu o imprimantă, o folie specială care va fi plasată pe placă si un fier de călcat care vă ajută la trecerea imprimeului după folie pe pelicula de curpru.Totuşi această operaţiune este destul de delicată, în consecinţă v-aş recomanda să mergeţi la o firmă care realizează imprimeuri.
După ce aţi realizat imprimarea schemei pe placă va trebui să creăm circuitul fizic prin corodare cuprului nefolositor.Aveţi nevoie de Clorură Ferică, soluţie pe care o puteţi găsi tot într-un magazin de componente electronice, şi de un recipient în care să turnaţi o parte din soluţie amestecată cu apă caldă.Puteţi să puneţi şi apă rece însă temperatura apei va spori procesul de corodare.Recipientul pe care îl veţi folosi ar fi bine să nu fie din metal pentru a se evita distrugerea lui.
Ţineţi placa în această soluţie 10-20 de minute până când se îndepărtează întreaga peliculă de cupru nefolositoare rămânând astfel doar circuitul.După ce terminaţi operaţia v-aş sfătui să nu aruncaţi soluţia în sistemul de conducte al băii deoarece ea este extrem de corozivă şi vă poate ataca ţevile.Cel mai bine ar fi sa o puneţi într-o sticlă şi să o aruncaţi la un coş de gunoi din exterior.Dacă până aici toate sunt bune şi frumoase urmează să daţi găuri plăcii.Găurile se pot da cu o bormaşină mică dar înainte să le daţi ar fi bine să ştanţaţi locurile în care veţi plasa burghiul pentru o mai mare precizie în momentul când găuriţi placa.
Dacă circuitul imprimat este mai mic decât placa vă recomand să decupaţi părţile nefolositoare cu un bomfaier sau un flex.
Din păcate nu dispun de schema electrică într-un program CAD, însă vă voi pune la dispoziţie schema electrică de imprimare cu componentele electronice pe ea .Pentru a mări poza daţi click pe ea:
Componentele de care veţi avea nevoie pentru montaj sunt următoarele: un microcontroler ATMega8+slot,un integrat MAX232 pentru conexiunea serială +slot,9 LED-uri(20mA),un L7805 – stabilizator de tensiune de 5 volţi,4 potenţiometre de 10K, 4 butoan fără reţinere şi 4 cu reţinere,8 rezistenţe de 10 ohmi,13 rezistenţe de 1K,8 rezistenţe de 470 ohmi,2 rezistenţe de 10K,2 rezistenţe de 4,7K, o rezistenţă de 15K,o diodă 1N4148, 2 diode zener de 5V, un tranzistor BC549, 2 condensatori electrolitici de 1 microfarad şi unul de 0.1 microfarazi, 2 conectori pentru portul serial cu pinii în jos, un conector de alimentare cu 2 intrări şi mai multe şiruri de pini (aprox. 120 de pini) pe care le veţi tăia în funcţie de numărul de găuri de la ieşirea integratelor.
Sfatul meu ar fi să daţi în linie dreapta găurile unde vor fi montate şirurule de pini, deoarece vă va fi mai uşor să montaţi pinii.V-aş mai sfătui să aveţi mare grijă la montarea elementelor cu polaritate astfel plusul să fie la plus şi minusul la minus,aici mă refer la LED-uri şi la condensatori.

Pentru lipirea pieselor pe circuit aveţi nevoie de un pistol de lipit,nişte fludor şi nişte sacâz.Când faceţi lipiturile trebuie să aveţi grijă să nu lipiţi două componente de circuit care nu au legatură pe schemă, altfel puteţi să legaţi plusul de minus şi circuitul să se închidă fără ca el să aibă consumator, în felul acesta riscând să ardeţi stabilizatorul de tensiune.
Pentru a vă face idee cum trebuie să arate piesele montate pe placă aveţi aici două fotografi cu ambele părţi ale plăcii,partea de lipituri şi partea de componente:

Dacă aţi terminat de făcut toate lipiturile ar fi bine să verificaţi circuitul ca nu cumva să aveţi lipituri incorecte.Înainte să puneţi circuitul sub tensiune se vetifică mai întâi la bornele stabilizatorului dacă rezistenţa este diferită de 0 apoi se verifică din punct în punct între elemente dacă au sau nu rezistenţa 0.Dacă rezistenţa este 0 înseamnă că avem o lipitura incorectă şi ea trebuie înlăturată.După ce toate conexiunile greşite au fost înlăturare puteţi alimenta placa.Sursa de tensiune poate fi o sursă de calculator.Mufa principală de alimentare a unei surse model ATX arată cam aşa:
Pentru a porni sursa trebuie să legaţi pinul PS_ON# la COM(masă).Pentru a porni placa trebuie să legaţi la plusul stabilizatorului de teinsiune de pe placa creată anterior ieşirea sursei 12VDC(firul galben) iar minusul la ieşirea COM (firul negru).Dacă toate sunt în regulă ar trebui să se aprindă LED-ul de lângă stabilizatorul de 5V.Ar fi bine să urmăriţi stabilizatorul să vedeţi dacă se încălzeşte iar dacă da deconectaţi repede circuitul de la alimentare deoarece aveţi o problemă pe care nu aţi rezolvat-o.

Conexiunile între pini se pot face cu fire subţiri.La capetele acestor fire vor fi legaţi cu fludor nişte papuci de conexiune.Pentru protecţie ,aceste legături între papuci şi fir vor trebui izolate cu tub termocontractant sau bandă izolir.Firele le puteţi face rost cumpărând un metru de cablu de alarmă pe care îl veţi desface.Papucii îi puteţi găsi tot în magazinele de componente electronice însă când îi cumpăraţi trebuie să aveţi grijă să se potrivească cu pinii şirurilor de pini.
Prezentarea plăcii o puteţi urmări aici:

Cam atâtea ar fi despre placa de dezvoltare.O soluţie pe care am uitat să o precizez ar fi folosirea unui breadboard pe care să montaţi circuitul în funcţie de aplicaţie. Breadboard arată cam aşa:

Linile din mijloc şi coloanele + şi – sunt legate în serie.În felul acesta puteţi crea un circuit destul de simplu având la dispoziţie componentele electronice şi nişte fire cu care să le concetaţi.

Unelte Software

Uneltele software pe care le vom folosi în dezvoltarea aplicaţiilor pot fi download-ate de la secţiunea Download-Software.În continuare ele vor fi prezentate pe rând:

CodeVision AVR

CodeVision AVR este IDE-ul cu care vom scrie codul sursă al programelor care vor rula pe microcontrolerul ATMega8.Modul de lucru este prezentat mai jos:

După ce porniţi programul CodeVision AVR ar trebui să aveţi următoarea fereastră:

Bun, dacă arată ca aici înseamnă că totul este în regulă.În continuare vom vedea cum se crează un proiect si cum se generează automat codul.

Pentru crearea unui nou proiect megeţi la File-New Project, alegeţi Project şi apăsaţi OK.

După ce apăsaţi OK vă va întreba dacă doriţi să folosiţi CodeWizardAVR, apăsaţi Yes.Următoarea etapă va fi de setare a funcţiilor microcontrolerului:

Alegeţi la Chip ATmega8 şi setaţi frecvenţa de 1MHz.După aceea mergeţi în meniu la File şi apăsaţi Generate,Save and Exit, apoi veţi alege locaţia şi veţi da nume fişierelor proiectului.Dacă până aici totul este bine ar trebui să aveţi un cod asemănător:
Pentru compilare va trebui să mergeţi în meniu şi să setaţi Project> Build All.Ca rezultat al compilării vom găsi în directorul în care aţi salvat proiectul un director care se numeşte Exe.În director veţi găsi un fişier cu extensia *.hex.Acest fişier reprezintă codul care va fi încărcat în microcontroler.
Bun, dacă aţi făcut toate acestea înseamnă că aţi realizat primul dumneavoastră proiect în CodeVision AVR.

ISIS Proteus
Pentru a simula orce aplicaţie din acest tutorial deschideţi ISIS Proteus.La început s-ar putea să vă întrebe dacă doriţi să încărcaţi un exemplu, în acest caz alegeţi nu.Obserăvm că în dreapta avem planşa de lucru,în stânga o listă de unelte iar sus meniul:
Pentru a exemplifica modul de funcţionare al programului voi crea o schemă simplă şi anume un led care va fi aprins prin apăsarea unui buton.Pentru acest proiect avem nevoie de un buton ,de un led, de o sursă de tensiune şi de o rezistenţă pentru a limita curentul prin circuit.Mai întâi vom aduce aceste piese din librărie în partea stângă, în lista DEVICES.Pentru a aduce elementele în listă megeţi în meniu la Library şi selectaţi Pick Device/Symbol sau apăsaţi butonul P de lângă DEVICES.Va apărea o fereastră în care va trebui să selectaţi componentele.Mergeţi în stânga sus la câmpul Keywords şi scrieţi button.Ca rezultat vom avea 2 dispozitive ca în figura de mai jos:
Daţi dubluclick pe BUTTON pentru a fi adăugat în lista din dreapta de dispozitive.
Procedaţi asemănător şi pentru alegerea rezistorului şi a LED-ului.Pentru rezistor căutaţi la Keywords cuvântul resistor iar pentru LED căutaţi LED-BIBY.După ce aţi ales componentele închideţi fereastra pentru că urmează să alegem sursa de tensiune.Pentru acest lucru mergeţi în stânga şi selectaţi butonul Generator Mode.
Din lista de generatoare selectaţi DC adică sursa de tensiune continuă,apoi plasaţi această sursă în plaşa de lucru.Totuşi pentru circuitul nostru avem nevoie şi de conexiunea la masă(GROUND).Aceasta o puteţi obţine tot din stânga de la butonul Terminal Mode.
Selectaţi ground şi plasaţi-l în fereastra de lucru.Până acum avem sursa de tensiune continuă şi masa.
Tensiune de lucru a microcontrolerului ATMega 8 este de 5 volţi, deci pentru uşurinţă vom seta şi tensiunea sursei pentru aplicaţia curentă tot 5 volţi,urmând ca la majoritatea aplicaţiilor să avem la bornele de alimentare tot această tensiune.Pentru setare se va da dublu click pe sursă şi se va seta 5 la caseta Voltage.
Bun, circuitul nostru mai are nevoie de LED şi rezistenţa de limitare a curentului în circuit.În lipsa rezistenţei curentul ar creşte şi ar distruge sursa chiar dacă simularea funcţionează şi fără ea.Valoarea rezistenţei va fi 1K, astfel vom avea un curent de 5 miliamperi.
Pentru plasarea rezistenţei şi a LED-ului vom alege din dreapta butonul Component Mode:

Vom plasa butonul,rezitenţa şi LED-ul între sursă şi masă.Componentele se vot roti prin click dreapta-Rotate iar legăturile între elemente se fac prin ducerea creionului în dreptul elementului şi trasarea liniei până la elementul următor.Setarea rezistenţei se face prin apăsarea dublului click pe ea şi înscrierea valorii dorite în câmpul Resistence.Schema finală ar trebui să arate cam aşa :
Totuşi dacă doriţi o intensitate mai mare a LED-ului puteţi scădea valoarea rezistenţei însă acest lucru va duce la un consum mai ridicat.
Pentru a simula schema creată apăsaţi butonul Play din stânga paginii jos.
Dacă totul este în regulă veţi putea vedea led-ul aprins la apăsarea butoului:
Cam acestea sunt bazele mediului Proteus, asemănător putând crea simulări pentru fiecare aplicaţie pe care o vom dezvolta pe parcursul tutorialului.

Twitter Delicious Facebook Digg Stumbleupon Favorites More