Documente Academic
Documente Profesional
Documente Cultură
Cuprins
Partea 1 - Hello world!..................................................................................................................3 Introducere....................................................................................................................................3 De ce ai nevoie?...........................................................................................................................4 Programarea uC-ului.....................................................................................................................5 Cum scriu cod pentru uC?............................................................................................................8 Cum transfer programul n uC?..................................................................................................10 Leduri clipitoare......................................................................................................................11 Tema 1........................................................................................................................................12 Partea 2 Push the button..............................................................................................................12 De ce ai nevoie?..........................................................................................................................13 Cum folosesc butoanele n cod?.................................................................................................13 Exemple......................................................................................................................................14 Partea 3 The clock is ticking........................................................................................................16 Exemple .....................................................................................................................................17 Partea 4 Fade to black..................................................................................................................19 Cum se folosete?.......................................................................................................................19 Exemple......................................................................................................................................19
La acest microcontroller vei conecta cteva leduri cu care ne vom juca mai trziu. n cazul n care ai uitat cum arata un led i cum se conecteaz arunca o privire pe imaginea de mai jos:
De ce ai nevoie?
Ca s te poi apuca de programarea propriu-zis ai nevoie nti de un circuit care s poat ndeplini funciile implementate n program (program la care m voi referi n continuare ca soft sau firmware - FW). Pentru realizarea circuitului ai nevoie de urmtoarele: Letcon, fludor, sacz (colofoniu) pentru lipirea componentelor (dac foloseti breadboard nu sunt necesare). n cazul n care nu ai mai lipit pn acum componente uit-te la filmuleul din link-ul urmator: http://www.youtube.com/watch?v=AOdnGUMi7lQ Cablaj de test sau breadboard 8 leduri 8 rezistene (100ohm sunt ok) 7805 regulator de tensiune pentru a putea alimenta circuitul de la cam orice alimentator gsit prin cas cu tensiune DC mai mare de 7V. ATMega8 microcontrollerul folosit n acest tutorial Fire de legatur USBasp programatorul folosit n acest tutorial. Poi folosi orice programator cu programele adecvate. Pe lng resursele hardware mai ai nevoie i de nite programe cu care s scrii / compilezi codul i cu care s transferi softul rezultat n microcontroller (cuvntul e destul de lung aa c n continuare voi folosi notaia uC). Programele necesare sunt urmatoarele: AVR Studio 4.18 mediul de dezvoltare a codului. Conine i un simulator foarte util. (http://en.stkshop.com/download--download_id-65.html) AVR Studio SP3 se instaleaz mpreun cu AVR Studio 4.18. l gseti aici: http://www.atmel.com/dyn/resources/prod_documents/AVRStudio4.18 SP3.exe WinAVR compilatorul de C care se folosete mpreun cu AVR Studio 4 (http://sourceforge.net/projects/winavr/files/WinAVR/20100110/WinA VR-20100110-install.exe/download) Khazama Programmer programul cu care se transfer softul n uC (http://khazama.com/project/programmer/)
Tutorial Introducere n programarea i utilizarea microcontrollerelor Atmel AVR Circuitul pe care l vei folosi n aceast prim parte a tutorialului este cel din imaginea de mai jos. Va trebui ca folosind uneltele descrise mai sus s conectezi componentele ntre ele ca n schema. Recomandat este ca toate ledurile sa fie montate ntr-un singur rnd pentru a nelege mai bine exemplele de cod prezentate. Lng leduri se vor monta (vertical - pentru a face economie de spaiu pe plcu; orizontal n cazul n care spaiul nu e o problem) rezistenele. Conexiunile pn la uC se vor face folosind fire de legtur. Poziia conectorului pentru programare nu este critic dar ncearc s aranjezi componentele n aa fel ncat s ocupi ct mai puin spaiu. Pe msura ce vei parcurge tutorialul plcua se va umple cu componente!
Programarea uC-ului
Pentru a nelege ceea ce urmeaz este necesar s citeti din datasheet-ul uC-ului (http://www.atmel.com/dyn/resources/prod_documents/doc2486.pdf) urmtoarele: Pag. 2 Pin configurations 5
Tutorial Introducere n programarea i utilizarea microcontrollerelor Atmel AVR Pag. 5 Port B Pag. 51 I/O Ports pn la Table 20 (Pag. 53) Pag. 55 pn la Digital Input Enable and Sleep Modes
AVR Studio 4 Dupa ce ai citit ce este indicat mai sus te po i apuca de programarea propriu-zis. AVR Studio 4 este programul n care vei dezvolta, compila i simula codul. Pentru crearea unui proiect nou deschide AVR Studio 4. n fereastra care i apare selecteaz New Project apoi AVR GCC.
D un nume proiectului i selecteaz unde vrei sa fie salvat apoi apas Next.
Tutorial Introducere n programarea i utilizarea microcontrollerelor Atmel AVR Ca i n liceu codul ncepe cu headerele necesare. Acum vei folosi doar #include <avr/io.h> pentru accesarea pinilor. Urmeaz venicul void main() n care apare codul propriuzis. Pn s ajungi s scrii cod trebuie s tii cteva noiuni mai puin folosite n programarea PC-ului: Familia de uC AVR lucreaza pe 8bii. Asta nseamn ca toi registri au lungime de 8 biti putnd stoca o valoare ntre 0 255 0 x00 0 xFF 0b00000000 0b11111111 . 1 logic = VCC (n cazul de fa 5V); 0 logic = GND (0V) (1<<X) nseamn c reprezentarea lui 1 n baza doi (0b00000001) o deplasez n stnga cu X poziii ( 1 X 7 ). Pentru X=2 rezultatul este 0b00000100. Toat operaia are ca rezultat setarea bitului X ca 1. ~(1<<X) nseamn c la toat operaia descris cu un pas mai sus se aplic complementul lui 1. Altfel spus: ce este 1 devine 0 si ce e 0 devine 1. Exemplu: ~(1<<3)=~(0b00001000)=0b1111011. Toat operaia are ca efect setarea bitului X ca 0 iar a celorlali ca 1. A|=B; - nseamn A=A|B, adic A ia valoarea rezultat din aplicarea operatiei logice SAU ntre A i B. La fel e pentru A&=B; nainte de a ncepe s scrii codul trebuie s te asiguri c proiectul are setrile corecte. Apas butonul pentru a deschide fereastra de configurare. Pentru tutorialul acesta AVR Studio este configurat ca n imaginea de mai jos:
Acum poi ncepe s scrii primul tu cod pentru uC. Exemplul urmator demonstreaz cum poi aprinde dou din cele opt leduri conectate pe PORTB, respectiv ledul 0 i 7. Poi alege orice led i oricte leduri.
#include <avr/io.h> //header necesar pt a putea accesa pinii uC-ului
Deschide programul Khazama Programmer i selecteaz Load FLASH File (marcat cu rou).
n fereastra care i apare mergi la locaia unde ai salvat proiectul, folderul default. Acolo gseti fiierul .hex rezultat n urma compilrii codului. Selecteaz fiierul, apoi Open. Asigur-te c programatorul e conectat att la calculator ct i la montaj iar montajul este alimentat. Selecteaz Command ->Read Chip Signature. Dac rezultatul este 0x1E9307 poi trece la programarea propriu-zis a uC-ului apasnd butonul Write FLASH to Chip marcat cu albastru n imaginea de mai sus. Presupunnd c scrierea s-a fcut cu success acum ar trebui ca cele dou leduri despre care am vorbit mai sus s fie aprinse.
10
Leduri clipitoare
Hai acum s ncercm s facem ledurile s clipeasc. Deoarece uC-ul funcionez la frecven foarte mare (1MHz n cazul celui folosit n acest tutorial) i execut o instruciune/ciclu ledurile i vor schimba starea mult prea repede ca ochiul uman s sesizeze ceva. Avem nevoie de o modalitate de a mri timpul ct ledul se afl ntr-o stare. Pentru asta avem la dispozitie funciile _delay_us(double __us) (ntrzie execuia urmatoarei intruciuni cu numrul cerut de microsecunde) i _delay_ms(double __ms) (ntrzie execuia urmtoarei instruciuni cu un anumit numr de milisecunde) incluznd headerul util/delay.h. Noi ne vom folosi de funcia _delay_ms() pentru a obine ntrzieri vizibile iar instruciunile necesare vor fi plasate n bucla infinit while(1) codul urmnd a fi executat repetitiv att timp ct montajul este alimentat.
#include <avr/io.h> #include <util/delay.h> void main() { DDRB|=(1<<DDB0)|(1<<DDB7); while(1) {PORTB|=(1<<PB0); _delay_ms(500); PORTB&=~(1<<PB0); PORTB|=(1<<PB7); _delay_ms(500); PORTB&=~(1<<PB7); } } //header necesar pt a putea accesa pinii uC-ului //header necesar pentru delay //seteaz pinul 0 i 7 ca ieire //aprind ledul 0 //atept 500ms //sting ledul 0 //aprind ledul 7 //atept 500ms //sting ledul 7
O modalitate de a scrie codul mai elegant ar fi sa definim operaiile cu biii din PORTB i delay-ul cu cte un nume. Exemplu:
#include <avr/io.h> #include <util/delay.h> //header necesar pt a putea accesa pinii uC-ului //header necesar pentru delay
#define LED0_ON() PORTB|=(1<<PB0) #define LED0_OFF() PORTB&=~(1<<PB0) #define LED7_ON() PORTB|=(1<<PB7) #define LED7_OFF() PORTB&=~(1<<PB7) #define DELAY() _delay_ms(500) void main() { DDRB|=(1<<DDB0)|(1<<DDB7); while(1) {LED0_ON(); //seteaz pinul 0 i 7 ca ieire //aprind ledul 0
11
Cele dou coduri sunt echivalente. Diferena este doar de estetic. Poi testa codul compilndu-l i apoi scriindu-l n uC.
Tema 1
1. Folosind circuitul construit, implementeaz un numarator binar pe 8 bii. 2. Folosind circuitul construit, implementeaz un program care s deplaseze un led aprins la stnga i la dreapta alternativ, lungimea deplasrii fiind de 7 bii. 3. Implementeaz un program care s deplaseze ledul stins la stnga i la dreapta alternativ, lungimea deplasarii fiind de 7 bii. 4. Combin programele create anterior (2 i 3) astfel nct pornind cu deplasarea ledului aprins, dup 3 deplasri complete se va trece la deplasarea ledului stins. Dup 3 astfel de deplasri programul trece din nou la deplasarea ledului aprins, ciclul repetndu-se la nesfarit. 5. Scrie un program care s conin cel puin 3 animaii diferite i care se vor schimba dupa un numr ales de cicluri. 6. Folosind 3 leduri consecutive pentru reprezentarea a 3 variabile binare a,b,c i unul pentru f, implementeaz funcia f = ab c +a b +c .
12
Tutorial Introducere n programarea i utilizarea microcontrollerelor Atmel AVR n prima parte ai fcut cunotin cu microcontrollerele i ai nvat cum se folosete un port ca output. n cele ce urmeaz vei nva cum poi folosi butoane pentru a schimba funcionarea montajului.
De ce ai nevoie?
Pentru a putea folosi butoanele nti s achiziionezi (dac nu ai deja) i s adaugi la circuitul existent urmatoarele componente: 2 push butoane 2 rezistente de 5K6 2 condensatori 100nF Circuitul arat cum se vede mai jos. Este acelai circuit pe care l-ai folosit pn acum cu butoanele conectate la pinii PD2 i PD3.
13
Tutorial Introducere n programarea i utilizarea microcontrollerelor Atmel AVR nainte de a te apuca de scris codul trebuie s tii c aproape fiecare pin, pe lng funcia sa principal de input / output mai are i alte funcii secundare notate n parantez n dreptul pinului din schem. Butoanele le-ai conectat pe pinii PD2 i PD3. n dreptul lor n schem ai s vezi scris INT0 respectiv INT1 care se refer la NTreruperi externe. Ce este o ntrerupere? O ntrerupere poate fi descris ca un eveniment care foreaz uC-ul s execute codul scris pentru acea ntrerupere n locul codului principal. La terminarea codului din ntrerupere se revine unde a rmas n codul principal. Pentru a nelege mai bine ce este o ntrerupere, cum se folosesc n general dar i cum vei folosi butoanele i recomand sa citeti din datasheet-ul uC-ului urmtoarele: Pag. 56 Alternate Port Functions Pag. 63 Alternate Functions of Port D Pag. 63-68 External Interrupts Pentru a te putea folosi efectiv de ntreruperi va trebui s incluzi n cod headerul avr/interrupt.h . ntreruperile sunt procesate de o funcie numit ISR (Interrupt Service Routine) ce primete ca parametru numele vectorului de ntrerupere (ex: ISR(INT0_vect)). Pentru butoane vei folosi ISR(INT0_vect) i ISR(INT1_vect). n interiorul fiecrei funcii vei scrie ce anume vrei s se ntmple cnd are loc ntreruperea respectiv. Butoanele au rezistene de pull-up (pe pinul respectiv al butonului ai 5V) care sunt conectate i la pinii uC-ului la un capat i mas n cealalt parte. Cnd apei unul din butoane, tensiunea pe pinul uC-ului va deveni 0V, deci ai o tranziie HIGH-LOW (falling edge). Att timp ct butonul este apsat ai LOW LEVEL. Cnd dai drumul butonului vei avea din nou 5V, deci o tranziie LOW-HIGH (rising edge). n funcie de cum ai configurat ntreruperea (vezi tabelul 31 i tabelul 32 de la pagina 66-67 a datasheetului) ea se va declana la unul din evenimentele descrise mai sus. n exemplele de mai jos ntreruperea va fi configurat s declaneze la falling edge. Pe lng configurarea corect a ntreruperilor, pentru ca acestea s declaneze trebuie activate global folosind funcia sei(). Pentru a dezactiva global ntreruperile se folosete funcia cli().
Exemple
1. Unul dintre butoane incrementeaz valoarea lui PORTB cu o unitate la fiecare apasare iar celalalt decrementeaz valoarea lui PORTB n acelai fel.
#include <avr/io.h> #include <avr/interrupt.h> ISR(INT0_vect) {PORTB++;} ISR(INT1_vect) {PORTB--;} void main() {DDRB=0xFF;
//PortB ca iesire
14
2. Butonul conectat la INT0 intrementeaz valoarea lui PORTB att timp ct e apsat iar cellalt mparte la doi valoarea la fiecare ridicare a butonului.
#include <avr/io.h> #include <avr/interrupt.h> ISR(INT0_vect) {PORTB++;} ISR(INT1_vect) {PORTB>>=1;} void main() {DDRB=0xFF; //PortB ca iesire MCUCR|=(1<<ISC10)|(1<<ISC11); //declanseaza INT0 pe low level si INT1 pe tranzitie //L-H GIMSK|=(1<<INT0)|(1<<INT1); //activeaza intreruperile pe INT0 si INT1 sei(); while(1); }
15
tiind c timerul este pe 8 bii rezult c ISR(TIMER0_OVF_vect) va declana de 976/256=3.81 ori pe secund. Ce faci dac vrei ca o anumit parte de cod s se execute mai rar de 3.81 ori ntr-o secund? Rspunsul este destul de simplu: implementezi un timer software, care asemenea celui hardware va avea un prescaler stabilit de tine. Not: n cele ce urmeaz voi folosi notaii i expresii de genul declaneaz la 3.81Hz = declaneaz de 3.81 ori pe sec. n cazul de fa dac vrei sa obii execuia unui cod la aproximativ 1Hz poi face ca n exemplul de mai jos:
ISR(TIMER0_OVF_vect) {if(++t==3) {t=0; ... codul tau ... } } // declanseaza la 3.81Hz //la fiecare a treia ntrerupere se va executa codul //reseteaz timerul software //do the monkey business
Exemplul de cod de mai sus d o frecven de execuie a codului de aproximativ 1.27Hz. ATENIE! Frecvena de 1.27Hz obinut mai sus este frecvena la care se va intra n if, respectiv n branch. Frecvena de execuie a instruciunilor din branch este f uC = 1000000 Hz .
16
Exemple
Acum c ai vzut cam cum st treaba cu calculele, hai s vedem i ceva exemple practice de cod. Exemplele ce urmeaz se bazeaz pe exemplele anterioare pentru a nelege mai bine cum se pot combina noiunile nvate pn acum. Ex1: Leduri clipitoare versiunea 2
#include <avr/io.h> #include <avr/interrupt.h> ISR(TIMER0_OVF_vect) {static uint8_t t=0; if(++t==3) {t=0; if(PORTB) PORTB=0; else PORTB=0xFF; } } void main() {DDRB=0xFF; TIMSK|=(1<<TOIE0); TCCR0|=(1<<CS02)|(1<<CS00); sei(); while(1); } //Enable Timer0 overflow interrupt //Timer0 prescaler =f/1024
Ex2: Moving LEDs - aplicaie folosete Timer0 pentru a obine delay-ul necesar aprinderii i stingerii ledurilor. INT0 i INT1 sunt folosite pentru detecia apsrii butoanelor care modific viteza i direcia de deplasare.
#include <avr/io.h> #include <avr/interrupt.h> uint8_t speed=1,t=0,led=0,i=0, dir=0; ISR(TIMER0_OVF_vect) {if(++t==speed) {t=0; if(dir) {if(!led) {if(i<=7) {i++; PORTB=(PORTB<<1)+1; }
17
18
Cum se folosete?
n datasheet este scris foarte detaliat (poate chiar prea detaliat) cum funcioneaz generatoarele de PWM i care sunt modurile de lucru. La baz totul este legat de timere (Timer1 i Timer2) care au i alte funcii pe lng cea de baz. Ca s nelegi o idee mai bine i recomand s arunci o privire n datasheet peste urmtoarele: Pag 59-60 Alternate Port Functions PortB: OC1A, OC1B,OC2 Pag 76-83 Timer1 Pag 85-88 Output Compare Units Pag 88 Modes of operation: Normal Mode, Fast PWM Mode Pag 97-103 Register Description (doar ce tine de PWM, fara Input Capture) Asemntor cu Timer1 se folosete i Timer2 cu cteva deosebiri: este pe 8 bii i are doar un singur generator de PWM. Pentru a-i fi mai uor s foloseti i Timer2 pentru PWM n exemplele ce urmeaz vei folosi Timer1 configurat n aa fel nct s fie compatibil cu Timer2. Ca i pn acum configurarea corect a hardware-ului este esenial n buna funcionare a montajului. Civa pai care trebuiesc urmai n folosirea PWM-ului ar fi: Setarea pinilor folosii pentru PWM ca output. Setarea modului de lucru al generatorului de PWM folosind tabelele din datasheet Iniializarea registrului OCR folosit cu o valoare dorit Activarea Timerului corespunztor generatorului de PWM care se dorete a fi folosit prin selectarea unei surse de ceas Aceti patru pai reprezint de fapt patru linii de cod care pot fi scrise oriunde n cod att timp ct se respect ordinea. De preferat este ca cele patru linii de cod sa fie scrise grupat pentru a evita problemele.
Exemple
1. n acest exemplu un singur generator de PWM va fi folosit doar pentru a demonstra implementarea n cod a celor patru pai descrii mai sus.
#include <avr/io.h> #include <util/delay.h> void main() {DDRB|=(1<<DDB1); //seteaza pinii de PWM ca output TCCR1A|=(1<<COM1A1)|(1<<WGM12)|(1<<WGM10);
19
2. Acest al doilea exemplu este puin mai complex folosind att Timer1 ct i Timer2 pentru a genera trei semnale PWM. n acest fel nlocuind cele 3 leduri de pe PCB conectate la generatoarele de PWM cu un singur led RGB s-ar putea obtine orice culoare existent. Scopul exemplului este ns altul: evidenierea modului de lucru asemanator al timerelor 1 i 2.
#include <avr/io.h> #include <util/delay.h> void main() {DDRB|=(1<<DDB1)|(1<<DDB2)|(1<<DDB3); //seteaza pinii de PWM ca output TCCR1A|=(1<<COM1A1)|(1<<COM1B1)|(1<<WGM12)|(1<<WGM10); // configureaza Timer1: Fast PWM 8bit, Non-inverting OCR1A=255; // initializeaza OCR1A cu 255,OCR1B cu 0 OCR1B=0; TCCR2|=(1<<COM21)|(1<<WGM21)|(1<<WGM20); // configureaza Timer2: Fast PWM 8bit, Non-inverting OCR2=0; // initializeaza OCR2 cu 0 TCCR1B|=(1<<CS10); //seteaza sursa de ceas Timer1: clk/1 (no prescalling) TCCR2|=(1<<CS20); //seteaza sursa de ceas Timer2: clk/1 (no prescalling) while(1) {while(--OCR1A>0) {OCR1B++; _delay_ms(5); } while(--OCR1B>0) {OCR2++; _delay_ms(5); } while(--OCR2>0) {OCR1A++; _delay_ms(5); } }}
20