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? .................................................................................................... 9 Leduri clipitoare...................................................................................................................... 10 Tema 1 ........................................................................................................................................ 11 Partea 2 Push the button .............................................................................................................. 12 De ce ai nevoie? ......................................................................................................................... 12 Cum folosesc butoanele n cod? ................................................................................................. 13 Exemple...................................................................................................................................... 13 Tema 2 ........................................................................................................................................ 14 Partea 3 The clock is ticking ....................................................................................................... 15 Exemple...................................................................................................................................... 16 Partea 4 Fade to black ................................................................................................................. 18 Cum se folosete? ....................................................................................................................... 18 Exemple...................................................................................................................................... 18
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/) 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 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 poi 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. 5
D un nume proiectului i selecteaz unde vrei sa fie salvat apoi apas Next.
Tutorial Introducere n programarea i utilizarea microcontrollerelor Atmel AVR 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> void main() { DDRB|=(1<<DDB0)|(1<<DDB7); PORTB|=(1<<PB0)|(1<<PB7); while(1); } //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
Tutorial Introducere n programarea i utilizarea microcontrollerelor Atmel AVR 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.
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
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> #define #define #define #define #define //header necesar pt a putea accesa pinii uC-ului //header necesar pentru delay
LED0_ON() PORTB|=(1<<PB0) LED0_OFF() PORTB&=~(1<<PB0) LED7_ON() PORTB|=(1<<PB7) LED7_OFF() PORTB&=~(1<<PB7) DELAY() _delay_ms(500)
10
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 abc a b c .
11
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.
12
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()
13
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;}
//PortB ca iesire //declanseaza INT0 pe low level si INT1 tranzitie //L-H //activeaza intreruperile pe INT0 si INT1
pe
14
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 1000000Hz .
15
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. 1. 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
2. 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; } else {led=1; i=0;} }
16
//trigger on falling edge //enable INT0 and INT1 trigger interrupt //Enable Timer0 overflow interrupt //Timer0 prescaler =f/1024
17
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);
18
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 // configureaza Timer1: Fast PWM 8bit, Non-inverting TCCR1A|=(1<<COM1A1)|(1<<COM1B1)|(1<<WGM12)|(1<<WGM10); OCR1A=255; // initializeaza OCR1A cu 255,OCR1B cu 0 OCR1B=0; // configureaza Timer2: Fast PWM 8bit, Non-inverting TCCR2|=(1<<COM21)|(1<<WGM21)|(1<<WGM20); OCR2=0; // initializeaza OCR2 cu 0 //seteaza sursa de ceas Timer1: clk/1 (no prescalling) TCCR1B|=(1<<CS10); 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); } }}
19
Pn acum am vzut cum se pot folosi diverse module ale uC-ului pentru a afia anumite valori sau evenimente pe cele 8 leduri. Dac n partea 2 (Push the button) am vzut cum putem detecta evenimente exterioare de scurt durat (apsarea unui buton) ce se prezint sub forma unor semnale digitale (1 butonul nu este apsat, 0 buton apsat), n aceast parte a tutorialului vom vedea cum putem citi semnale continue n timp (tensiunea pe o rezisten n acest caz). Pentru a putea realiza acest lucru trebuie modificat montajul realizat anterior prin conectarea lui AGND la GND, AVCC la VCC i AREF printr-un condensator la GND ca n schema prezentat mai jos.
20
Cum se folosete?
n datasheet funcionarea modulului de conversie analogic-digital este descris pe 13 pagini ns pentru a putea urma acest pas al tutorialului nu este necesar parcurgerea tuturor paginilor. Totui pentru o mai bun nelegerea felului cum merg lucrurile i recomand s citeti urmtoarele pagini: Pag. 196-198 Analog-to-Digital Converter - Features Pag. 198 Starting a Conversion, Prescaling and Conversion Timing Pag. 200 Changing Channel or Reference Selection Pag. 201 Voltage Reference Pag. 205-208 - ADC Conversion Result, ADC Multiplexer Selection, ADC Control and Status Register A, ADC Data Register
Acum voi explica pe rnd ce nseamn fiecare bloc despre care ai citit n paginile enumerate mai sus: Analog to Digital Converter (Convertor Analogic Numeric): acest dispozitiv are rolul de a converti valoarea unei tensiuni ntr-un numr. Modul n care se face acest lucru difer ntre tipurile de ADC. Pentru aceasta are nevoie de o tensiune de referin, fix, stabil. n funcie de tensiunea de referin i de rezoluia convertorului (numrul de bii pe care lucreaz), pentru aceeai valoare a tensiunii aplicate la intrare se pot obine rezultate diferite. Aa cum ai citit la pag. 205 ADC Conversion Result, rezultatul (numrul) se obine dup formula: n cazul n care se folosesc toi cei 10 bii ai convertorului. Prescaler (pag. 198 Prescalling and Conversion Timing) ca orice circuit digital, i ADC-ul are nevoie de un semnal de tact pentru a funciona. De frecvena acestui semnal depin timpul de conversie i rezoluia maxim. Pentru a folosi ADC-ul la rezoluia maxim, Atmel recomand frecvene ntre 50KHz i 200KHz. Timpul de conversie pentru prima conversie este de 25 de perioade de tact (clock cycles) iar pentru urmtoarele conversii este de 13 perioade. ADC Multiplexer (pag. 200 Changing Channel or Reference Selection): Este posibil ca unui singur convertor s i se atribuie mai multe c anale de intrare, ca i n cazul uC-ului ATMega8 care are un singur ADC cu 5 canale. Acestea se conecteaz la convertor cte unul la un moment dat prin intermediul unui multiplexor. Multiplexorul se comporta ca un comutator cu mai multe pozitii. Poziia este dat de biii MUX3:0 din registrul ADMUX. Astfel pentru canalul 0 (poziia 0) biii vor avea valorile 0000 (0 n zecimal) iar pentru canalul 5 (poziia 5) vor avea valorile 0101 (5 n zecimal). Pentru celelalte combinaii existente vezi Tabelul 75, pag. 206. ADC Voltage Reference (Tensiunea de referin) Aa cum am explicat mai sus, de tensiunea de referin depinde n mod direct rezultatul conversiei pentru aceeai tensiune aplicat la intrare. Convertorul existent n ATMega8 ofer posibilitatea de a alege ntre 3 referine: AREF
21
Tutorial Introducere n programarea i utilizarea microcontrollerelor Atmel AVR (tensiunea aplicat pe pinul AREF), AVCC (tensiunea de alimentare a convertorului, 5V, aplicat pe pinul AVCC) sau referina intern de 2.56V. Este recomandat ca tensiunea de referin s se aleag ct mai apropiat de valoarea maxim pe care o poate atinge semnalul de intrare ns sa nu fie mai mic.
Exemple
1. Acest exemplu demonstreaz cum se seteaz ADC-ul pentru a citi n mod continuu valoarea tensiunii aplicat pe canalul 0 cu afiare pe cele 8 leduri.
#include <avr/io.h> void adc_init(void); uint8_t adc_read(uint8_t channel); int main(void) { DDRB=0xFF; adc_init(); while(1) { PORTB = adc_read(0); } } void adc_init() { ADMUX|=(1<<REFS0) //Referinta AVCC, | (1<<ADLAR);//Deplaseaza rezultatul la stanga (cei mai semnificativi 8 biti in ADHC) ADCSRA|=(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0) //Prescaler: F_CPU/128 | (1<<ADEN); //Activeaza ADCul } uint8_t adc_read(uint8_t channel) { ADMUX &= 0xE0; //Sterge vechiul canal ADMUX |= channel; //Seteaza noul canal ADCSRA|=(1<<ADSC); while(!(ADCSRA&(1<<ADIF))); return ADCH; } //Porneste conversia //Asteapta sfarsitul conversiei //Returneaza rezultatul (pe 8 biti)
//Portb devinde iesire //Initializeaza ADC //Bucla infinita //Transmite pe PortB valoarea citita pe canalul 0
22