This is an old revision of the document!
Raamat, mida käes hoiad, on esimene praktiline mikrokontrolleri ja robootika käsiraamat eesti keeles, mis autorite lootuste kohaselt aitab robootikahuvilistel oma teadmisi laiendada ja paremaid lahendusi ehitada ning meelitab uusi huvilisi inseneriteadustega tegelema. Tegemist on just Eesti vajadustest ja situatsioonist lähtuva praktilise abimehega, mida saab kasutada nii koolis, ülikoolis, hobirobootikas kui ka ettevõtetes praktiliste AVR mikrokontrolleritel põhinevate süsteemide õppimisel ja arendamisel. Käsiraamat on suunatud nii õpetajale kui ka õpilasele, aidates mõlemal kiiremini ja tulemuslikumalt soovitud tulemuseni jõuda: õpilastel siis targemaks saada ja õpetajatel oma õppeaine lihtsamalt ja paremini õpilasteni viia :)
Platvorm
Praktiliste harjutuste konkreetsuse huvides on baasplatvormiks valitud ATmega128 mikrokontrolleril põhinev Mehhatroonika ja Robootika Kodulabori komplekt, mis on paljudes Eesti koolides juba kasutusel. AVR on PIC-i kõrval üks kõige levinumatest mikrokontrolleritest harrastuselektroonikute seas ja see on õppeotstarbeks igati sobilik.
Raamat jaguneb tinglikult viieks osaks:
1. osa teeb kiire sissejuhatuse algajale või meeldetuletuse kogenud elektroonikule lihtsatest, kuid hädavajalikest elektriskeemi arvutusvalemitest. Need valemid ja nende rakendamisoskus tulevad kasuks mitmete praktiliste harjutuste läbimisel. Kiirtutvustus on ka C-keele kohta, mis annab näidete varal ülevaate keele süntaksist.
2. osa annab ülevaate 8-bitilistest AVR seeria mikrokontrolleritest ATmega128 näitel. Peatükk seletab eesti keeles lahti AVR-i andmelehtedes kirjutatu ja on abiks praktiliste harjutuste läbimisel. Algaja võib AVR-i tutvustuse esialgu vahele jätta ja pöörduda selle poole harjutuste käigus, sest tutvustus eeldab üldteadmisi, mida annavad harjutuste teoreetilised peatükid.
3. osa kirjeldab praktiliste tööde aluseks olevat riistvara- ja tarkvaraplatvormi. Viimase juurde kuulub harjutuste jaoks loodud tarkvarateek, mis teeb levinuima mikrokontrolleri funktsionaalsuse kasutamise lihtsaks ja mugavaks. Väheneb nn. raua programmeerimise maht ja rohkem saab tähelepanu pöörata seadme toimeloogikale. Tarkvarakeskkondadest on toetatud nii Windowsi kui ka Linuxi operatsioonisüsteemid.
4. osas on praktilised harjutused, mis on konkreetsed näited enam levinud elektroonika- ja elektromehaanikaseadmete kasutamiseks AVR mikrokontrolleriga. Kõik harjutusülesanded on üles ehitatud ja teema järgi grupeeritud nii, et neid oleks õppimisel võimalikult mugav kasutada. Igal harjutuse peatükil on eraldi seadet ja selle tööpõhimõtet selgitav teooriaosa ning praktiline osa, mis õpetab seadet programmi kaudu juhtima. Harjutuste paremaks mõistmiseks on toodud ka lühinimekiri raamatu teistest seotud peatükkidest. Harjutuste gruppide juurde kuuluvad harjutusülesanded, mida õpetaja saab kasutada täiendava harjutamise eesmärgil. Harjutusülesanded on jaotatud kahte raskusastmesse. Iga teema sisaldab ka kordamisküsimusi, mis enamasti sunnivad antud teema kohta rohkem infot otsima.
5. peatükk on samuti hea õppimise abiline, eriti projektitöö puhul. Peatükk näitlikustab, kuidas esitada projektitööna valminud lahendust ja selle dokumentatsiooni. Toodud on soovitatavad dokumentatsiooni punktid koos osalise näitelahendusega.
Loodame, et raamat on abimeheks nii noorele kui ka vanale robootika- ja mikrokontrollerite huvilisele ning toob mehhatroonika, kui suure perspektiiviga tulevikuala juurde uusi huvilisi.
Lumine ja pakasene Tallinn, jaanuar 2010
Raivo Sell
Mikrokontroller on arvuti, mahutatuna ühe kiibi peale (inglise keeles computer-on-a-chip). Tegu on integraalskeemiga, mis sisaldab nii mälu, protsessorit kui ka sisend-väljundliideseid. Mikrokontroller programmeeritakse täitma mingit kindlat ülesannet nii, et kui funktsionaalsust tahetakse muuta või täiendada, siis tuleb kiibile uus programm peale laadida. Mikrokontrollerid erinevad tavaarvutist (lauaarvuti, sülearvuti, server) mitmete aspektide poolest:
Mikrokontrollereid leidub väga palju seadmetes, mida inimesed igapäevaselt kasutavad, näiteks kodutehnika (mikrolaineahi, telekas), mänguasjad (Lego NXT, rääkivad nukud), sõiduvahendid (auto, tõstuk) jms. Nende laialdane kasutus on olnud võimalik tänu sellele, et oma programmeeritavuse ja laialdase funktsionaalsuse tõttu on seadmetele lihtne lisada uusi omadusi.
Robootika on ala, mis ühendab endas teadmisi ja tehnoloogiat robotite ehitamisest. Tehnoloogia kiire arengu tõttu on aga üha hägustumas mõiste robot kui inimest asendav automaat. Robotina ei saa võtta ainult humanoidrobotit, autotööstuse koosteliini robotkätt, lennuki autopilooti, närvivõrkudel põhinevat tehisintelligenti või lihtsat koristusrobotit, vaid juba ka arvutis jooksvat tarkvara, mis teeb inimese eest mingi töö ära (näiteks raporti koostamine). Roboteid luuakse teadupärast ju inimese asendadamiseks teatud ülesannete täitmisel. Selleks on mitmeid põhjuseid: töökeskkond on inimesele liiga ohtlik, tootmishinda tuleb alandada, et inimtööjõu eest ei peaks enam maksma, nüri ja üksluine töö põhjustab palju eksimusi inimese töös või uued juhtimissüsteemid on piisavalt keerulised ja ajakriitilised, et inimene tuleb asendada automaatse otsustajaga.
Kuna robootika valdkond on väga lai, siis järgnevalt piiritleme seda kui hobirobootikat, kus süsteemid ei ole väga keerulised ning on võimetekohased ehitada ka üksiktegijal. Hobirobootikas on levinumad mikrokontrollerid järgmised:
Väga tihti on kolmandad osapooled loonud arendusplaadid ja -keskkonnad eelnevalt mainitud mikrokontrollerite baasil. Kuna neid on palju, siis tasub välja tuua vaid tuntumad: Arduino (AVR-i baasil), BASIC Stamp (PIC-i baasil) ja Lego NXT (ARM-i baasil). Raamatus lähemalt käsitletavad Kodulabori arendusvahendid on loodud AVR ATmega128 mikrokontrolleri baasil.
Kuna mikrokontrollereid ja nende baasil loodud arendusplaate on väga palju, siis tekib kindlasti küsimus, et kuidas see kõige sobivam leida. Laias laastus võib vaadeldavad omadused jagada nelja kategooriasse - hind, füüsilised parameetrid, arenduskeskkond ja kasutajatugi. Füüsilistest parameetritest tasub jälgida järgmisi:
Arenduskeskkonna all mõeldakse PC arvuti tarkvara, mille abil saab kirjutada ja kompileerida programmi, laadida programm mikrokontrollerisse ning siluda programmi töö käigus, et avastada võimalikke vigu. Siinkohal saabki määravaks see, kui mugav ja lihtne on kõiki neid toiminguid teha, kuna programmi väljatöötamise käigus on see põhiline töökeskkond. Siit jõuab ka neljanda kategooria - kasutajatoe - juurde, ehk kui lihtne on saada abi ja toetust võimalike ettetulevate probleemide lahendamiseks. Kõiki neid nelja eespool mainitud kategooriat vaagides peakski sobiva arendusplaadi leidma.
Praktilistes harjutustes on kirjeldatud elektriskeeme, mis on niivõrd tüüpilised, et on järgnevates peatükkides eraldi välja toodud. Nende tundmine on oluline praktilistest harjutustest arusaamiseks ja läbimiseks. Kindlasti tulevad need kasuks ka paljudes huviliste isiklikes projektides.
Ohmi seadust kasutatakse elektrijuhile rakendatud pinge ja juhti läbiva voolutugevuse vahelise sõltuvuse iseloomustamiseks. Iseloomustav tegur on juhi takistus ehk juhi omadus elektrilaengute liikumist takistada. Ohmi seaduse sõnastas Georg Simon Ohm järgmiselt: voolutugevus juhis on võrdeline juhi otstele rakendatud pingega ja pöördvõrdeline juhi takistusega. Valemi kirjapilt:
I = U / R
kus:
Ohmi seadusest on tuletatud mitmeid teisi valemeid, mida elektroonikas igapäevaselt kasutatakse.
Pingejagur on elektriahel, mille väljundpinge moodustab osa sisendpingest. Väljundpinge suurus sõltub elektriahela moodustavate takistite takistuse suhtest. Kõrvaloleval skeemil on toodud kahe takistiga pingejaguri elektriskeem. Skeemi väljundpinge on arvutatav järgmise valemiga:
U2 = U1 ⋅ (R2 / (R1 + R2))
kus:
Valem tuleneb Ohmi seadusest, mille järgi:
I = U1 / (R1 + R2)
ning:
U2 = I ⋅ R2
Pingejagurit kasutatakse tihti takistuslike andurite ühendamisel, kus üks takistitest asendatakse takistusliku anduriga (näiteks termistor).
Kui LED-i (valgusdioodi) on vaja toita kõrgema pingega, kui on selle päripinge, ja väiksema vooluga, kui toiteallikas välja annab, tuleb LED-iga järjestikku lisada takisti. Takisti piirab voolu ja tekitab vajaliku pingelangu. Õige takisti väärtuse leidmiseks saab kasutada Ohmi seadust:
R = Ur / If = (Uin - Uf) / If
kus:
Kuna takisti valimisel tuleb lähtuda ka selle soojuse eraldamise võimest, siis tuleb leida ka nõutav elektriline võimsus takistil:
Pr = Ur ⋅ If = (Uin - Uf) ⋅ If
Kokkuvõtvalt saab öelda, et LED-i voolu piirav takisti peab olema vähemalt sama suure takistusega, kui R ja vähemalt sama suure võimsusega, kui Pr.
Arvutusnäide:
LED ühendatakse 12 V pingega. Valitud LED-i päripinge on 3 V ja pärivool 20 mA
If = 20 mA = 0,02 A
R = (12 - 3) / 0,02 = 450 Ω
Pr = (12 - 3) ⋅ 0,02 = 0,18 W
Lähim standardne takistus on 470 Ω ja võimsus 1/4 W, nii et sellise takisti valimegi.
Kauaaegne populaarne PC arvutite programmeerimiskeel C on laialt levinud ka mikrokontrollerite programmeerimisel. C on lakooniline riistvaralähedane keel, mis võimaldab kirjutada riistvara võimalusi efektiivselt kasutavat programmikoodi. C-keele süntaksis on võtmesõnu minimaalselt, kuid sisaldab palju erineva tähendusega märke, mis teevad keele õppimise raskeks. Järgnev peatükk sisaldab lühiülevaadet C-keele süntaksi osadest, mis on kasutusel ka praktiliste näidete juures. Algajal on C-keele kohta soovitatav lugeda täiendavaid materjale.
Põhimõtteliselt võib C-keele programmi kirjutada ükskõik mis kujul, kas või üherealisena, sest kompilaator eeldab vaid süntaksireeglite järgimist. Samas on selguse ja lihtsuse huvides ikkagi soovitatav tähelepanu pöörata ka programmikoodi stiilile. Tüüpiline C-keele programmi ülesehitus:
/* Päisefailide kaasamine */ #include <avr/io.h> #include <stdio.h> /* Makro-deklaratsioonid */ #define PI 3.141 /* Andmetüübid */ typedef struct { int a, b; } element; /* Globaalsed muutujad */ element e; /* Funktsioonid */ int main(void) { // Lokaalsed muutujad int x; // Programm printf("Tere maailm!\n"); }
Programmi saab kirjutada teksti, mida ei kompileerita ja mis on programmeerijale abiks selgitamisel või märkmete tegemisel. Samuti saab kommentaare kasutada programmilõikude ajutiseks täitmisest kõrvaldamiseks. Näide kahte liiki kommentaaridest:
// Üherealine kommentaar. // Kommentaariks loetakse kahe kaldkriipsu järel olevat teksti /* Mitmerealine kommentaar Kommentaari algus ja lõpp määratakse kaldkriipsude ja tärnidega */
C-keele baasandmetüübid:
Tüüp | Miinimum | Maksimum | Bitte | Baite |
---|---|---|---|---|
(signed) char | -128 | 127 | 8 | 1 |
unsigned char | 0 | 255 | 8 | 1 |
(signed) short | -32768 | 32767 | 16 | 2 |
unsigned short | 0 | 65535 | 16 | 2 |
(signed) long | -2147483648 | 2147483647 | 32 | 4 |
unsigned long | 0 | 4294967295 | 32 | 4 |
float | -3.438 | 3.438 | 32 | 4 |
double | -1.7308 | 1.7308 | 64 | 8 |
Sulgudes olevat sõna “signed” ei pea kasutama, kuna vaikimisi ongi andmetüübid bipolaarsed.
AVR mikrokontrolleril int = short
PC arvutil int = long
C-keeles puudub spetsiaalne teksti-andmetüüp. Selle asemel kasutatakse char tüüpi massiive (nendest edaspidi) ja ASCII “tähestikku”, kus igal tähel ja märgil on oma järjekorranumber.
Programmis saab kasutada kindlat andmetüüpi mälupesasid - muutujaid. Muutujate nimed võivad sisaldada ladina tähestiku tähti, numbreid ja alakriipsu. Nimi ei tohi alata numbriga. Muutuja deklareerimisel kirjutatakse selle ette andmetüüp. Väärtuse omistamiseks muutujale kasutatakse võrdusmärki (. Näide muutujate kasutamisest:
// char tüüpi muutuja c deklareerimine char c; // Muutujale c väärtuse omistamine. c = 65; c = 'A'; // A on ASCII märgisüsteemis samuti väärtusega 65 // int tüüpi muutuja i20 deklareerimine ja algväärtustamine int i20 = 55; // Mitme unsigned short tüüpi muutuja deklareerimine unsigned short x, y, test_variable;
Konstante deklareeritakse samamoodi nagu muutujaid, kuid ette lisatakse const võtmesõna. Konstantide väärtust ei saa programmi käigus muuta. Näide kasutamisest:
// int tüüpi konstandi määramine const int x_factor = 100;
Baasandmetüüpidest saab struct võtmesõnaga struktuure koostada. Struktuur on justkui kombineeritud andmetüüp. Tüüpi deklareeritakse typedef võtmesõnaga. Näide struktuurist andmetüübi loomise ja kasutamise kohta:
// Uue punkti andmetüübi deklareerimine typedef struct { // x ja y koordinaat ning värvikood int x, y; char color; } point; // Punkti muutuja deklareerimine point p; // Punkti koordinaatide määramine p.x = 3; p.y = 14;
Andmetüüpidest võib koostada massiive (jadasid). Massiiv võib olla ka mitmemõõtmeline (tabel, kuup, jne). Näide ühe- ja kahemõõtmelise massiivi kasutamisest:
// Ühe- ja kahemõõtmelise massiivi deklareerimine char text[3]; int table[10][10]; // Teksti moodustamine tähemassiivist text[0] = 'H'; // Täht text[1] = 'i'; // Täht text[2] = 0; // Teksti lõpetamise tunnus (null-bait) // Tabeli ühe elemendi muutmine table[4][3] = 1;
Muutujate, konstantide ja väärtust tagastavate funktsioonidega saab koostada avaldisi (tehteid). Avaldise väärtusi saab omistada muutujatele, neid saab kasutada funktsiooni parameetritena ja erinevates tingimuslausetes.
C-keeles toetatud aritmeetilised tehted on liitmine (+), lahutamine (-), korrutamine (*), jagamine (/) ja mooduli võtmine (%). Näited aritmeetiliste tehete kasutamisest:
int x, y; // Mooduli võtmine, korrutamine ja väärtuse omistamine // x saab väärtuse 9 x = (13 % 5) * 3; // Liitev-omistav operaator // x väärtuseks saab 14 x += 5; // Ühe lahutamise kiirmeetod // x väärtuseks saab 13 x--;
Loogilised tehted on eitus (!), loogiline korrutamine (&&) ja loogiline liitmine (||). Näide tehete kasutamisest:
bool a, b, c; // Algväärtustamine a = true; b = false; // Eitus // c väärtus tuleb väär sest tõest eitati c = !a; // Loogiline korrutamine // c väärtuseks tuleb väär, sest üks operandidest on väär c = a && b; // Loogiline liitmine // c väärtus tuleb tõene, sest üks operandidest on tõene c = a || b;
NB! bool andmetüüp C-keeles tegelikult puudub, selle asemel on kasutusel täisarvud, kus 0 tähistab väära ja iga muu arv tõest väärtust. Näiteks Kodulabori teegis on defineeritud bool kui unsigned char. Konstant true tähistab seal väärtust 1 ja false väärtust 0.
Arvude väärtuste võrdlemisel saadakse loogilised väärtused. Võrdlustehted on samaväärsus (, erinevus (!
, suurem (>), suurem-võrdne (>
, väiksem (<) ja väiksem-võrdne (⇐). Näide kasutamisest:
int x = 10, y = 1; // Suurem-kui võrdlustehe, mis on tõene // Tehte ümber on sulud vaid selguse pärast bool b = (5 > 4); // Erinevuse tehe // Tehte tulemus on väär b = (4 != 4); // Aritmeetiline, võrdlus ja loogiline tehe üheskoos // b tuleb väär, sest esimene loogilise korrutise operand on väär b = (x + 4 > 15) && (y < 4);
Bititehted on andmetega binaarses arvusüsteemis tegelemiseks. Neid saab rakendada kõigi täisarv-tüüpi andmetega. Bititehted sarnanevad loogiliste tehetega, kuid erinevad selle poolest, et tehe teostatakse iga bitiga eraldi, mitte kogu arvuga. C keeles on bititeheteks inversioon (~), konjunktsioon (&), disjunktsioon (|), antivalentsus (^), nihe vasakule («) ja nihe paremale (»).
// Märgita 8-bitise char-tüüpi muutuja deklareerimine // Muutuja väärtus on kümnendsüsteemis 5, kahendsüsteemis 101 unsigned char c = 5; // Muutuja c disjunktsioon arvuga 2 (kahendsüsteemis 010) // c väätuseks saab 7 (kahendsüsteemis 111) c = c | 2; // Bitinihe vasakule 2 võrra // c väärtuseks saab 28 (kahendsüsteemis 11100) c = c << 2;
Bititehted on hädavajalikud mikrokontrollerite registrite kasutamisel. Täpsemalt tutvustab neid AVR registrite peatükk.
Funktsioon on programmilõik, mida saab selle nime järgi täitmiseks välja kutsuda. Funktsioonil võivad olla parameetrid ja funktsioon võib tagastada ühe väärtuse. Kui funktsioon ei tagasta väärtust, on selle tüüp void. Kui funktsioonil pole parameetreid, tuleb vanemat C-keele kompilaatorit kasutades void kirjutada ka parameetrite deklaratsiooni asemele. Näide liitmisfunktsioonist ja tagastamisväärtuseta funktsioonist:
// Kahe int tüüpi parameetriga funktsiooni deklareerimine // Funktsioon tagastab int-tüüpi väärtuse int sum(int a, int b) { // Kahe arvu liitmine ja summa tagastamine return a + b; } // Ilma parameetrite ja tagastatava väärtuseta funktsioon void power_off(void) { }
Funktsiooni kasutamiseks tuleb see välja kutsuda. Funktsioon peab programmikoodis olema deklareeritud enne välja kutsumise kohta. Näide liitmisfunktsiooni väljakutsumisest.
int x; int y = 3; // Liitmisfunktsiooni väljakutsumine // Parameetriteks on muutuja ja konstandi väärtus x = sum(y, 5); // Väljalülitamise funktsiooni väljakutsumine // Parameetrid puuduvad power_off();
C-keele programmi täitmist alustatakse main nimelisest funktsioonist, mis teeb selle kohustuslikuks funktsiooniks.
Tingimuslause võimaldab vastavalt sulgudes oleva avaldise tõesusele täita või mitte täita tingimusele järgnevat lauset või programmilõiku. Tingimuslause võtmesõna on if. Näide kasutamisest:
// Avaldis on tõene ja lause x = 5 täidetakse, // sest 2 + 1 on suurem kui 2 if ((2 + 1) > 2) x = 5; // Kui x on 5 ja y on 3, siis täidetakse järgnev programmilõik if ((x = 5) && (y = 3)) { // Suvaline tegevus y = 4; my_function(); }
Tingimuslause võib olla pikem ja sisaldada ka lauset või programmilõiku, mis täidetakse avaldise mittetõesuse korral. Selleks tuleb if tingimuslause järel kasutada else võtmesõna.
// Kas x on 5 ? if (x = 5) { // Suvaline tegevus z = 3; } // Kui x ei olnud 5, kas siis x on 6 ? else if (x = 6) { // Suvaline tegevus q = 3; } // Kui x ei olnud 5 ega 6... else { // Suvaline tegevus y = 0; }
Kui on vaja võrrelda avaldist mitme erineva väärtusega, on mõistlik kasutada valikulauset switch võtmesõnaga. Näide kasutamisest:
int y; // Tingimuslause y võrdlemiseks switch (y) { // y on 1 ? case 1: // Suvaline tegevus function1(); break; // y on 2 ? case 2: // Suvaline tegevus function2(); break; // Kõik muud juhtumid default: // Suvaline tegevus functionX(); // break lauset pole vaja, // kuna võrdlemine lõppeb nagunii }
Tsüklitega saab programmilõiku täita mitmeid kordi.
while võtmesõnaga tähistatud programmilõiku täidetakse seni, kuni sulgudes olev avaldis on tõene.
int x = 0; // Tsükkel kestab seni, kuni x on väiksem kui 5 while (x < 5) { // x suurendamine ühe võrra x++; }
for võtmesõnaga tsükkel sarnaneb while tsüklile, kuid lisaks on sulgudes ära määratud enne tsüklit täidetav lause ja iga tsükli ajal täidetav lause.
Näide:
int i, x = 0; // Algul määratakse i nulliks. Tsüklit täidetaks seni, kuni // i on vähem kui 5. Iga tsükli lõpus suurendatakse i ühe võrra for (i = 0; i < 5; i++) { // x suurendamine 2 võrra x += 2; } // Siinkohal tuleb x väärtuseks 10
while ja for tsüklitest saab erandkorras väljuda break võtmesõnaga. continue võtmesõnaga saab alustada järgmist tsüklit ilma järgnevat koodi täitmata.
int x = 0, y = 0; // Lõputu tsükkel, kuna 1 on loogiline tõesus while (1) { // Tsüklist väljutakse, kui x on saavutanud väärtuse 100 if (x >= 100) break; // x suurendamine, et tsükkel kunagi lõppeks ka x++; // Kui x on 10 või vähem, siis alustatakse järgmist tsüklit if (x <= 10) continue; // y suurendamine y++; } // Siinkohal on y väärtus 90
Järgnevad peatükid tutvustavad AVR mikrokontrollerit, mille põhjal on koostatud kogu käesolev raamat. Mikrokontroller, olgugi et pisike, on täis mitmeid võimalusi, mille kasutamise kohta Atmel on kirjutanud peaaegu 400-leheküljelise juhendi ning lisaks mitmed spetsiifilised lisadokumendid. Kogu sellest infost on siinkohal tehtud kiire ja võimalikult lihtne ülevaade, mis aitab algajal paremini AVR mikrokontrolleri funktsionaalsusest aru saada ja selle dokumentatsioonis orienteeruda.
AVR on Atmeli poolt toodetav 8-bitiste RISC mikrokontrollerite seeria. Harvardi arhitektuuri kohaselt on AVR-il eraldi programmi- ja andmemälu. Programmi jaoks on süsteemisiseselt ümberkirjutatav välkmälu (inglise keeles Flash), andmete jaoks staatiline (SRAM) ja EEPROM mälu. Taktsagedus ulatub enamasti kuni 16 MHz ja jõudlus on peaaegu 1 MIPS megahertsise takti kohta.
AVR mikrokontrollerite tootmist alustati 1997. aastal ja praeguseks on see vabakutseliste elektroonikute seas üks levinumaid. Esialgse edu tagasid odavad arendusvahendid, mitmekesine perifeeria ühes korpuses ja madal voolutarve. Nüüdseks võib eeliseks lugeda suure infomaterjali ja õpetuste pagasit, mis aastate jooksul tekkinud on. Paratamatult on AVR tehnoloogia vananev, kuid konkurentsis püsimiseks teeb Atmel ka tänapäevase perifeeria ning 16- ja 32-bitiste siinidega AVR mikrokontrollereid, millest esimesed on 8-bitistega ühilduvast XMega ja teised täiesti uuest AVR32 seeriast.
Vastavalt rakenduste tüübile on ka AVR mikrokontrollereid olemas erineva konfiguratsiooniga. Suurema osa AVR-e moodustab megaAVR seeria, mis on suure programmimälu mahuga. Vastupidiselt megaAVR seeriale on olemas tinyAVR seeria väiksemate kestade ja kärbitud võimalustega. Lisaks on veel mikrokontrollerite seeriad spetsiaalselt USB, CAN, LCD, ZigBee, automaatika, valgustuse juhtimise ja akutoitega seadmete jaoks.
Järgnevalt on kirjeldatud peamisi megaAVR seeria mikrokontrollerite võimalusi selle seeria ühe levinuima kontrolleri - ATmega128 näitel, mis on kasutusel ka Kodulabori komplektis. Üldiselt on kõigil AVR seeria mikrokontrolleritel registrite nimed, tähendused ja kasutamise kord reglementeeritud nii, et näiteid saab väikeste muudatustega ka teiste kontrollerite puhul kasutada. Peamised erinevused esinevad perifeeria juures. Tutvustuse koodinäited on toodud assembleris ja C-keeles AVR LibC abil.
Nagu kõik teisedki kiibid, on AVR pakendatud mingi standardkesta sisse. Traditsiooniline kest on DIP (nimetatakse ka DIL). DIP on nii-öelda jalgadega kest - kõik kiibi viigud on umbes 5-millimeetriste jalgadena näpuotsasuurusest mustast plastist korpusest välja toodud. DIP kest on mõistlik valik hobirakendustes ja prototüüpide puhul, sest selle jaoks on saada odavad pesad, kust saab mikrokontrolleri läbipõlemise korral lihtsalt kätte ja uuega asendada. Samas on jalad ka DIP kesta miinuseks, sest nende jaoks on vaja trükiplaadile auke puurida.
Palju kompaktsemad on pindliides ehk SMT (nimetatakse ka SMD) kestad, sest neil on jalad mõeldud mitte plaadi läbistamiseks, vaid otse rajale kinnijootmiseks. SMT kestas on kiibid õhukesed umbes mündi suurused neljakandilised mustad korpused, mille jalad on umbes millimeetri pikkused. SMT kestas kiipide jootmisel on vaja täpsemat kätt ja paremaid töövahendeid.
AVR-e on saada nii DIP kui SMT kestades. Viikusid on püütud loogiliselt ning elektriliselt ühtlaselt paigutada. Näiteks on maa ja toiteviigud suurematel kiipidel toodud mitmesse kiibi külge, välise kvartsi viigud on maa viigu lähedal, siinide viigud on numbrilises järjekorras, andmesideliideste viigud on kõrvuti jne. AVR digitaalsed viigud ühilduvad TTL/CMOS standardsete pingenivoodega. 5 V toitepinge juures tähistab pinge 0 kuni 1 V loogilist nulli, mida nimetatakse ja kirjutatakse elektroonikute kõnepruugis ka kui: null, 0, madal, maa, mätas, ground või GND. Sama toitepinge juures tähistab pinge 3 kuni 5,5 V loogilist üht, mille nimetused on: üks, 1, kõrge, high. Selline suur loogiliste väärtuse pingeskaala kehtib sisendite kohta - väljundpinge on ilma koormuseta AVR viikudel vastavalt olekule ikkagi 0 V või toitepinge lähedane. Tehnoloogiast tingituna on ka analoogpinge (ADC kanalid) väärtused lubatud sarnases 0 kuni 5,5 V vahemikus.
Et järgnevatest näidetest ATmega128 kohta paremini aru saada, on välja toodud ATmega128 SMT kesta viikude skeem. Viikude juures on selle number, primaarne funktsioon ja sulgudes alternatiivne funktsioon. Toiteotsad on GND ja VCC. AVCC ja AREF on vastavalt analoog-digitaalmuunduri toite ja võrdluspinge viigud. XTAL1 ja XTAL2 on välise kvartsostsillaatori, resonaatori või taktigeneraatori jaoks. Viigud PB0 kuni PG4 tähistavad sisend-väljundsiinide bitte. Viikude alternatiivfunktsioonidest tuleb juttu vastavates peatükkides.
Üks kõige raskemini mõistetavaid asju mikrokontrollerite juures on algajate jaoks tavaliselt “register”. Sellest mõistest ei pääse üle ega ümber, kui on soov mikrokontrolleritega tegeleda. Ka käesolev materjal eeldab, et lugeja saab tuttavaks registri mõistega ja seepärast on järgnevalt seda algajale ka võimalikult lihtsalt selgitatud.
Register on nagu mõne kodumasina nuppude paneel. Seal on lülitid, mida saab sisse vajutada või välja lükata. Üks parim näide on kassetimängija. Kes veel mäletab, siis kassetimängijatel on (oli) vasakult paremale 6 nuppu:
Iga nupp teeb midagi, kuid ainult õigel kasutamisel. Näiteks stopp-nupp ei tee midagi enne, kui kassett on mängima pandud - alles siis teeb see midagi arusaadavat ja peatab mängimise. Edasi- või tagasikerimise nuppe võib aga igal ajal vajutada, sest linti hakatakse kerima nii poole mängimise kui seismise ajal. Salvestama hakkab kassetimängija aga ainult siis, kui salvestamise nupp koos mängimise nupuga alla vajutada. Mõni on ehk proovinud mitu nuppu või kõik nupud korraga alla vajutada - sel juhul võis mängija mida iganes teha või üldse katki minna.
Mikrokontrolleri registriga on sama lugu nagu kassetimängija nuppudega - iga nupuke paneb seal õigel kasutamisel midagi käima. Valesid nuppe vajutades mikrokontroller (enamasti) küll katki ei lähe, kuid ei tööta ka. Tegelikult registris selliseid nuppe nagu kodumasinatel muidugi pole, on hoopis hulk transistore, mis elektrit sisse ja välja lülitavad. Lihtsamatel mikrokontrolleritel on registris 8 transistoridel põhinevat elektrilist lülitit. Registrit võib aga käsitleda nagu 8-bitist arvu, milles iga bitt tähistab ühe lüliti olekut. Näiteks biti väärtus 1 võib tähendada, et lüliti on sees ja 0, et lüliti on väljas.
Kuna registri lülitite olekut saab väga hästi esitada arvuna ja vastupidi, siis võib registrit võrrelda ka mäluga, mis suudab hoida ühe arvu suurust informatsiooni. Selle võrdlusega jõudis jutt selleni, et registrid ongi mälupesad. Vahe mälupesaga seisnebki üldjuhul ainult selles, et mälupesa ei tee muud, kui hoiab informatsiooni, registris see informatsioon aga juhib midagi. Ehk kui pildil kujutatud registrisse kirjutada binaarväärtus 01100001, siis kolm näilist lülitit lükatakse alla ja midagi hakkab toimuma.
Kui kassetimängijal võib igat nuppu eraldi vajutada, siis registrites on ühe “lüliti” või biti muutmine keerulisem. Üldjuhul tuleb muuta kogu registri sisu korraga. Enne kui bittide muutmisest rääkida, tuleks aga teada veel seda, et registreid on mikrokontrolleris palju. Mõnede mikrokontrolleri osade juhtimiseks võib kasutusel olla ka kümneid registreid. Registrite paljusus tähendab, et registreid peab kuidagi eristama ja seda tehakse nimega. Üks ilus registri nimi on näiteks PORTB. Tõe huvides võib mainida, et tegelikult on nimed vaid inimese välja mõeldud asendused numbrilistele aadressidele.
C-keele programmis registri väärtuse kirjutamiseks või lugemiseks tuleb selle poole pöörduda nagu muutuja poole. Järgnev näide demonstreerib väljamõeldud registrisse REG binaarväärtuse kirjutamist ja selle väärtuse muutujasse reg lugemist. Binaarväärtuse ette kirjutatakse 0b (ees on null), et kompilaator arvusüsteemist aru saaks.
REG = 0b01100001; unsigned char reg = REG;
Põhimõtteliselt registrite väärtuse kirjutamises ja lugemises midagi keerulist polegi, kuid keerulisemaks läheb lugu siis, kui soovitakse muuta registri üksikute bittide väärtust. Bittide muutmiseks tuleb enne selgeks saada binaartehted ja erinevad arvusüsteemid. Keegi ei keela tegutseda binaararvudega, kuid binaararvudega tegelemine on tülikas nende pikkuse tõttu ja tavaliselt kasutatakse nende asemel heksadetsimaalarve, mis on lühemad.
Heksadetsimaalarvus pole numbrid mitte 0 ja 1, nagu binaarsüsteemis, ega 0-st 9-ni, nagu kümnendsüsteemis, vaid 0-st F-ni. Üks heksadetsimaalnumber moodustub neljast bitist. Kõrvalolev tabel näitab heksadetsimaalnumbritele vastavaid binaararve. Binaararve teisendatakse heksadetsimaalarvuks lugedes bitte nelja kaupa, alates madalamast järgust. Järkusid loetakse paremalt vasakule ja nende nummerdamist alustatakse nullist. Näiteks binaararvu 1110 madalaima ehk 0. järgu väärtus on 0 ja kõrgeima ehk 3. järgu väärtus on 1. Eespool toodud näidisregistri binaarväärtus 01100001 on heksadetsimaalkujul 61, mis C-keeles kirjutatakse kujul 0x61 (ees on null).
Üksikute bittide muutmiseks arvus (registris, muutujas või kus iganes) tuleb kasutada binaartehteid. Binaartehe on tehe binaararvude vahel, kus nende arvude iga biti vahel toimub omaette loogikatehe. Enamasti on mikrokontrollerites kasutusel neli binaartehet, millel kõigil on mitu nimetust. Järgnevalt on toodud kõigile neljale binaartehtele vastav loogikatehe üksiku biti või bittidega.
Nüüd on lühidalt selgitatud kõik, mida läheb vaja üksikute bittide väärtuste muutmiseks. Kuid ilmselt jääb teooriast ikkagi väheks ja seepärast on järgnevalt toodud mõningad tüüpnäited registritega.
Selleks et üks või enam bitte registris kõrgeks ehk üheks seada, tuleb kasutada loogilist liitmise tehet. Liitmistehte üks operand peab olema register, teine binaararv, kus kõrge on ainult see bitt, mida ka registris soovitakse kõrgeks seada. Seda teist binaararvu nimetatakse ka bitimaskiks. Kõrvalnäites toodud tehe näeb C-keeles välja niimoodi:
// Oletame, et REG = 0x0F REG = REG | 0x11; // Üks meetod REG |= 0x11; // Teine meetod // Siinkohal REG = 0x1F
Ühe või enama biti registris madalaks ehk nulliks seadmiseks tuleb kasutada loogilise korrutamise tehet. Tehte üks operand peab olema register, teine bitimask, kus madalaks on seatud vaid see bitt, mida ka registris soovitakse madalaks seada. Kõrvalnäites toodud tehe näeb C-keeles välja nii:
// Oletame, et REG = 0x0F REG = REG & 0xFE; // Üks meetod REG &= 0xFE; // Teine meetod // Siinkohal REG = 0x0E
Ühe või enama biti registris inverteerimiseks tuleb kasutada mittesamaväärsuse tehet. Tehte üks operand peab olema register, teine bitimask, kus kõrgeks on seatud vaid see bitt, mida ka registris soovitakse inverteerida. Kõrvalnäites toodud tehe näeb C-keeles välja järgmiselt:
// Oletame, et REG = 0x0F REG = REG ^ 0x11; // Üks meetod REG ^= 0x11; // Teine meetod (rakendada tohib korraga ainult üht) // Siinkohal REG = 0x1E
Kogu registri bittide inverteerimiseks tuleb kasutada eitustehet. See on unaarne tehe ehk tal on ainult üks operand. Kõrvalnäites toodud tehe näeb C-keeles välja niimoodi:
// Oletame, et REG = 0x0F REG = ~REG; // Siinkohal REG = 0xF0
Ühe või enam biti väärtuse lugemiseks registrist tuleb kasutada sama tehet, mis biti nullimisel - loogilist korrutamist. Tehte üks operand peab olema register, teine bitimask, kus kõrgeks on seatud vaid see bitt, mille väärtust registrist lugeda soovitakse. Kõrvalnäites toodud tehe näeb C-keeles välja järgmiselt:
// Oletame, et REG = 0x0F unsigned char x = REG & 0x01; // Siinkohal x = 0x01
Tegelikult on paljudes programmeerimiskeeltes peale binaartehete veel mõned bitioperatsioonid, mis teevad programeerija elu lihtsamaks. Need on bitinihutuse operatsioonid, mis binaararvus nihutavad bitte kas vasakule või paremale poole. Nihutusoperatsioonide põhiline väärtus seisneb registritega tegeldes nende võimes bitijärkusid bitimaskiks teisendada ja vastupidi.
Kõrvaloleval pildil on toodud näide bitinihutuse operatsioonist vasakule. Bitinihutus pole loogikaoperatsioon ja sel puudub vastav tähis, C-keeles on see aga “«”. Nihet vasakule kasutatakse bitijärgu bitimaskiks teisendamiseks. Näiteks, kui soovitakse kuuenda biti (NB! järk on 5) maski, siis tuleb arvu 1 nihutada vasakule 5 korda. Näites toodud operatsioon näeb C-keeles välja järgmiselt:
REG = 0x01 << 5; // Siinkohal REG = 0x20
Sarnaselt bitinihkega vasakule toimib ka bitinihke operatsioon paremale. Selle operatsiooni tähis C-keeles on “»”. Nihet paremale kasutatakse bitimaskist biti loogilise väärtuse leidmiseks. Eespool oli toodud näiteks üksiku biti väärtuse lugemise tehe. Oletame, et bitt, mida lugeda, pole aga madalaima järguga, vaid näiteks järguga 5. Sel juhul oleks lugemisel vastus kas 0x20 või 0x00, kuid vahel läheb vaja vastust 1 või 0 ja siis tulebki appi nihe paremale. Kõrvalnäites toodud operatsioon näeb C-keeles välja nii:
// Oletame, et REG väärtus on 0x20 unsigned char x = REG >> 5; // Siinkohal on x väärtus 0x01 (ehk lihtsalt 1)
Kui bitinihke operatsioonidega nihkub bitt madalaimast järgust paremale või kõrgeimast järgust vasakule, siis see bitt kaob. Mõnedes programmeerimiskeeltes on olemas ka roteeruvad bitinihke operatsioonid, kus “servast” välja minev bitt tuleb teiselt poolt tagasi. C-keeles roteeruvad bitinihke operatsioonid puuduvad, kuid vajadusel saab need ise kirjutada.
Kõik toodud bitioperatsioonide näited toimivad peale registrite ka muutujatega ja konstantidega. Viimased saavad muidugi ainult operandideks, mitte vastusteks olla.
Selleks et midagi reaalselt mikrokontrolleri registritega teha saaks, tuleb osata selle mikrokontrolleriga läbi saada. Kõigi mikrokontrolleritega käib kaasas üks või mitu andmelehte, kus on dokumenteeritud kogu mikrokontrolleri struktuur ja funktsionaalsus. Andmelehes on kirjeldatud ka registrid. Järgnevalt uurime, kuidas saada aru AVR-i andmelehe registrite kirjeldusest.
Pildil on toodud ATmega128 mikrokontrolleri register UCSRnA, mille pikem nimetus on “USART Control and Status Register A”. See on register, millega sätitakse AVR-i USART moodulit ja kust saab lugeda selle mooduli olekuid. Kõik AVR-i registrite nimed kirjutatakse suurte tähtedega, kuid tähelepanelik lugeja ilmselt märkab, et selles registris on väike n-täht. Väikese n-tähega tähistatakse nimelt mõne mooduli indeksit. Kuna ATmega128-s on 2 üsna sarnast USART moodulit, siis ei kirjeldata nende registreid topelt, vaid ühe korra ja n-tähe asemele peab lugeja arvestama kas “0” või “1”. Seega ATmega128-s on registrid UCSR0A ja UCSR1A.
Registri sisu tähistab paksu piirjoonega 8 lahtriga kast. Iga lahter tähistab üht bitti. Kasti kohal on toodud biti järgud - suurenevad paremalt vasakule. Kuna AVR on 8-bitine mikrokontroller, on ka enamik registreid 8-bitised. Mõningad erandid on 16-bitised registrid, mis koosnevad tegelikult kahest 8-bitisest registrist. Lisaks registritele on nimi ka igal registri bitil - täpselt nagu kassetimängija nuppudelgi. Iga biti kohta on andmelehes olemas selle selgitus. Biti nimed on samuti lühendid ja n-täht neis tuleb samuti asendada mooduli indeksiga. Mõnes registris pole kõiki 8 bitti kasutatud ja sel juhul tähistatakse biti lahter sidekriipsuga.
Registri bittide all on toodud kaks rida, kus on kirjas, kas bitt on loetav (R), kirjutatav (W) või mõlemat (R/W). Näiteks olekubitte ei saa üle kirjutada ja isegi siis, kui seda programmis üritada, ei omanda bit lihtsalt talle omistatavat väärtust. Biti puhul, mida saab ainult kirjutada, on öeldud üks kindel väärtus, mis selle lugemisel alati tuleb. Bittide all teises reas on toodud vaikeväärtus, mis on bitil pärast mikrokontrolleri käivitamist (inglise keeles reset).
Kui AVR-i registrite nimed viitavad tegelikult mälupesade aadressidele, siis biti nimede taga peitub selle biti järgu number. Seega registris bittidega manipuleerimiseks tuleb bitinimed nihutusoperatsiooni abil bitimaskiks teisendada. Järgnevalt on toodud mõned C-keele näitelaused eeltoodud USART 0 mooduli registri kasutamiseks.
// TXC0 biti kõrgeks seadmine UCSR0A |= (1 << TXC0); // U2X0 biti madalaks seadmine UCSR0A &= ~(1 << U2X0); // UDRE0 biti(maski) väärtuse lugemine unsigned char u = (UCSR0A & (1 << UDRE0)); // Siinkohal on u väärtus kas 0 või 32, // mis võimaldab seda loogilises avaldises kasutada if (u) { // MPCM0 biti inverteerimine UCSR0A ^= (1 << MPCM0); } // Mõnikord on aga vaja saada konkreetne 0 või 1 väärtus, // selleks tuleb loetud bitti nihutada paremale u >>= UDRE0; // Siinkohal on u väärtus kas 0 või 1
AVR-il on sisemine 8-bitine andmesiin, mille kaudu liiguvad andmed arvutusüksuse (ALU), olekuregistri (SREG), programmiloenduri (PC), muutmälu (SRAM) ja perifeeria vahel. ALU-s täitmisele minev programm ehk instruktsioonide jada tuleb välkmälu aadressilt, mille määrab programmiloendur. ALU juurde kuuluvad 32 üldkasutatavat 8-bitist registrit, mida kasutatakse paljude instruktsioonide täitmisel operandidena.
AVR-i käsukonveier on kaheastmeline. Samal ajal kui üht instruktsiooni täidetakse, laetakse järgmine instruktsioon programmimälust ootele. See on ka põhjus, miks siirdekäskude täitmine võtab 2 takti siirdetingimuse täitumisel. Kuna uus instruktsioon laetakse käsukonveierisse alati järgmiselt mäluaadressilt, siis siiretel muule programmiaadressile tuleb eelnevalt laetud instruktsioon minema visata ja uus laadida, sest see oli vanast ehk siis valest kohast laetud.
Üldkasutatavad registrid R0-R31 on justkui vahepuhvrid mälu ja perifeeria andmete hoidmiseks ning nendega toimetamiseks. Üldkasutatavad registrid lihtsustavad protsessori arhitektuuri, kuna ALU jaoks on need kiirelt kättesaadavad ja igal arvutusel ei pea operandide mälust lugemiseks kasutama andmesiini. Üldkasutatavaid registreid kasutatakse kõikide andmetega seotud aritmeetiliste ja loogiliste operatsioonide tegemiseks.
Assemblerkeeles programmeerides võib kiiret töötlust vajavaid andmeid üldkasutatavates registrites hoida. Kui programmeeritakse C-keeles ja on kindel soov muutuja hoidmiseks üldkasutatavat registrit kasutada, defineeritakse muutuja täiendavalt “register” tüüpi. Näiteks:
register char x;
Enamiku AVR-ide käsustik koosneb 90-133 erinevast instruktsioonist. ATmega128-l on 133 instruktsiooni. Instruktsioonid on kas ühe, kahe või üldse ilma operandideta. Enamik instruktsioone täidab mikrokontrolleri protsessor ühe takti jooksul, kuid keerukamad kulutavad kuni 5 takti. AVR-i järeltulija XMega puhul on mitmeid instruktsioone täiendatud nii, et need kulutavad vähem takte. Suurem osa AVR-i instruktsioonidest on siireteks, andmete liigutamiseks, võrdlusteks ja loogilisteks ning aritmeetilisteks teheteks. Tehete ja võrdluste puhul on kasutusel olekuregister, kus märgitakse vastavate bittidena ära juhud, kui tehte tulemus ALU-s oli: negatiivne või positiivne, null, ületas maksimaalse võimaliku väärtuse (8-bitti), vajas biti ülekandmist järgmisesse tehtesse, ja veel paaril keerukamal juhul.
Näide
Toodud on Assembleris ehk puhtalt instruktsioonidena kirjutatud kood, mis liidab muutmälus aadressil $100 (detsimaalarvuna 256) asuvale baidile juurde arvu 5. Kasutatud käsud on olemas kõigil AVR-idel.
ldi r1, 5 ; Konstandi 5 laadimine üldkasutatavasse registrisse r1 lds r2, $100 ; Baidi laadimine muutmälust registrisse r2 add r2, r1 ; Registrile r2 registri r1 väärtuse liitmine sts $100, r2 ; Registri r2 väärtuse kirjutamine tagasi muutmällu
Pinumälu (inglise keeles stack) on andmete ülesehitus, kus viimasena mällu kirjutatud andmed loetakse välja esimesena. AVR-is saab pinumälu kasutada alamfunktsioonide, katkestuste ja ajutiste andmete juures. Alamfunktsioonide ja katkestuste täitmisel lisatakse eelnevalt pinumällu programmiloenduri aadress, mille pealt programm katkes. Kui alamfunktsioon või katkestus on töö lõpetanud, loetakse pinumälust aadress, kust programmi tööd jätkata. Ajutisi andmeid lisatakse pinumällu tavaliselt lühemate programmilõikude juures, mis ei vaja mälu reserveerimist kogu programmi ajaks. Lihtsamad assemblerkeele programmid on kirjutatud üldjuhul nii, et pinumälu kasutama ei pea, kuid selle võtavad kasutusele kompilaatorid, kui programmis on palju muutujaid ning funktsioone.
MegaAVR seeria mikrokontrolleritel on pinumälu füüsiline asukoht muutmälus, kuid mõnel tinyAVR seerial muutmälu üldse puudub ja pinumälu tarbeks on spetsiaalne üsna piiratud mahuga mälu. Sellistele, ilma muutmäluta mikrokontrolleritele kompilaatoreid üldjuhul pole.
Kõrgtaseme keeles (Pascal, C, C++) programmeerides ei pea otseselt mikrokontrolleri siseeluga kursis olema, sest kompilaator valib ise vastavalt vajadusele üldkasutavaid registreid ja instruktsioone, kuid see teadmine tuleb kasuks. Mikrokontrolleri instruktsioone on oluline tunda ajakriitilistes rakendustes, kus protseduurid peavad toimuma loetud protsessori taktide jooksul.
Nii nagu enamik digitaalelektroonikat, töötab ka AVR kindlal taktsagedusel. Kindel taktsagedus tagab andmevahetuse töökindluse kogu kiibi ulatuses. Taktsignaali ehk töötakti genereerimiseks on AVR-i puhul mitu võimalust.
Sisemine RC ostsillaator
See on kiibisisene taktigeneraator, mis ei vaja väliseid komponente. Puuduseks on suhteliselt madal sagedus ja ebatäpsus.
Väline RC ostsillaator
Sama põhimõttega, nagu sisemine RC ostsillaator ja ei oma sisulist eelist eelmise ees.
Kvartsostsillaator
Kvartsostsillaatoris kasutatakse elektriväljas oma resonantssagedusel võnkuvat kristalli ja selle piesoelektrilist omadust mehhaanilisel deformatsioonil (võnkumisel) elektriväli tekitada. Kvartsostsillaatorit võimaldavad ligi 0,001% täpsust taktsagedust ja seda olenemata temperatuurist.
Keraamiline resonaator
Tegu on kvartsostsillaatorile sarnaneva lahendusega, kus kasutatakse odavamat piesoelektrilist materjali. Resonaatorid on reeglina ka väiksemad kui kvartsostsillaatorid, kuid paraku on nad ka ebatäpsemad (~0,5%) ja temperatuuritundlikumad.
Väline taktsignaal
Välist taktsignaali võib tekitada ükskõik mis seade, peaasi et taktsagedus ja amplituut (pinge) oleks lubatud piirides. Näiteks võib skeemis kasutada eraldi taktigeneraatorit, mis takteerib mitut mikrokontrollerit.
Katkestuse (inglise keeles interrupt) saavad AVR-il tekitada loendurid, andmesideliidesed, analoog-digitaalmuundur, komparaator, spetsiaalsed sisend-väljundviigud ja mitmed muud funktsioonid, olenevalt kontrollerist. Igat katkestust saab lubada või keelata seda genereerivas üksuses. Olenemata katkestuse lubamisest või mitte, on iga katkestuse jaoks vastavas kontrolleriüksuses 1-bitine andmeväli (lipuke, inglise keeles interrupt flag), mis märgitakse katkestust põhjustava sündmuse toimumisel tõeseks. Kui toimub nimetatud andmevälja muutumine ja katkestus on lubatud, hakkab kontroller täitma koodi, mis oli katkestuse toimumisel ette nähtud.
AVR mikrokontrolleris on iga katkestus seotud kindla sündmusega. Igal sündmusel on olekuregistris lipubitt, mis tähistab sündmuse juhtumist. Lisaks on sündmustega seotud katkestuste maskeerimise registrid ja vastavad bitid. Kui sündmuse katkestuse bitt on maskeerimata ja tekib sündmus, jätab protsessor mõne(kümne) töötakti jooksul käimasoleva programmi täitmise pooleli ning alustab katkestuse programmi täitmist. Pärast katkestuse programmi täitmist jätkab protsessor poolelijäänud programmi täitmist.
Näide
Katkestuste kasutamiseks AVR LibC teegiga tuleb kasutusele võtta interrupt.h fail. Katkestusel täitmisele minev programmikood lisatakse pärast “ISR”-i nimelist võtmesõna. “ISR” järele sulgudesse kirjutatakse katkestuse nimi. C-keele koodinäide:
#include <avr/interrupt.h> ISR(XXX_vect) { // Tee midagi }
Globaalne, kõigi katkestuste toimumise lubamine, määratakse ära juht- ja olekuregistris SREG. Võimaluse kõiki katkestusi keelata või lubada tingib andmete kaitse vajadus. Kuna katkestused katkestavad käimasoleva programmi täitmise, võivad nad segada või rikkuda andmeid, mida põhiprogramm katkestamise hetkel kasutas. Sellist olukorda saab vältida kõikide katkestuste keelamisega enne tundlike andmetega tegelemist. Globaalne katkestuste keelamine on lihtne, kui seda saab teha ühe registri (SREG) muutmisega. Pärast kriitilise programmiosa lõppu saab katkestused uuesti lubada ja kõik katkestused, mille lipuke vahepeal ära märgiti, lähevad täitmisele.
Näide
Oletame, et programmis on kasutusel 16-bitine muutuja, mille väärtust muudab nii põhiprogramm kui ka katkestuse programmilõik, ja selle muutuja väärtus omistatakse hiljem teisele muutujale:
#include <avr/interrupt.h> // Globaalsed 16-bitised muutujad x ja y unsigned short x, y; // Suvaline katkestus, mis muudab x väärtuse ISR(XXX_vect) { x = 0x3333; } int main() { // Muutujale x väärtuse omistamine x = 0x1111; // Globaalne katkestuste lubamine sei(); // x väärtuse muutujasse y laadimine y = x; }
Programm on väga lihtne - algul omistatakse muutujale x väärtus 0x1111 ja hiljem selle väärtus omakorda muutujale y. Kui vahepeal tekib katkestus, saab x-i väärtuseks 0x3333. Loogikareeglite järgi saab muutujal y programmi lõpus olla kaks võimalikku väärtust, kuid 8-bitise AVR peal on ka kolmas võimalus. Nimelt, 8-bitise arhitektuuriga toimub 16-bitiste andmete liigutamine 2 takti jooksul ja vahepeal tekkiv katkestus võib andmete ühtsust rikkuda. Niisiis võib peale 0x1111 ja 0x3333 tekkida ka väärtus 0x3311. Et sellist asja ei juhtuks, tuleks katkestused enne operatsioone, mis toimuvad pikemalt kui 1 takti jooksul, ajutiselt keelata.
Toodud näites muutujale y muutuja x väärtuse omistamine ohutul meetodil:
// Globaalne katkestuste keelamine cli(); // Laadimine y = x; // Globaalne katkestuste uuesti lubamine sei();
Kõik AVR siinid on loetavad ja kirjutatavad, kui neid kasutada tavalises loogilises sisend-väljundrežiimis (inglise keeles input/output, ehk I/O). AVR siinid on nimetatud suurte ladina tähestiku algustähtedega A, B, C, jne. Mõnel AVR-il võib aga siin A puududa, kuigi siin B on olemas. Iga siin on 8-bitine ja iga biti jaoks on enamasti kontrolleri kestast välja toodud eraldi viik. Viikusid loendatakse arvudega alates nullist. Siini mõlema kasutussuuna jaoks on olemas kaks eraldi registrit. Lisaks on olemas iga siini kohta register siini reaalse toimimissuuna määramiseks, milles biti väärtus 1 näitab viigu kasutamist väljundina ja 0 sisendina. Kokku on iga siini kohta kolm registrit:
Näide
Vaja on siini B viigud 0-3 teha sisenditeks, viigud 4-7 väljunditeks, seada 5. viik kõrgeks ja lugeda 0-3 viigu väärtus muutujasse. C-keele programmi kood on järgnev:
#include <avr/io.h> int main() { unsigned char x; // Viigud 0-3 sisendiks, 4-7 väljundiks DDRB = 0xF0; // Viienda viigu kõrgeks seadmine PORTB |= (1 << PIN5); // 0-3 sisendviigu väärtuse lugemine x = PINB & 0x0F; }
Toodud näites on sisendeid kasutatud Hi-Z ehk kõrge impendatsiga (inglise keeles high impedance) režiimis. Põhimõtteliselt on tegemist sisendiga, mis ei koorma peaaegu üldse signaaliallikat. Seda režiimi võib vaja minna, kui viiku kasutatakse andmesiinina. Kui viik on kasutusel nupu, lüliti või muu maad ning sisendit kokku ühendavas lahenduses, siis tasub sisendis kasutada pull-up takistit. Selleks tuleb sisendrežiimis seada kõrgeks vastava viigu väljundbitt - tulemusena lülitub toitepinge ja sisendi vahele takisti, mis hoiab sisendi pingenivood kõrgel, kui miski seda just alla ei tõmba. Pull-up takisti eesmärk on ära hoida sisendi “ujumine” (inglise keeles floating) staatilise elektri ja muude häirete tõttu. Pärast kontrolleri käivitumist on kõik IO siinid vaikimisi kõrge impedantsiga sisendrežiimis.
Enamasti on IO siinil olevaid viike peale loogiliste ühenduste kasutatud ka muu perifeeria tarbeks. Kui on soov kasutada viigu alternatiivfunktsiooni, tuleks tutvuda AVR-i andmelehega, kus on öeldud, mis režiimis peab IO viik olema. Näiteks ADC kanali sisendina kasutamiseks peaks viik olema sisendrežiimis ja PWM signaali genereerimiseks väljundrežiimis. Mõned perifeeriamoodulid määravad aga ise IO viigu režiimi.
Välised katkestused (inglise keeles external interrupt) on ühed lihtsamad perifeeria funktsioonid. AVR-idel on tavaliselt 1 kuni 8 spetsiaalset viiku, mille loogilise väärtuse muutumisel või kindlal olekul tekitatakse programmis katkestus. Kuna enamasti kasutatakse seda funktsiooni kontrolleriväliste loogikasignaalide jälgimiseks, siis nimetataksegi vastavaid viike välise katkestuse viikudeks.
Välise katkestuse kasutamiseks tuleks viik seadistada tavalise IO sisendrežiimi (võib ka väljundrežiimis kasutada, aga siis saab katkestust tekitada vaid kontroller ise). Välise katkestuse seadistusregistrites tuleb ära märkida katkestuste tekitamise lubamine ja tingimus, mille peale seda teha. Võimalikke tekitajaid on neli:
Katkestuse tekitamiseks loogilise nulli valimisel tekitatakse katkestust järjest senikaua, kuni viigu väärtus on null. Põhiprogrammi töö on samal ajal peatatud.
Lähtudes tööpõhimõttelt, on väliseid katkestusi kahte liiki: kontrolleri taktiga sünkroniseeritud ja asünkroonsed. Sünkroniseeritud katkestused toimivad sisendite väärtuse meelespidamise teel, mis tähendab, et loogilised muutused leitakse kahel erineval taktil saadud väärtuste võrdlemise teel. Kui välise signaali loogilised muutused toimuvad kiiremini, kui käib töötakt, siis katkestused, kas ei teki õigesti või jäävad üldse vahele. Asünkroonsed katkestused ei sõltu kontrolleri taktist ja võimaldavad tuvastada ka kiiremini muutuvat välist signaali - loogilist nivood peab signaal hoidma vähemalt 50 ns. ATmega128-l on 4 sünkroniseeritud ja 4 asünkroonset välist katkestust.
Näide
Vaja on panna ATmega128 viik number 9 ehk siini E viik 7 tekitama katkestust, kui selle väärtus muutub. Sellele viigule vastab väline katkestus INT7, mis on sünkroonne.
#include <avr/interrupt.h> // Välise katkestuse programm ISR(INT7_vect) { // Tee midagi } int main() { // Siini E viigu 7 muutmine sisendiks biti 7 nullimise teel DDRE &= ~(1 << PIN7); // Siini E viigule 7 pull-up takisti määramine sisendi ujumise vastu PORTE |= (1 << PIN7); // Väliste katkestuste seaderegistris katkestuse 7 // tekitajaks loogilise muutuse määramine EICRB = (1 << ISC70); // Välise katkestuse 7 lubamine EIMSK |= (1 << INT7); // Globaalne katkestuste lubamine sei(); // Lõputu programmitsükkel while (1) continue; }
Lisaks üksikute viikude tekitatavatele katkestustele on suurematel AVR-idel võimalik kasutada ka tervete gruppide viikude loogiliste väärtuste muutuste katkestusi. Neid katkestusi nimetatakse lihtsalt viigu muutuse katkestusteks (inglise keeles pin change interrupt). Need rakenduvad siis, kui vähemalt ühe viigu väärtus grupis muutub.
Analoog-digitaalmuundur (inglise keeles analog to digital converter, lühend ADC) muundab analoogpinge väärtuse digitaalseks väärtuseks. AVR-i ADC analoogpinge sisend on lubatud 0-5,5 V piires. Digitaalne väärtus on 10-bitine, kuid selle täpsus on ±2 ühikut. Viga võib veelgi kasvada, kui kiibi toitepinget häirete eest ei kaitsta. ADC jaoks on AVR-il eraldi toite ja võrdluspinge viik. Eraldi toide on mürakindluse pärast ja see ei tohi kiibi toitepingest erineda rohkem kui 0,3 V. Võrdluspinge määrab maksimaalse digitaalse väärtuse. Ehk kui võrdluspinge on 3 V, siis sama pingega sisend annab väärtuseks 210 - 1 ehk 1023.
AVR ADC töötab võrdlusmeetodil (inglise keeles successive approximation). Lühidalt öeldes toimub mõõdetava pinge võrdlemine kindlate nivoopingetega ja tulemuste esitamine tõeväärtuste-, ehk bitijadana. See meetod on suhteliselt aeganõudev, sest iga biti leidmine lõppväärtuses toimub eraldi. AVR-il kulub töö ajal 13 takti ühe mõõtmise tegemiseks ja 25 takti kõige esimesel mõõtmisel (käivitusel). Need taktid pole aga kontrolleri töötaktid, vaid spetsiaalselt ADC üksuse jaoks sagedusjaguriga saadud taktid. Maksimaalse täpsuse saamiseks peaks ADC takt olema 50-200 kHz. Kõrgemal taktil kaob täpsus. Vahel on ka mõõtmiste suur arv olulisem kui täpsus ja siis on põhjendatud suurema sageduse kasutamine. Ühele mõõtmisele kuluvaks ajaks on AVR dokumentatsioonis antud 13-260 µs.
Mõõtetulemust saab kasutaja lugeda 8- ja 10-bitisena. Kuna AVR on 8-bitine, siis ADC mõõteväärtuste jaoks on sel kaks 8-bitist registrit. Seadistustes saab määrata, kas 10-bitisest väärtusest 2 esimest või 2 viimast bitti lähevad eraldi registrisse. Kui eraldatakse 2 noorimat ehk tulemust vähem iseloomustavat bitti, saab mõõtetulemuse 8-bitisena lugeda - sellist kombinatsiooni nimetatakse vasak-asetusega mõõtetulemuseks (left align). Teistpidist kombinatsiooni, kus kaht tulemusregistrit lugedes tekib 10-bitine arv, nimetatakse parem-asetusega mõõtetulemuseks (right align).
Mõõdetavaid analoogpinge sisendkanaleid on AVR-idel tavaliselt 8, ATtiny seerial üksikud, mõnel ATmega seeria kiibil 16, kuid muundureid on siiski üks. Erinevate sisendite kasutamiseks on kiibis multiplekser. Multiplekseri sisend on spetsiaalse registriga määratav. ADC üksusel on veel mõned omadused: muundamine protsessori magamisrežiimis müra vähendamiseks ja sisemise fikseeritud võrdluspinge (2,56 V, mõnel ka 1 V) kasutamise võimalus.
Näide
Vaja on mõõta ATmega128 ADC kanali 3 pinget vahemikus 0-5 V 8-bitise täpsusega.
#include <avr/io.h> int main() { unsigned char result; // Võrdluspingeks AREF viigu valimine // (eeldatavasti on see ühendatud +5V toiteahelasse) // Multiplekseriga kanali 3 valimine // Tulemus on vasak-asetusega ADMUX = (1 << REFS0) | (1 << ADLAR) | (3); // ADC üksuse käivitamine, // teisendustakti seadmine 16 korda aeglasemaks töötaktist ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADSC); // Mõõtmise lõpetamise ootamine while (ADCSRA & (1 << ADSC)) continue; // 8-bitise tulemuse lugemine result = ADCH; }
Loendurid (inglise keeles counter), teatud mõttes taimerid (inglise keeles timer), on mikrokontrollerite ühed oluliseimad lisafunktsioonid. Nende abil saab protsesse täpselt ajastada, signaale genereerida ja sündmusi loendada. Loenduri tööpõhimõte seisneb sisendtaktide arvu trigerite ahela abil binaarväärtuseks teisendamises. Ahela pikkusest oleneb maksimaalne loendatavate taktide arv, mida tähistatakse kahendkoodi pikkusega. AVR mikrokontrolleril on loendurid 8- ja 16-bitised. Kui loendur omab maksimaalset väärtust (8-bitiste puhul 255, 16-bitiste puhul 65535), tekib järgmise taktiga ületäitumine (inglise keeles overflow) ja loendur alustab uuesti nullist. Loenduri taktsignaal saab tulla mikrokontrolleri töötaktist ja sel juhul on võimalik selle sagedust sagedusjaguriga (inglise keeles prescaler) ka vähendada. Mõnel AVR-il on sisemine eraldiseisev taktsignaali generaator, mille sagedust saab sageduskordistiga tõsta. Loendurid erinevad ka rakendusvõimaluste ja töörežiimide poolest.
Normaalrežiimis ei täida loendur muud funktsiooni kui pidevat järestikulist arvude loendamist. Loenduri väärtust saab igal hetkel programmis muidugi ka lugeda ja muuta. Ainuke lisavõimalus normaalrežiimis on katkestuse tekitamine loenduri ületäitumisel. Normaalrežiimi kasutatakse tavaliselt mingi programmilõigu täitmiseks kindlate ajaintervallide järel.
Näide
Vaja on 8 MHz taktsagedusel töötav ATmega128 10 ms (sagedus 100 Hz) ajavahemiku järel katkestust tekitama panna. Ülesandeks sobib 8-bitine loendur 0.
#include <avr/interrupt.h> ISR(TIMER0_OVF_vect) { // Loendurile sellise väärtuse omistamine, // et järgmine ületäitumine tekiks 10 ms pärast. // Valem: 256 - 8 MHz / 1024 / 100 Hz = 177,785 = ~178 TCNT0 = 178; } int main() { // Et esimene ületäitumise katkestus tekiks 10 ms pärast, // tuleb ka siinkohal loendur algväärtustada. TCNT0 = 178; // Sagedusjaguri teguriks 1024 TCCR0 = 0x07; // Loenduri täitumise katkestuse lubamine TIMSK |= (1 << TOIE0); // Globaalne katkestuste lubamine sei(); // Lõputu programmitsükkel while (1) continue; }
Näites toodud loendurile omistatava väärtusega siiski täpselt 10 ms järel katkestust ei tekitata, sest vaja oleks loendurile omistada komakohaga väärtus, kuid see pole võimalik. Et täpset katkestuse intervalli saada, tuleb nii sagedusjaguri tegur kui ka loendurile täitumisel omistatav väärtus valida nii, et taktsagedus jaguks täpselt. Paraku pole see alati võimalik, ja eriti just 8-bitise loenduri puhul, sest selle väärtuste skaala on üsna väike. Täpsema ja suurema intervalli tekitamiseks saab kasutada 16-bitist loendurit.
Loenduri taktsignaalina saab kasutada ka mikrokontrollerivälist signaali (inglise keeles external clock source). Selleks on AVR mikrokontrolleril Tn viik, kus n tähistab loenduri numbrit. Välist taktsignaali ja polaarsust saab valida sagedusjaguri registriga.
Kuna loendurid võimaldavad mõõta aega, on keerukamatel AVR mikrokontrolleritel võimalus riistvaraliselt mõõta ka aega, mil toimus mingi sündmus. Seda loenduri osa nimetatakse sündmuse püüdjaks (inglise keeles input capture unit). AVR-is on valida kahe sündmuse vahel: spetsiaalse sisendviigu või analoogkomparaatori võrdlustulemuse loogilise väärtuse muutus. Kui toimub valitud sündmus, kirjutatakse loenduri väärtus spetsiaalsesse registrisse, kust selle võib soovitud ajal välja lugeda. Kui sündmuse toimumise aeg on pikem kui loenduri ületäitumise aeg, tuleb tarkvaraliselt lugeda ka loenduri ületäitumisi (näiteks ületäitumise katkestusega) ja need lõpptulemusse arvestada.
Näide
Vaja on 8 MHz taktsagedusel töötava ATmega128-ga mõõta välise 122 Hz - 100 kHz loogilise nelinurksignaali sagedust 1 Hz täpsusega. Programm on tehtud 16-bitise loendur 1 sündmuste püüdjaga.
#include <avr/interrupt.h> unsigned long frequency; // Sündmuse toimumise katkestus ISR(TIMER1_CAPT_vect) { // Loenduri nullimine TCNT1 = 0; // Tulemus on ainult siis arvestatav, kui // loendur pole vahepeal üle täitunud if (!(TIFR & (1 << TOV1))) { // Sageduse arvutamine perioodi pöördväärtusest. frequency = (unsigned long)8000000 / (unsigned long)ICR1; } else { // Sagedus on vähem kui 122 Hz frequency = 0; // Loenduri ületäitumise lipukese nullimine TIFR &= ~(1 << TOV1); } } int main() { // Tõusva frondi registreerimine, sagedusjaguri tegur 1 TCCR1B = (1 << ICES1) | (1 << CS10); // Sündmuse toimumise katkestuse lubamine TIMSK = (1 << TICIE1); // Globaalne katkestuste lubamine sei(); // Lõputu programmitsükkel while (1) continue; }
Programmis tekib välise signaali tõusva frondi ajal sündmuse katkestus. Katkestuse jooksul kontrollitakse, ega loenduri ületäitumine pole toimunud - see saab juhtuda, kui signaali sagedus on alla 122 Hz (8 MHz / 216), ja sel juhul ei kajasta loenduri väärtus reaalset perioodi. Sagedus arvutatakse 32-bitiste arvudega pöördväärtusena perioodist. Esimese asjana aga nullitakse loendur, sest taimer töötab samal taktil mis protsessor ja iga instruktsiooni täitmine, mis toimub pärast välist sündmust, lühendab mõõdetavat perioodi ning sellest tulenevalt rikub ka mõõtetulemust. Maksimaalsele mõõdetavale sagedusele seab piiri katkestuse programmiosa tööaeg.
Sündmuste püüdmist ning nende aja registreerimist saab teha ka tarkvaraliselt. Saab kasutada väliseid või muid katkestusi ja nende tekkimise ajal lugeda loenduri väärtus. Riistvaraline sündmuste püüdmine on siiski mõeldud eeskätt programmist sõltumatuks töötamiseks ja suhteliselt lühiajaliste (või tihedate) sündmuste mõõtmiseks.
Keerukamate loenduritega saab peale signaali pikkuse mõõtmise ka signaali tekitada. Selleks on loenduril väärtuse võrdlemise üksus (inglise keeles output compare unit) ja võrdlustulemuse väljastusüksus (inglise keeles compare match output unit). Võrdlusüksusesse kuuluvad registrid sama bitilaiusega kui loendur ise ja nende registrite väärtusi võrreldakse loenduri väärtusega selle töö ajal. Hetkel, mil loenduri väärtus saab võrdseks võrdlusüksuse registri väärtusega, saab tekitada katkestuse ja spetsiaalsete väljundviikude oleku muutuse. Valida on võrdusmomendil viigu kõrgeks muutumise, madalaks muutumise ja ümbermuutumise vahel. Väljundviigu oleku muutused tekitavadki signaali.
Mõnedel signaali genereerimise režiimidel on määratav ka loenduri suurim väärtus - loenduri füüsiline suurus jääb küll samaks, kuid mängus on võrdlusregister, mille väärtust ületades loendur nullitakse. Seda võimalust kasutades saab eespool toodud ülesandeid täpse ajalise katkestuse tekitamise kohta lahendada, kuid mõeldud on see pigem signaali perioodi muutmiseks. Lisaks sellele on võimalik loendurit seadistada režiimi, kus see toimib nii juurde- kui mahalugemisel.
Loendurid ja nende abil genereeritavate signaalide režiimid on ühed keerulisemad perifeeriamoodulid AVR-il. Kõigist neist kirjutamine läheks pikaks ja enamasti pole nende kasutamisel kõike detailselt teada. Seetõttu on järgnevalt kirjeldatud vaid üht levinuimat PWM signaali robootikas. Ülejäänut saab juba AVR dokumentatsioonist järgi uurida.
Pulsilaius-modulatsioon (inglise keeles pulse width modulation, lühend PWM) on signaali tüüp, mille sagedus ja ühtlasi ka perioodid on konstantne (enamasti), kuid mõlema poolperioodi pikkus on muutuv. PWM signaale kasutatakse elektromehaaniliste, optiliste jms. seadmete juhtimiseks. Näiteks mudelismist tuntud servomootorite PWM signaal on 50 Hz sagedusega ja 1 ms kuni 2 ms pikkuse kõrge poolperioodiga.
Näide
Vaja on 8 MHz taktsagedusel töötava ATmega128-ga genereerida kaks kiirusreguleeritavat servomootori signaali. Viiguga PB5 (OC1A) tuleb genereerida pulsipikkus 1 ms ja viiguga PB6 (OC1B) pulsipikkus 2 ms.
#include <avr/io.h> int main() { // Viigud väljundiks DDRB |= (1 << PIN5) | (1 << PIN6); // Väljundid A ja B võrdusmomendil madalaks, // "Fast PWM" režiim, sagedusjagur 8 TCCR1A = (1 << COM1A1) | (1 << COM1B1) | (1 << WGM11); TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS11); // Suurim loenduri väärtus. Valem: // TOP = 8 MHz / 8 / 50 Hz ICR1 = 20000; // Esimese mootori poolperiood 1 ms, teisel 2 ms OCR1A = 1000; OCR1B = 2000; // Lõputu programmitsükkel while (1) continue; }
USART on universaalne sünkroonne jadaliides, UART aga selle lihtsustatud variant - universaalne asünkroonne jadaliides. Vahe seisneb selles, et USART kasutab peale andmeliinide ka taktsignaali liini, millega andmeid sünkroniseeritakse, UART aga mitte. AVR-i USART võimaldab täisduplekssidet, 5- kuni 9-bitiseid andmesõnu (8 biti puhul sõna = bait), 1 või 2 stoppbitti, kolme paarsuse režiimi ja laia boodikiiruste valikut. AVR mikrokontrolleritel on üldiselt kuni 2 USART liidest, kuid mõnel puudub USART üldse. Andmete edastamine toimub sõna kaupa, ehk AVR teeb riistvara tasandil kasutaja edastatud sõna bittideks ja edastab selle iseseisvalt ning vastupidi. Kasutaja juhib USART tööd seade-, oleku- ja andmeregistreid kirjutades ning lugedes.
Kõikide seadistuste jaoks on olemas vastavad registrid, mida on üsna lihtne andmelehe abil seadistada. Natuke keerulisem on boodikiiruse seadmine. Taktsignaal andmete edastamiseks genereeritakse töötaktist ja kasutaja saab valida teguri 1-st 4096-ni, millega töötakt läbi jagatakse. Täiendavalt jagatakse saadud taktisignaali olenevalt režiimist veel 2, 8 või 16-ga. Probleem on selles, et kõiki taktsagedusi ei saa jagada nii, et tekiks standardne boodikiirus. Mõnede mikrokontrolleri taktsageduste puhul on boodikiiruse erinevus soovitust ligikaudu 10%. AVR andmelehtedes on toodud tabelid tüüpilistest taktsagedustest, boodikiirustest ja nende saamiseks vajalikust jagamistegurist ning tekkida võivast veast.
Kuna andmete edastus toimub protsessorist sõltumata ja oluliselt aeglasemalt, tuleb enne saatmist veenduda, et liides on valmis uut sõna edastama. Selleks tuleb jälgida saatepuhvri valmisoleku olekubitti, mis näitab, kas sinna võib saatmiseks uue sõna kirjutada või mitte. Kui mikrokontroller käivitada, on see luba vaikimisi kohe olemas. Niipea kui sõna on saadetud ja puhvrisse pole uut sõna saatmiseks kirjutatud, muudetakse saatmise õnnestumise olekubitt kõrgeks.
Sõna saabumist tähistab samuti spetsiaalne olekubitt. Lisaks on olekubitid vastuvõtmisel tekkiva kaadri vea, paarsuse vea ja vastuvõtja puhvri ületäitumise tähistamiseks. Puhvri ületäitumine tekib näiteks siis, kui eelmist saabunud sõna pole vastuvõtu puhvrist välja loetud - seepärast ongi oluline saabuvad sõnad kiiresti programmi lugeda, kasutades selleks näiteks katkestust. Kokku on kolm võimalikku katkestuse põhjust: saatepuhvri valmisolek, saatmise õnnestumine ja vastuvõtmise õnnestumine.
Muide, saatepuhver ja vastuvõtupuhver on füüsiliselt küll erinevad registrid, kuid jagavad sama mäluaadressi ja neil on ühine nimi. Ühine andmeregister toimib nii, et sellesse kirjutades jõuab sõna saatepuhvrisse ja sellest lugedes tuleb see vastuvõtupuhvrist. Veel ühe täpsustusena tuleks arvestada, et 9-bitiste andmesõnade puhul edastatakse ja loetakse üheksandat bitti hoopis ühe seaderegistri kaudu.
Näide
Seadistada 8 MHz taktsagedusel töötav ATmega128 USART0 liides boodikiirusel 9600 bps asünkroonselt edastama 8-bitiseid sõnu 1 stop-bitiga ja ilma paarsuse bitita. Saata märk “X”.
#include <avr/io.h> int main() { // Boodi kiiruseks 9600 bps seadmine. Valem: // Jagamistegur = taktsagedus / 16 / boodi kiirus - 1 // UBRR = 8000000 / 16 / 9600 - 1 = ~51 UBRR0H = 0; UBRR0L = 51; // Saatja lubamine UCSR0B = (1 << TXEN0); // Asünkroonse režiimi seadistamine, andmesõna pikkuseks 8 bitti // 1 stop-bitt, keelatud paarsuse bitt. UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); // Ootame, kuni andmepuhver on tühi ehk eelmine sõna on saadetud // Selles näites ei oma see küll mõtet, sest saadetakse alles // esimest märki, küll tasub seda teha rohkemate märkide korral. while (!(UCSR0A & (1 << UDRE))) continue; // Märgi kirjutamine puhvrisse, kust see ka teele saadetakse UDR0 = 'X'; // Lõputu tsükkel while (1) continue; }
Mehhatroonika ja Robootika Kodulabor on ATmega128 mikrokontrolleril põhinev omavahel seotud moodulite komplekt, mis on komplekteeritud kaasaskantavasse kohvrisse. Kodulaboriga saab teha erinevaid mehhatroonika- ja robootikaalaseid eksperimente ning harjutusi alates lihtsast tule vilgutamisest kuni keeruka seadme ehitamiseni. Kodulabor on mõeldud eelkõige koolidele, sisaldades endas lisaks riistvarale ka metoodilist materjali ja harjutusülesandeid koos näidete ja lahendustega. Kodulabor on integreeritud oma veebikeskkonnaga, mis on suunatud õpilasele ja õpetajale ning võimaldab kasutajate omavahelist suhtlust. Lühidalt öeldes on Kodulabor mobiilne töövahendite komplekt, mida kasutatakse õppe ja harjutamise eesmärgil kodus, koolis või töökohal.
Kodulabor on välja arendatud Tallinna Tehnikaülikooli ja Eesti ettevõtte poolt koostöös Euroopa partnerülikoolidega Leonardo da Vinci programmi toel. Kodulabori moodulid on komplekteeritud erinevatesse komplektidesse. Lihtsaim komplekt, millega saab teha esmaseid digitaalsete sisendite-väljundite eksperimente, on Kodulabori baaskomplekt. Andurite ja mootoritega eksperimenteerimiseks on vaja Andurite ja Mootorite lisakomplekti. Täiskomplekt sisaldab endas nii Kodulabori baaskomplekti, Andurite ja Mootorite lisakomplekti kui ka lisamooduleid.
Tänapäevane inseneriõpe ei saa enam põhineda ühel konkreetsel õppeviisil, ammugi mitte enam klassikalisel ülikooli loeng-harjutus-tüüpi standardlahendusel. Tänapäeva õppija ei rahuldu enam rangelt ajastatud laboritundidega. Enamik noori (ja ka vanemaid õppijaid) elavad infoühiskonna täisväärtuslikku elu ja viidavad suure osa oma ajast internetis, mis tähendab, et klassikaliste meetoditega õppimisele jääb järjest vähem aega. Selle tõttu tuleb inseneriõpe tuua samuti üle infoühiskonda ja teha see atraktiivseks, kaotamata samal ajal kvaliteedis ja praktilise töö osakaalus.
Mehhatroonika ja robootika integreeritud õppe kontseptsioon sisaldab endas nii standardseid õppeabimaterjale kui ka uudseid lähenemisi, mis on metoodiliselt seotud ühtseks tervikuks.
Alljärgnev näide võib olla abiks koolile robootika õppesüsteemi käivitamiseks kui ka ideedeks rakendada erinevaid õppevõimalusi tehnikavaldkonna praktilises õppes.
Õppe kontseptsioon sisaldab endas järgnevaid õppeabimaterjale:
Teoreetilised abimaterjalid koosnevad traditsioonilisest õpik-käsiraamatust ja harjutusülesannete kogust.
Praktiline osa koosneb Kodulaborist ja üle interneti robotite programmeerimise keskkonnast - Kauglaborist. Kodulaborid moodustavad Kauglaboriga ühtse terviku, mis tähendab, et õppija saab kodus harjutada üksikuid funktsioone, näiteks, kuidas juhtida erinevaid mootoreid või kasutada andureid ja samal ajal on võimalus üle interneti oma värskeid oskusi rakendada süsteemi juhtimiseks. Süsteemiks on reaalne seadmestik (näiteks mobiilne robot), mida saab programmeerida ja juhtida Kauglabori vahendusel. Robot on ehitatud samadest komponentidest, mis sisalduvad Kodulaboris, võimaldades nii omandatud oskusi kohe ka terviksüsteemi peal proovida. Roboti liikumisest ja tegemisest saab tagasisidet videokaamerate abil.
Kodulabori veebikeskkond
http://home.roboticlab.eu
Kauglabori veebikeskkond
http://distance.roboticlab.eu
Õppeprotsessi ühe teema/laboritöö raames kirjeldab järgnev skeem.
Teema algab sissejuhatava loenguga, mis võib toimuda klassikalise kontakttunnina, kaugloenguna (juhul kui õpetaja on eemal) või videoloenguna. Videoloeng on oluline isegi sel juhul, kui toimub tavaloeng, võimaldades nii ka puudunud õpilastel loengumaterjalist osa saada või osalenud õpilastel soovi korral loeng üle vaadata. Teemat tutvustav loeng sisaldab endas praktilise näite koos läbitegemist ja õppetajapoolset protsessi kommenteerimist. Teoreetilist osa toetab õpik ja harjutuste kogu teoreetiline osa.
Teema tutvustusele järgneb iseseisev praktiline töö. Praktiline töö koosneb näitelahenduse katsetamisest, selle muutmisest vastavalt “Soojendusülesandele” ja iseseisvast harjutusülesandest, mille määrab õpetaja praktiliste tööde “Harjutusülesannete” osast. Praktiline töö teostatakse Kodulaboriga või mõne muu robootika komplektiga, mida toetab teoreetiline ja praktiline juhend, Kauglabor ja veebikeskkond. Olulisel kohal on siinjuures õpetajate ja õpilaste tugikeskkond ja võrgustik, mis peaks iseseisvale tööle igakülgset abi pakkuma. Foorumis saab küsida abi nii juhendajalt kui ka kaasõpilastelt.
Praktilise harjutuse tulemused vormistatakse aruandeks ja saadetakse õpetajale või, kui kasutusel on e-õppe süsteem, laetakse koos töötavate masinkoodis lahendustega vastavasse süsteemi. Aruanne sisaldab tüüpiliselt töö kirjeldust ja lahenduse lähtekoodi, mis peab olema selgelt ja arusaadavalt kommenteeritud.
Ei ole mingi uudis, et infotehnoloogia tungimine igapäevaellu on muutnud paljude, kui mitte enamuse noorte õppimise stiili ja kommunikatsioonikanaleid. Tõenäoliselt saab õppija juba praegu olulise osa õpitava aine informatsioonist erinevate infotehnoloogia kommunikatsioonikanalite kaudu. Enne mingi probleemi lahendamist tehakse tihti kiire otsing internetist, leidmaks taustainformatsiooni või näitelahendusi. Kuna noorte igapäevasuhtlus ja tegevus on igati põimunud internetiga ja seal olevate erinevate võrgustikega, on igati loomulik, et koolitaja poolt pakutav õpetamismetoodika peab järgima üldisi trende ja leidma tee õppijani läbi tema poolt harjumuspärase suhtluskanali - interneti. Loomulikult ei välista interneti kasutamine traditsioonilisi õpetamise vorme, kuid ainuüksi nendest enam ei piisa.
Robootika ja mehhatroonika on tulevikku suunatud alad, mille õpetamisel tuleb samuti järgida tänapäeva trende ja uusi tehnoloogiaid. Samal ajal aga on see valdkond väga praktiline ja nõuab oskuste ning teadmiste omandamiseks praktilist katsetamist ja harjutamist. Kuigi on olemas ka virtuaalseid ülesandeid, ei asenda see praktilisi oma käega tehtud tegevusi. Järgnevalt püüame pakkuda ühe võimaliku praktilise juhendi, kuidas viia läbi ühte robootika ainet, kus on kasutusel erinevaid õpetamise vorme integreeriv lähenemine. Metoodika eeldab, et õpetajal on võimalus kasutada modulaarset praktilist robootika õppekomplekti - antud juhul Kodulaborit.
Mida pidada silmas õppeaine alustamisel….
Optimaalse õpilaste arvu laborikomplektiga tegutsemiseks määrab suuresti ära juba arvutikasutamise võimalus. See tähendab, et ühe arvuti taha mahub enamasti kuni 3 inimest nii, et veel kõik saavad toimuvast aktiivselt osa võtta. Suurema arvu juures ei näe osa õpilasi enam kirjutatavat koodi ja neil hakkab igav ning tunnitööga enam ei tegeleta.
Praktiline töö on jagatud laboritöödeks, kus iga labori juures tuleb lahendada ülesanne programmiliselt ning tulemus vormistada aruandena. See võimaldab tööd õpilaste vahel jagada. Näiteks üks vastutab programmikoodi eest, teine aruande kirjutamise eest, kolmas riistvara ühendamise eest. Aruandes endas võib nõuda näiteks lisaks programmikoodile ka lahenduse kirjeldust tekstina, kasutatava algoritmi lahtiseletavat diagrammi, vastuseid käsitletud teema kohta käivatele küsimustele ja õpilaste nägemust labori plussidest ja miinustest. Viimane on hea võimalus uurida õpilastelt tagasisidet sellest, kas ülesanne oli liiga keeruline või lihtne, kui praktiline või huvitav ülesanne tundus, mida õpiti juurde jms.
Kindlasti tasub laborikomplekti käsitlev esimene programmeerimisülesanne koos läbi teha. Samaaegselt õpetajaga, kes selgitab toimingute tausta ja lahendab ülesannet ekraanil, teevad õpilased demonstreeritud ülesannet koos kaasa. Kogu protsess võiks olla kirja pandud etapiliselt, et mahajääjad või puudujad saavad juhendi järgi võimalusel ka ise tegutseda. Labori läbiviimise üks võimalik variant on järgnevalt toodud välja etappidena, mis võivad omakorda varieeruda vastavalt situatsioonile.
Ülesannete lahendamisel võib alati tekkida grupp (grupid), kes on teistest aeglasem või alustasid hiljem. Sellisel juhul on tavaliselt probleemiks õpetaja tähelepanu koondumine mahajäänud grupi abistamisele ning teised peavad ootama ja igavlema, kuni mahajääja grupp on järele jõudnud. Analoogselt tekib probleem, kui klassis on üks grupp, kes jõuab töödega valmis teistest kiiremini. Mõlema probleemi lahendamiseks on võimalus kasutada kirjapandud ülesandeid või laborijuhendeid. Kuna kogu töö protsess ja nõutud osad on kirja pandud, siis saavad grupid töötada iseseisvalt ning õpetajal on võimalus abistada neid, kellel tekib probleeme edasijõudmisega. Lisaks on erineva raskusastmega ülesandeid, mida saab jagada vastavalt grupi võimekusele või boonusülesandena nendele, kes on normülesanded juba ära jõudnud lahendada.
Kui õpetaja peab oluliseks, et kõik oskaksid programmeerida ning saaksid programmikoodist aru, siis võib õpetaja nõuda, et õpilased vahetaksid teatud osaülesande järel kohad, nii et igaüks saaks proovida programmeerimist. Teine võimalus on ülesande hindamisel küsida programmikoodi lahenduse kohta selgitust ükskõik milliselt grupi liikmelt ning viimase vastus määrab kogu grupiliikmete hinde. See sunnib gruppi töötama ühtsena ning hoolitsema, et kõik grupi liikmed saaksid aru, kuidas lahenduse üksikasjad töötavad. Kui selline lähenemine tundub ebaõiglasena, võib iseseisva töö kaitsmise organiseerida nii, et grupp peab lahendama õpilaste arvuga võrdse arvu töid. Iga õpilane peab kaitsma ühe töö. Millise, selgub alles kaitsmise käigus.
Tihtipeale võivad programmi koodi kompileerimisel või riistvara valesti käsitlemisel tekkida mingid tüüpvead. Nende sümptomid tasub kindlasti kirja panna koos lahendusega, kuna sama viga, millele lahenduse leidmine võttis tunde, võidakse õpilaste poolt korrata. Tüüpprobleemide lahendused saab koondada Kodulabori tugikeskkonna foorumisse.
Üks võimalus motivatsiooni tõstmiseks ja kogu õppeprotsessi huvitavamaks muutmiseks on tekitada võistlusmoment, kus õpilastel tuleb mingile probleemile leida lahendus, mida kursuse lõpus ühiselt testitakse. Lahenduse headus peab olema mõõdetav (aeg, kaugus vms.). Võib tekitada ka erinevaid hindamiskriteeriume: nn. väljanägemine, optimaalne lahendus, huvitavaim tehniline lahendus jms. Ülesannet annab kindlasti siduda ka reaalse elu probleemidega (nt patareide sorteerija). Samas on võimalus kasutada ka mobiilseid platvorme, et lahendada hobirobootika tüüpülesandeid nagu joonejälgimine, labürindi läbimine jms.
Järgnevalt on toodud näiteks tüüpiline laboritöö kirjeldus, mida võib kasutada praktilise töö lähteülesandena.
Laboratoorne töö Nr 3. Andurid ja analoog-digitaalmuundur
Juhendaja: Raivo Sell
Töö eesmärk
Tutvuda analoog-digitaalmuunduri tööpõhimõtte ja analoogsignaalide muundamisega, kasutades AVR ATmega128 8-bitist mikrokontrollerit. Lisaks tutvuda erinevate analoogväljundiga anduritega. Teha läbi lihtne harjutus analooganduri kasutamisest.
Tööks vajalikud vahendid
Kodulabori baasversioon, Andurite ja Mootorite lisakomplekt, AVR tarkvara.
Töö käik
Aruanne
Tehtud töö kohta tuleb esitada elektrooniline aruanne, mis sisaldab:
Aruanne peab sisaldama nime, labori numbrit, teostamise kuupäeva, kaasosaliste nimesid (kui olid). Aruanne peab olema lühike, kuid sisutihe. Hinnatakse kvaliteeti, mitte kvantiteeti! Olge valmis lahenduse demonstreerimiseks juhendajale ja Teie poolt loodud programmikoodi kommenteerimiseks. Aruanded laadida üles e-õppe keskkonda vastava ülesande juurde. Labori aruande esitamise tähtaeg on 1 nädal pärast töö tegemist.
Kirjandus
Robootika Kodulabori moodulid on jagatud erinevatesse komplektidesse, võimaldades valida sobivaima, sõltuvalt õpilase või kooli eesmärkidest. Lihtsaim komplekt on Kodulabori baaskomplekt, mis sisaldab endas kõike vajalikku mikrokontrolleri kasutamiseks ja lisaks Digitaal-sisend/väljundite plaati koos LCD ekraaniga. Baaskomplektiga saab kasutada Mootorite ja Andurite lisakomplekti, mis sisaldab erinevat tüüpi mootoreid, andureid ja nende tarvikuid. Lisakomplekt töötab koos Kodulabori baaskomplektiga. Iseseisvalt lisakomplekti kasutada ei saa, sest see ei sisalda mikrokontrollerit. Kodulabori täiskomplekt sisaldab endas Kodulabori baaskomplekti ja Andurite ja Mootorite lisakomplekti täies mahus ning lisaks veel kolme moodulit, milleks on Kommunikatsioonimoodul, RFID moodul ja Masinnägemise moodul. Täiskomplekt sobib rohkem õpetajale. Õpilastele ja kaasaskandmiseks on olulisel mugavam ja mõistlikum kasutada Kodulabori baaskomplekti üksi või koos Andurite ja Mootorite lisakomplektiga.
Mootorite moodul
Andurite moodul
Kodulabori täiskomplekt sisaldab kõiki komponente Kodulabori baaskomplektist ja Andurite ja Mootorite lisakomplektist ning lisaks järgmisi mooduleid:
RFID moodul
Kommunikatsiooni moodul
Masinnägemise moodul
Kodulabori baaskomplekti ja täiskomplekti saab edukalt kasutada lisaks eksperimentidele ka robotiehitamise baasplatvormina või muu mehhatroonikasüsteemi keskse juhtsüsteemina. Kodulabori versioonid on pidevas arengus ja aeg-ajalt tasub kontrollida, kas on ilmunud lisamooduleid või uuendusi. Samuti tasub kontrollida moodulite versiooni numbreid, kuna mõningad harjutused ja näited võivad olla koostatud uuematele versioonidele.
Kodulabori keskseks mooduliks (kontrollermooduliks) on arendusplaadile paigaldatud mikrokontroller ATmega128. Lisaks mikrokontrollerile on plaadil veel mitmesuguseid perifeeriaseadmeid, pingealaldi ja ühenduspistikud. Kontrollermooduli plaat sisaldab endas järgmisi komponente:
Kontrollermooduli plaat on varustatud alaldiga ja pingestabilisaatoriga. Sisendpingeks sobib plaadile 6-15 V. Voolukadude minimeerimiseks on soovitatav kasutada 6-9 V pingeallikat. Toite ühendamisel peab plaadil toite LED põlema hakkama. Kui see ei sütti, võib põhjus olla puudulikus toites, ühendamata jäänud toitesillas (toitepesa kõrval) või hoopis lühises Kontrollermooduli plaadil või temaga ühendatud seadmes. Mikrokontrollerit saab programmeerida nii ISP kui JTAG liidese kaudu. Kodulabori komplektiga kaasasolev JTAG-ICE programmaator toetab lisaks lihtsale programmi pealelaadimisele ka programmikoodi silumist. JTAG-ICE programmaatorit võib kasutada ka ISP režiimis. Programmeerimise viigud on ühendatud läbi multiplekseri, mis võimaldab kontrolleril töö ajal vastavaid viike kasutada ka teiste funktsioonide jaoks.
Kontrollermooduli plaat on varustatud oleku-LED-iga, mis on ühendatud mikrokontrolleri viiguga PB7. LED süttib, kui viik seada madalasse olekusse (loogiline 0). Seda on hea kasutada lihtsa indikaatorina. ATmega128 mikrokontroller on varustatud kahe jadaliidesega, mille signaalid on MAX232 muunduriga teisendatud RS-232 nivoole. Ühe jadaliidese (UART1) jaoks on standardne RS-232 DB-9 pistik, teise jaoks piikriba.
Plaadile on paigaldatud lisamälu - 4 Mb Atmel AT45DB041B välkmälu. Mälu on ühendatud SPI liidese kaudu mikrokontrolleriga ja seda võib kasutada andmete salvestamiseks, juhul kui need peavad säilima ka pärast toite eemaldamist mikrokontrollerilt.
Nr | Viik | Alternatiivfunktsioon / kirjeldus | |
---|---|---|---|
1 | VCC | - | +5 V |
2 | GND | - | Maa |
3 | REF | AREF | ADC võrdluspinge sisend |
4 | GND | - | Maa |
5 | PF0 | ADC0 | ADC sisendkanal 0 |
6 | GND | - | Maa |
7 | PF1 | ADC1 | ADC sisendkanal 1 |
8 | GND | - | Maa |
9 | PF2 | ADC2 | ADC sisendkanal 2 |
10 | GND | - | Maa |
11 | PF3 | ADC3 | ADC sisendkanal 3 |
12 | GND | - | Maa |
13 | PF4 | ADC4/TCK | ADC sisendkanal 4 või JTAG taktsignaal |
14 | GND | - | Maa |
15 | PF5 | ADC5/TMS | ADC sisendkanal 5 või JTAG režiimivalik |
16 | GND | - | Maa |
17 | PF6 | ADC6/TDO | ADC sisendkanal 6 või JTAG andmete väljund |
18 | GND | - | Maa |
19 | PF7 | ADC7/TDI | ADC sisendkanal 7 või JTAG andmete sisend |
20 | GND | - | Maa |
Nr | Viik | Alternatiivfunktsioon / kirjeldus | |
---|---|---|---|
1 | PD7 | T2 | Taimer/Loendur2 taktsignaali sisend |
2 | PD6 | T1 | Taimer/Loendur1 taktsignaali sisend |
3 | PD5 | XCK1 | USART1 taktsignaali sisend/väljund |
4 | PD4 | IC1 | Taimer/Loendur1 sündmuste püüdja sisend |
5 | PD3 | INT3/TXD1 | Väline katkestus 3 või UART1 andmete väljund |
6 | PD2 | INT2/RXD1 | Väline katkestus 2 või UART1 andmete sisend |
7 | PD1 | INT1/SDA | Väline katkestus 1 või TWI andmesignaal |
8 | PD0 | INT0/SCL | Väline katkestus 0 või TWI taktsignaal |
9 | VCC | - | +5 V |
10 | GND | - | Maa |
11 | PB7 | OC2/OC1C | Taimer/Loendur2 või Taimer/Loendur1 võrdlustulemuse väljastusüksus (C) |
12 | PB6 | OC1B | Taimer/Loendur1 võrdlustulemuse väljastusüksus B |
13 | PB5 | OC1A | Taimer/Loendur1 võrdlustulemuse väljastusüksus A |
14 | PB4 | OC0 | Taimer/Loendur0 võrdlustulemuse väljastusüksus |
15 | PB3 | MISO | SPI master andmete sisend / SPI slave väljund |
16 | PB2 | MOSI | SPI master andmete väljund / SPI slave sisend |
17 | PB1 | SCK | SPI taktsignaal |
18 | PB0 | SS | SPI slave valik |
19 | PE7 | INT7/IC3 | Väline katkestus 7 või Taimer/Loendur3 sündmuste püüdja sisend |
20 | PE6 | INT6/T3 | Väline katkestus 6 või Taimer/Loendur3 taktsignaali sisend |
21 | PE5 | INT5/OC3C | Väline katkestus 5 või Taimer/Loendur3 võrdlustulemuse väljastusüksus C |
22 | PE4 | INT4/OC3B | Väline katkestus 4 või Taimer/Loendur3 võrdlustulemuse väljastusüksus B |
23 | PE3 | AIN1/OC3A | Komparaatori negatiivne sisend või Taimer/Loendur3 võrdlustulemuse väljastusüksus A |
24 | PE2 | AIN0/XCK0 | Komparaatori positiivne sisend või USART0 taktsignaali sisend/väljund |
25 | PE1 | PDO/TXD0 | ISP Programmeerimisliidese väljund või UART0 andmete väljund |
26 | PE0 | PDI/RXD0 | ISP Programmeerimisliidese sisend või UART0 andmete sisend |
Nr | Viik | Alternatiivfunktsioon / kirjeldus | |
---|---|---|---|
1 | GND | - | Maa |
2 | VCC | - | +5 V |
3 | PA0 | AD0 | Välismälu-liidese aadressi- ja andmebitt 0 |
4 | PA1 | AD1 | Välismälu-liidese aadressi- ja andmebitt 1 |
5 | PA2 | AD2 | Välismälu-liidese aadressi- ja andmebitt 2 |
6 | PA3 | AD3 | Välismälu-liidese aadressi- ja andmebitt 3 |
7 | PA4 | AD4 | Välismälu-liidese aadressi- ja andmebitt 4 |
8 | PA5 | AD5 | Välismälu-liidese aadressi- ja andmebitt 5 |
9 | PA6 | AD6 | Välismälu-liidese aadressi- ja andmebitt 6 |
10 | PA7 | AD7 | Välismälu-liidese aadressi- ja andmebitt 7 |
11 | - | - | Pole ühendatud |
12 | - | - | Pole ühendatud |
13 | PG2 | ALE | Välismälu-liidese aadressi lukustussignaal |
14 | - | - | Pole ühendatud |
15 | PC6 | A14 | Välismälu-liidese aadressi- ja andmebitt 14 |
16 | PC7 | A15 | Välismälu-liidese aadressi- ja andmebitt 15 |
17 | PC4 | A12 | Välismälu-liidese aadressi- ja andmebitt 12 |
18 | PC5 | A13 | Välismälu-liidese aadressi- ja andmebitt 13 |
19 | PC2 | A10 | Välismälu-liidese aadressi- ja andmebitt 10 |
20 | PC3 | A11 | Välismälu-liidese aadressi- ja andmebitt 11 |
21 | PC0 | A8 | Välismälu-liidese aadressi- ja andmebitt 8 |
22 | PC1 | A9 | Välismälu-liidese aadressi- ja andmebitt 9 |
23 | PG0 | WR | Välismälu kirjutussignaal |
24 | PG1 | RD | Välismälu lugemissignaal |
25 | - | - | Pole ühendatud |
26 | - | - | Pole ühendatud |
Kontrollermooduli ühendamisel teiste moodulite ning seadmetega on esimeseks ja viimaseks tegevuseks toite eemaldamine ja ühendamine. Ajal kui plaat on pingestatud, on ohtlik seadmeid ühendada. Mooduleid ja seadmeid tuleb omavahel ühendada ettevaatlikult ja liigset jõudu kasutamata, kuna ribakaabliga võib vale käsitlemise tulemusena kontaktid kergesti kõveraks painutada. Programmaatori ühendamisel veenduge, et kaabel saaks õiget pidi. JTAG-ICE programmaatori puhul on ribakaabel suunatud plaadist eemale (punane triip toitepesa pool).
Digitaalne sisend-väljundmoodul on mõeldud lihtsamateks harjutusteks ja elementaarseks protsessi juhtimiseks. Moodulil on kolm nupp-lülitit ja kolm valgusdioodi (LED), mida saab kasutada AVR sisend-väljundviikudega. Lisaks lihtsatele valgusdioodidele on moodul varustatud ka LED numberindikaatoriga ja LCD ekraanide väljunditega. Digitaalset moodulit on mugav kasutada koos teiste moodulitega, võimaldades juhtida näiteks mootoreid ja kuvada andurite lugemeid. Moodul on varustatud:
Digitaalne sisend-väljundmoodul on Kontrollermooduli plaadiga ühendatud ühe ribakaabliga porti PA/PC/PG, mis koondab endas 8-viigulisi porte PA ja PC ning 3-viigulist porti PG. Lisaks saab moodul ribakaabli kaudu ka toite (+5 V). Kui moodul on õigesti ühendatud, peab moodulil olev väike roheline LED +5V_OK põlema minema. Kui LED ei sütti, võib põhjuseks olla ribakaabli vale ühendamine.
Moodul on varustatud kolme nupuga: S1, S2 ja S3, mis on ühendatud vastavalt PC0, PC1, PC2 viikudega. Nuppude teine ots on läbi kaitsetakistite ühendatud maaga (loogiline 0). Moodulil olevad 5 mm LED-id: LED1, LED2 ja LED3 on ühendatud vastavalt PC3, PC4 ja PC5 viikudega. LED-ide teine ots (anood) on ühendatud toitega (loogiline 1).
Digitaalne sisend-väljundmoodul on varustatud ühe 7-segmendilise numberindikaatoriga, mis on ühendatud kolme mikrokontrolleri väljundviiguga läbi ajuri A6275. Ajuri andmesignaal (S-IN) on ühendatud viiguga PC6, taktisignaal (CLK) viiguga PC7 ja lukustussignaal (LATCH) viiguga PG2.
Digitaalmooduli plaadil on eraldi välja toodud port PA. See on ühendatud samaaegselt kahte erinevasse viikude gruppi, kus esimene grupp on ühendatud läbi nivoomuunduri, võimaldades ühendada 3,3 V pingel töötavaid seadmeid (näiteks graafiline LCD) ja teine grupp on ühendatud otse porti PA (5 V nivoo) ning on joondatud vastavalt standardse tekstilise LCD viikude järgi. Eraldi on välja toodud port PG kaks kasutamata viiku - PG0 ja PG1, kuhu on võimalik ühendada lisaseadmeid, nagu näiteks ultraheli andur (alates mooduli versioonist 3.3). NB! Ultraheli anduri ühendamisel jälgida toite ja signaali kaablite viike, mida ei tohi omavahel segamini ajada. Signaali kaabel tuleb ühendada viikudega, mis on plaadil tähistatud 1 ja 2. Toitekaabel tuleb ühendada nii, et anduri maa (must juhe) oleks ühendatud plaadil oleva maa viiguga, mis on tähistatud märgiga GND.
Mooduli ühendamine on soovitatav teostada alltoodud järjekorras. Enne ühendamist veenduda, et Kontrollermooduli toide oleks lahti ühendatud.
LCD moodul on moodul, mis hõlmab endas Digitaalse sisend-väljundmooduli ühendusi ja erinevat tüüpi LCD ekraane. Digitaalse mooduli külge on võimalik ühendada 5 V nivool töötavaid alfabeetilisi LCD ekraane ja 3,3 V nivool töötavaid graafilisi LCD ekraane (alates Digitaalmooduli versioonist 3.2). Alfabeetilise ekraani kontrastsuse reguleerimiseks on Digitaalmooduli plaadil väike potentsiomeeter (LCD_BG). Graafilise LCD ekraani kontrastsust reguleeritakse tarkvaraliselt. LCD ekraanid ühendatakse porti PA. Korraga saab kasutada ainult ühte LCD ekraani.
Mooduli ühendamisel on soovitatav järgida allolevat järjekorda ja enne ühendamist veenduda, et Kontrollermooduli toide on lahti ühendatud.
Andurite moodul koosneb integreeritud andurite ja madalpääsu filtri plaadist ning kaugusanduritest.
Anduri moodul on varustatud:
Andurid on ühendatud läbi silla (inglise keeles jumper), võimaldades mikrokontrollerisse suunata kas välise anduri signaali (ühendatud pistikusse CON2) või plaadil oleva anduri signaali. Vaikimisi on analoogsisenditega (ADC0-ADC3) ühendatud kõik plaadil olevad andurid. Andurite mooduli plaat võimaldab lisaks plaadil olevatele anduritele analoog-digitaalmuunduri sisenditesse ühendada ka väliseid analoogväljundiga andureid. Selleks saab kasutada kanaleid ADC4-ADC7, mis on välja toodud pistikust CON2. Tähelepanu tuleks pöörata aga asjaolule, et ATmega128 kasutab samu ADC4-ADC7 viike (PF4-PF7) ka JTAG programmaatori tööks. Mõlemat funktsiooni korraga kasutada ei saa, mikrokontrolleri saab seadistada kasutama vaid üht neist. Kui sellegipoolest soovitakse kasutada väliseid andureid koos JTAG programmaatoriga, tuleb sildade abil ADC0-ADC3 kanalid plaadil olevatelt anduritelt välistele viikudele ümber lülitada.
Madalpääsu RC filtri saab koostada analoogsisendite 0-3 vahele (viigud PF0-PF3). Madalpääsu filtri koostamiseks paigutatakse vastavatesse pesadesse takisti ja kondensaator. Vaikimisi on madalpääsu filter koostatud kanalile PF0. Takisti väärtuseks on 10 kΩ ja kondensaatori väärtuseks 100 nF.
Mooduli ühendamisel on soovitatav järgida allolevat järjekorda ja enne ühendamist veenduda, et Kontrollermooduli toide on lahti ühendatud.
Mootorite moodul koosneb mootorite juhtplaadist ja erinevatest mootoritest. Mootoriplaat on projekteeritud AVR ATmega128 kontrolleriplaadiga ühendamiseks, kuid seda saab edukalt kasutada ka teiste mikrokontrollerite ja mootoritega, sest sisaldab H-sildu (L293D), mis on mootorite juhtimisel üldlevinud.
Mootoriplaat eraldab mootorite toited juhtsignaalidest ning võimaldab ühe ribakaabliga ühendada kõik juhtsignaalid kontrollerplaadiga.
Moodul võimaldab juhtida erinevaid mootoritüüpe ning kõigil tüüpidel võib olla erinev toitepinge. Mooduli (ühendus)võimalused:
Mootorite mooduli toitepistik (PWR):
Viik | Ühenduspunkt | Pinge | Vool |
---|---|---|---|
1 | DC mootorid | kuni 36 V | kuni 600 mA |
2 | Bipolaarne samm-mootor | kuni 36 V | kuni 600 mA |
3 | Servomootorid | 4,8 - 6 V | kuni 1 A |
4 | Unipolaarsed samm-mootorid | kuni 50 V | kuni 500 mA |
5 | Loogika toide (valitav JP1 abil) | 5 V | |
6 | Maa (GND) |
NB! Pinge ja vool sõltuvad eelkõige kasutatavast mootorist ja ei tohi ületada mootori lubatavaid piirväärtusi. Kodulabori komplektis sisalduvate mootorite toide on üldjuhul 5 - 6 V ja vastavalt sellele on kaasasoleva harukaabli väljundpinged limiteeritud 5 või 6 V.
Mootori konkreetsed margid ja mudelid võivad Kodulabori komplektides varieeruda, kuid igas komplektis on alati 1 alalisvoolumootor, 1 samm-mootor (unipolaarne või bipolaarne) ja 1 RC servomootor.
Allpool on toodud võimalikud mootorid, mis esinevad Kodulaborite komplektides.
Mootoriplaat tuleb Kontrollermooduli plaadiga ühendada ühe ribakaabliga Kontrollerimooduli porti PE-PB-PD. Mootorite toited ühendatakse eraldi PWR pistikuga, kus igale mootori tüübile on võimalik anda erinev toitepinge, sõltuvalt kasutatavast mootori tüübist. Plaadil olevaid kiipe on võimalik toita välise toiteallikaga või otse kontrollerplaadilt. Selle määrab plaadil olev sild JP1. Kui sild ühendab viigud 1 ja 2, siis kiipide toide võetakse otse Kontrollermoodulist. Kiipide korrektse toite olemasolu saab kontrollida plaadil oleva väikese rohelise LED +5V abil. Mootoriplaadil on eraldi välja toodud ka UART ühendus, mis võimaldab läbi mootoriplaadi ühendada UART protokolliga ühilduvaid seadmeid.
Alalisvoolumootorid ühendatakse pistikute gruppi DC1. Iga paari külge on võimalik ühendada üks mootor - kokku 4 mootorit. Mootori pistikuga 3 on paralleelselt ühendatud koodrite ENC1 ja ENC2 pistikud. Kui soovitakse kasutada mootoreid koos koodritega, siis mootoripistikut 3 samaaegselt kasutada ei saa (tarkvaraliselt muudetakse see sisendiks). Mootoreid juhitakse üldlevinud kahe integreeritud H-silla kiipidega L293D, mis mõlemad on võimelised juhtima samaaegselt kahte mootorit. Mootorid võib asendada ka muude täituritega (näiteks pieso heligeneraator, relee jms.), mida saab juhtida digitaalsete signaalidega ja millede maksimaalne vool ei ületa 500 mA.
AVR viik | Juhtsignaal | AVR viik | Juhtsignaal |
---|---|---|---|
PB4 | Mootor 1 1A | PD6 | Mootor 3 1A |
PB7 | Mootor 1 2A | PD7 | Mootor 3 2A |
PD0 | Mootor 2 1A | PD4 | Mootor 4 1A |
PD1 | Mootor 2 2A | PD5 | Mootor 4 2A |
Mootoriplaat toetab kahe erinevat tüüpi samm-mootori kasutamist. Plaadile on võimalik ühendada 2 unipolaarset samm-mootorit ja 1 bipolaarne samm-mootor. Bipolaarset samm-mootorit juhitakse H-sillaga L293D ja unipolaarset samm-mootorit transistorite jadaga ULN2803. Mootorite juhtsignaalide mustrid genereeritakse tarkvaraliselt. Samm-mootorite ühendamisel on oluline jälgida mähiste järjekorda. Unipolaarse samm-mootori toiteotsad ühendatakse viikudesse 1 ja 2. Kui tegemist on viie juhtmelise unipolaarse samm-mootoriga, siis toite ots ühendatakse viiku 2 ja viik 1 jääb vabaks. Samm-mootorite ühendused:
Pesa viik | Mähise ots | Unipolaar 1 | Unipolaar 2 | Bipolaar |
---|---|---|---|---|
1 | 1 | + toide | + toide | |
2 | 2 | + toide | + toide | |
3 | 1a | PE0 | PE4 | PB0 |
4 | 2a | PE1 | PE5 | PB1 |
5 | 1b | PE2 | PE6 | PB2 |
6 | 2b | PE3 | PE7 | PB3 |
RC servomootorid ühendatakse mootoriplaadi pistikutesse PWM1 ja PWM2. Mootorid ühendatakse nii, et signaali juhe (tavaliselt kollane või valge) jääb viiku 1 (plaadi ääre pool). Sama-aegselt on võimalik kasutada kahte servomootorit. Mootorite juhtsignaalid on ühendatud otse kontrolleri taimerite väljundviikudega.
AVR viik | Juhtsignaal |
---|---|
PB5(OC1A) | PWM1 |
PB6(OC1B) | PWM2 |
Mooduli ühendamisel on soovitatav järgida allolevat järjekorda ja kontrollerplaadi toitepistik ühendada alati kõige viimasena.
Kodulabori teek moodustub mitmetest C-keele päisefailidest (“.h” laiendiga) ja ühest staatiliselt C-keele teegi failist (“.a” laiendiga). Teegi installeerimisel kopeeritakse kõik teegi failid AVR-GCC alamkaustadesse, kust kompilaator nad lihtsalt üles leiab. Kasutaja teeki või selle osasid oma rakenduse kausta kopeerima ei pea.
Sellest, kuidas Kodulabori teeki reaalselt Windows ja Linux operatsioonisüsteemidega kasutama hakata, räägivad esimesed kaks praktilist harjutust. Erinevaid teegi osasid kasutavad erinevad harjutused. Eranditult tuleb igasse teeki kasutavasse projekti kaasata teegi “.a” fail mis lingitakse kompilaatori poolt projekti kompileeritud failiga. Päisefaile tuleb kaasata vastavalt vajadusele. AVR-iga seotud teegi osade päisefailid asuvad “homelab” kaustas, Kodulabori moodulitega seotud teegi osad “homelab/module” kaustas. Nimetatud kaustad asuvad kompilaatori juurkaustas ja neist failide kaasamiseks peab faili nime kirjutama suurendus- ja vähendusmärkide vahel. Näide AVR-i viikude ja Kodulabori Mootorite mooduli teegi kaasamisest:
#include <homelab/pin.h> #include <homelab/module/motors.h>
Kui Kodulabori teeki ei kasutata, siis on vajalik AVR-i registrite kasutamiseks kaasata projekti:
#include <avr/io.h>
Teegi kasutamise korral seda eraldi teha ei ole vaja, kuna on kaasatud juba failis pin.h.
Kodulabori veebilehel on vabalt kättesaadav Kodulabori teegi lähtekood, mida on võimalik kohandada vastavalt oma projekti vajadustele. Allalaetavas teegis on ka lisafunktsioone, mida käesolev raamat ei kirjelda. Järgnevad peatükid kirjeldavad teegi erinevaid osasid mida kasutatakse raamatu näidisprogrammides.
Bitioperatsioonide teek on üldkasutatav makrofunktsioonide kogum tüüpiliste bititehete teostamiseks. Neid funktsioone võib kasutada ükskõik milliste registrite või andmetüüpide puhul, sest makrofunktsioonidel pole kindlat andmetüüpi. Funktsioonid sobivad nii 8-, 16- kui ka 32-bitiste muutujate ning registrite jaoks. Neid bitioperatsioone kasutavad kõik teised teegi osad, seepärast on lähtekoodi alampeatükis funktsioonid ka välja kirjutatud.
Bitiindeksiks loetakse biti järjekorranumbrit, alustades kõige vähemtähtsast (inglise keeles least significant bit, lühend LSB). Loendamine algab nullist. 8-bitiste arvude puhul on bitiindeksi väärtus 0-7, 16-bitiste puhul 0-15 ja 32-bitiste puhul 0-31.
Bitiindeksi teisendamine bitimaskiks. Parameetrid:
Muutujas kindla biti kõrgeks seadmine. Parameetrid:
Muutujas kindla biti madalaks seadmine. Parameetrid:
Muutujas kindla biti soovitud olekusse seadmine. Parameetrid:
Muutujas kindla biti oleku ümberpööramine (madal kõrgeks ja vastupidi). Parameetrid:
Väärtuse kindla biti kõrgeloleku kontroll. Parameetrid:
Väärtuse kindla biti madaloleku kontroll. Parameetrid:
Muutujas b kolmanda biti kõrgeks seadmine ja viimase ümberpööramine.
#include <homelab/bit.h> int main(void) { unsigned char b = 0x00; bit_set(b, 2); bit_invert(b, 7); }
Järgnevalt on lühendatud kujul toodud teegi lähtekood, kust on näha, mis iga makrofunktsiooni taga peitub:
// // Funktsioonid bittidega tegelemiseks // #define bit_mask(bit) (1 << (bit)) #define bit_set(value, bit) value |= bit_mask(bit) #define bit_clear(value, bit) value &= ~bit_mask(bit) #define bit_invert(value, bit) value ^= bit_mask(bit) #define bit_is_set(value, bit) ((value) & (bit_mask(bit))) #define bit_is_clear(value, bit) (!((value) & (bit_mask(bit)))) #define bit_set_to(v, b, x) v = ((x) ? (v | bit_mask(b)) : (v & ~bit_mask(b))) // // Funktsioonid bitimaskidega tegelemiseks // #define bitmask_set(value, bitMask) value |= (bitMask) #define bitmask_clear(value, bitMask) value &= ~(bitMask) #define bitmask_invert(value, bitMask) value ^= (bitMask) #define bitmask_set_to(v, m, x) v = ((x) ? (v | (m)) : (v & ~(m))) #define bitmask_is_set(value, bitMask) ((value) & (bitMask))
Viikude teek on ette nähtud AVR digitaalsete sisend- ja väljundviikudega opereerimiseks. Teegi eesmärk on lihtsustada AVR viikude kasutamist. Kasutaja saab programmis luua soovitud viigu kohta käiva muutuja, millele ta omistab spetsiaalse makrofunktsiooniga füüsilise viigu aadressi. Seejärel saab muutuja abil välja kutsuda erinevaid funktsioone viigu suuna ja olekute muutmiseks ning nende lugemiseks.
Määrates viigu füüsilise siini (pordi) ja indeksi ära ainult ühe korra ja ühes kohas, on füüsiliste muudatuste korral lihtne programmi muuta. Näiteks, kui algul kasutatakse indikaatorina ühte LED-i, võib lihtsa tarkvara muudatusega teist LED kasutama hakata. Viigu muutujatest võib luua ka massiive, näiteks siinide koostamiseks.
Näide sellest, kuidas ühe viigu väärtus teha sõltuvaks teisest. Programmis omandab viik PC3 viigule PC0 vastupidise väärtuse:
#include <homelab/pin.h> pin output_pin = PIN(C, 3); pin input_pin = PIN(C, 0); int main(void) { bool value; // Viigu väljundiks seadistamine pin_setup_output(output_pin); // Viigu pull-up takistiga sisendiks seadistamine pin_setup_input_with_pullup(input_pin); // Lõputu tsükkel while (true) { // Sisendviigu väärtuse lugemine value = pin_get_value(input_pin); // Väljundviigule vastupidise väärtuse omistamine pin_set_to(output_pin, !value); } }
Analoog-digitaalmuunduri teek on AVR ADC mooduli kasutamise lihtsustamiseks. Teegi muundamise funktsioonid on blokeeruvad ehk nende väljakutsumisel jääb protsessor muundamise lõppu ootama. Muundamise aeg sõltub ADC taktijagurist.
Näites seatakse analoog-digitaalmuundur töövalmis ja loetakse kahelt sisendkanalilt pinge. Kanali 0 pingemuundamise väärtus loetakse muutujasse x ja kanali 1 väärtus kümnekordse ümardamise tulemusena muutujasse y.
#include <homelab/adc.h> int main(void) { unsigned short x, y; // Analoog-digitaalmuunduri seadistamine // Võrdluspinge tuleb AVCC viigult. Muunduri töötakt // on 8 korda madalam kontrolleri taktist. adc_init(ADC_REF_AVCC, ADC_PRESCALE_8); // Kanali 0 muundatud väärtuse lugemine muutujasse x x = adc_get_value(0); // Kanali 1 muundatud ja keskmistatud väärtuse lugemine muutujasse y y = adc_get_average_value(1, 10); }
Tegu on AVR universaalse jadaliidese kasutamise teegiga. Võimaldab asünkroonset andmete kirjutamist ja lugemist.
Makrofunktsiooni USART mooduli asünkroonse režiimi boodikiiruse registri väärtuse arvutamiseks. Parameetrid:
Jadaliidese asünkroonseks seadistamine. Parameetrid:
Blokeeruv sümboli saatmise funktsioon. Funktsioon ootab, kuni saatmise puhver tühjeneb ja kirjutab sinna saatmiseks uue sümboli. Parameetrid:
Blokeeruv teksti saatmise funktsioon. Parameetrid:
Sisendpuhvris andmete olemasolu kontroll. Parameetrid:
Sisendpuhvrist sümboli lugemine. Enne lugemist peab veenduma, et puhvris on sümbol. Parameetrid:
Sisendpuhvri sümboli olemasolu kontroll ja selle lugemise ühisfunktsioon. Parameetrid:
Jadaliidese seadmistamine töötab asünkroonselt 8 andmebiti, ühe stoppbiti ja ilma paarsuse kontrollita boodikiirusel 9600. Programm saadab teksti ja loeb sissetuleva sümboli.
#include <homelab/usart.h> usart port = USART(0); int main(void) { char c; // Jadaliidese seadistamine usart_init_async(port, USART_DATABITS_8, USART_STOPBITS_ONE, USART_PARITY_NONE, USART_BAUDRATE_ASYNC(9600)); // Teksti saatmine usart_send_string(port, "Tere\n"); // Sissetuleva sümboli ootamine while (!usart_has_data(port)) {} // Sümboli lugemine c = usart_read_char(port); }
Käesolev taimerite teek katab suure osa ATmega128 taimerite funktsionaalsusest. Kuna AVR taimerid on erinevate kiipide vahel päris erinevad, siis ei saa nende kasutamiseks kirjutada universaalseid funktsioone. Ka kirjeldatavad ATmega128 funktsioonid on suures osas lihtsalt primitiivsed registri muutmise või lugemise funktsioonid, kuid siiski on nad loetavamad kui registrid.
Näites seadistatakse taimer 0 tavalisse loendamise režiimi ja lubatakse ületäitumise katkestus.
#include <homelab/timer.h> #include <avr/interrupt.h> // Katkestuse programmilõik ISR(TIMER0_OVF_vect) { } int main(void) { // Taimer 0 normaalrežiimi, taktijagur 32 timer0_init_normal(TIMER0_PRESCALE_32); // Taimer 0 ületäitumise katkestuse lubamine timer0_overflow_interrupt_enable(true); // Globaalne katkestuste lubamine sei(); }
Tegu on tarkvaraliste ja riistvaraliste viite tekitamise funktsioonide teegi osaga. Viite funktsioone välja kutsudes jääb programm neid ettenähtud ajaks täitma ja muu programmi, välja arvatud katkestuste, täitmine peatub.
Viitefunktsioonid pole eelnevalt kompileeritud, sest mikrokontrolleri taktsagedus võib erinevates rakendustes erineda. Need kompileeritakse iga kord uuesti.
Mõlemat liiki viitefunktsioonide kasutamise näide:
#include <homelab/delay.h> int main(void) { // Tarkvaraline viide 100 ms sw_delay_ms(100); // Riistvaraline viide 100 ms hw_delay_ms(100); }
Seotud mooduliga: [HW] Kasutajaliidese moodul
See teek on spetsiaalselt loodud Kodulabori Digitaalse sisend-väljundmooduli plaadil asuva indikaatori kasutamiseks. 7-segmendilise indikaatoriga saab kuvada numbreid 0 kuni 9 ja mõningaid tähti.
Indikaatori juhtviikude seadmistamine väljundiks.
Soovitud numbri kuvamine indikaatoriga. Parameetrid:
Näites on number 5 kuvamise protseduur.
#include <homelab/module/segment_display.h> int main(void) { // 7-segmendilise indikaatori seadistamine segment_display_init(); // Indikaatoril numbri 5 kuvamine segment_display_write(5); }
Seotud mooduliga: [HW] LCD moodul
See teegi osa sisaldab Kodulabori alfabeetilise LCD kasutamise funktsioone.
#include <homelab/module/lcd_alpha.h> int main(void) { // Ekraani seadistamine lcd_alpha_init(LCD_ALPHA_DISP_ON); // LCD ekraani puhastamine lcd_alpha_clear(); // Kursori (nähtamatu) teise rea algusesse viimine lcd_alpha_goto_xy(0, 1); // Teksti kuvamine lcd_alpha_write_string("Tere"); }
Seotud mooduliga: [HW] LCD moodul
See teegi osa sisaldab Kodulabori graafilise LCD kasutamise funktsioone. Kuigi LCD on graafiline, puuduvad teegist hetkel siiski kujundite joonistamise funktsioonid.
#include <homelab/module/lcd_gfx.h> int main(void) { // Ekraani seadistamine lcd_gfx_init(); // LCD ekraani puhastamine lcd_gfx_clear(); // Kursori (nähtamatu) ekraani keskele viimine lcd_gfx_goto_char_xy(5, 2); // Teksti kuvamine lcd_gfx_write_string("Tere"); }
Seotud mooduliga: [HW] Mootorite moodul
Mootorite teek võimaldab juhtida Kodulabori mootorite moodulit ja mootoreid, mis sinna ühenduvad. Olemas on alalisvoolu-, samm- ja servomootorite juhtimise funktsioonid.
Ühe alalisvoolu mootorikontrolleri juhtviikude seadistamine väljundiks. Parameetrid:
Alalisvoolu mootorikontrolleri juhtkäsk. Parameetrid:
Bipolaarse mootorikontrolleri juhtviikude seadistamine väljundiks.
Bipolaarse samm-mootori mootorikontrolleri poolsammumise juhtkäsk. Funktsioon on blokeeruv ehk seda täidetakse seni, kuni soovitud arv samme on tehtud. Parameetrid:
Ühe servomootori juhtviikude väljundiks seadistamine ja taimer 1 seadistamine PWM režiimi. Parameetrid:
Servomootori juhtkäsk. Kui juhitakse positsioneerivat servomootorit, siis muutub rootori asend, kui lõputult pöörlevat, siis muutub pöörlemise kiirus. Parameetrid:
Järgnev näide demonstreerib kõiki teegi funktsioone. Järjest seadistatakse mootorikontrollerid ja liigutatakse mootoreid.
#include <homelab/module/motors.h> int main(void) { // Alalisvoolu mootorikontrollerite 0 ja 1 seadistamine dcmotor_init(0); dcmotor_init(1); // Bipolaarse samm-mootori kontrolleri seadistamine bipolar_init(); // Servomootorite 0 ja 1 juhtsignaalide seadistamine servomotor_init(0); servomotor_init(1); // Üks alalisvoolu mootor pöörlema ühtpidi, teine teistpidi dcmotor_drive(0, -1); dcmotor_drive(1, +1); // Samm-mootori pööramine 100 kraadi ühele poole ja seejärel // 2 korda kiiremini teisele poole bipolar_halfstep(1, 100, 50); bipolar_halfstep(-1, 100, 25); // Servomootorite vastassuunda keeramine servomotor_position(0, -100); servomotor_position(1, +100); }
Seotud mooduliga: [HW] Andurite moodul
See teegi osa sisaldab Kodulabori andurite kasutamise funktsioone.
Termistori temperatuuri arvutamine Celsiuse kraadides ADC muunduri väärtusest. Funktsioon põhineb teisendustabelil. Parameetrid:
IR kaugusanduri väljundpinge ADC väärtuse sentimeetriteks ümberarvutamise funktsioon. Parameetrid:
Ultraheli-kaugusanduri mõõtmise teostamise funktsioon. Funktsioon tekitab SRF04 kaugusmõõdiku päästikuimpulsi ja mõõdab kajaimpulsi saabumise aega. Aja põhjal arvutatakse objekti kaugus. Mõõtmine võtab aega kuni 36 ms. Funktsioon eeldab 14.7456 MHz mikrokontrolleri taktsagedust. Parameetrid:
#include <homelab/module/sensors.h> // Ultraheli kaugusmõõdiku juhtviigud pin pin_trigger = PIN(G, 1); pin pin_echo = PIN(G, 0); int main(void) { unsigned short adc_value = 400; // näidisväärtus signed short distance; // IR kaugusanduri ADC väärtuse sentimeetriteks teisendamine distance = ir_distance_calculate_cm(GP2Y0A21YK, adc_value); // Ultraheli-kaugusanduriga mõõtmine distance = ultrasonic_measure(pin_trigger, pin_echo); }
Praktilised näited on üles ehitatud ühtse läbiva stiiliga ja võimalikult konkreetsed. Iga näide algab lühikese teoreetilise taustaga, andes nii vajalikud põhiteadmised harjutuses järgnevale praktilisele osale. Praktiline osa sisaldab endas tarkvara lähtekoodi kommenteeritud näidet. Üldjuhul on koodinäites kasutatud Kodulabori teeki, aga mõne näite puhul ka otsest registrite seadistamist. Natuke erineva struktuuri ja eesmärgiga on esimene peatükk, mis kirjeldab vajaliku tarkvara paigaldamist ja seadistamist. Näited on toodud Windowsi ja Linuxi keskkondade jaoks. Järgnevad peatükid ja praktilised näited sobivad mõlema operatsioonisüsteemi ja arendustarkvara jaoks.
Ülesehitus
Praktiliste näidete peatükkide juures on toodud loetelu näite läbimiseks vajalikest eelteadmistest. Loetelus on viited raamatu teistele peatükkidele, mis on tähistatud teemakohaste ikoonidega:
Näidete baastarkvara
Nagu eespool öeldud, on praktilised koodinäited koostatud Kodulabori teegi baasil. Teeki on kirjutatud enimkasutatavad AVR spetsiifilised operatsioonid ja Kodulabori moodulitega seotud protseduurid. Teegi kasutamine tähendab, et kasutaja ei pea moodulite töölepanekuks kirjutama riistvaralähedast, registritega toimetavat programmikoodi, kuigi see võimalus on alati olemas. Riistvaraga suhtleva tarkvara eraldamine näidetest ja harjutusülesannetest võimaldab kasutajal keskenduda oma algoritmi loomisele, mitte riistvaraga seotud eripäradele.
Näidete koodistiil
Näidisprogrammid on kirjutatud ühtses stiilis, et programmikood oleks ülevaatlikum. Ühtne stiil teeb programmi loetavaks ja välistab kergemate süntaksivigade tekkimise. Kindlat stiili on soovitatav järgida ka harjutusülesannete tegemisel. Stiili peamised iseloomustajad:
AVR mikrokontrolleri programmeerimiseks on vaja koodi kirjutamise keskkonda, vastava keele kompilaatorit ja kompileeritud programmi kontrollerisse laadimise tarkvara. Mugavaim on kasutada kõigeks selleks spetsiaalset integreeritud arenduskeskkonda (IDE). AVR mikrokontrollerit on võimalik programmeerida paljudes erinevates programmeerimiskeeltes: assembler, C, C++, Pascal, Basic jne. Käesolev raamat on suunatud C-keele kasutamisele mikrokontrolleri programmeerimisel. AVR mikrokontrolleri C-keeles programmeerimiseks on olemas tasuta tarkvara nii Linuxi kui ka Windowsi operatsioonisüsteemidele. Järgnevad peatükid tutvustavadki mõlema keskkonna seadistamist.
Kogu vajaliku installeeritava tarkvara harjutuste läbimiseks leiab Kodulabori veebilehelt.
Järgnev juhend kirjeldab AVR arenduskeskkonna installeerimist ja kasutamist Windowsi operatsioonisüsteemis.
Enne paigaldamist tuleks hankida alljärgnev tarkvara, kas tootja või Kodulabori kodulehelt või Kodulabori kohvriga kaasas olevalt plaadilt.
1. AVR Studio
AVR Studio 4 on IDE (inglise keeles Integrated Development Environment), milles toimub tarkvara kirjutamine ja mikrokontrollerisse laadimine. Uusima AVR Studio versiooni leiab selle tootja, Atmeli, kodulehelt.
2. WinAVR
WinAVR on GNU-GCC kompilaator AVR mikrokontrolleritele. See on vabavara, mille leiab Sourceforge veebilehelt. WinAVR pakub installeerimisel välja kataloogi nime, mis sisaldab lisaks nimele versiooni numbrit, kuid kataloog tuleks käsitsi muuta lihtsalt:
C:\WinAVR
3. Kodulabori teek
Kodulabori teek sisaldab programmi lihtsustavaid funktsioone AVR ja Kodulabori komplekti osade kasutamiseks. Teegi viimase versiooni leiab Kodulabori veebilehelt. Teek tuleb kindlasti installeerida samasse kataloogi, kus on WinAVR.
4.. Virtuaalne COM pordi ajur
Ajur võimaldab arvutiga ühendada JTAG ICE programmaatori. Ajur tuleb installeerida enne programmaatori ühendamist arvutiga. Paigaldusprogrammi nimi on “CDM x.xx.xx.exe”, kus “x” tähistab versiooni. Seejärel tuleb ühendada programmaator arvutiga USB liidese kaudu ja lasta Windows-il teostada automaatne paigaldus. Olekuribal peaks nägema umbes sellist teadet.
Sõltuvalt sellest, kui palju virtuaalseid jadaporte on arvutisse eelnevalt paigaldatud ja kasutusele võetud, paigaldab Windows automaatselt järgmise järjekorranumbriga virtuaalpordi. Uus järjekorranumber genereeritakse ka USB pordi vahetamisel. AVR Studio mõned versioonid tunnevad JTAG ICE programmaatori ära ainult jadaportides COM1…COM9 ja silumise funktsiooni lubavad kasutada ainult jadaportides COM1…COM4. Kasutajal on võimalus pordi järjekorranumbrit muuta, kasutades Device manager töövahendit. Vaata protseduuri veebilehelt.
AVR programmi kirjutamiseks tuleb luua uus projekt, mis tüüpiliselt sisaldab endas palju erinevaid faile: programmikoodi(e), päisefaile, kompileeritud programmi jne. Selleks et projektid oleks korrektselt eristatavad, tuleks iga projekti jaoks luua uus kataloog (seda võimalust pakub uue projekti loomise abimees).
Uue projekti loomiseks tuleb läbida järgmised sammud:
1. Avada AVR Studio ja vajutada nupule uus projekt (New Project). Juhul kui vastav aken automaatselt ei avane, valida menüüst Project - New project. Pärast sobivat sisestust vajutada nupule Next.
2. Avaneb aken, kus tuleb märkida kompilaatori ja failide algseaded. Kompilaatoriks valida AVR GCC ja paremas akna osas sisestada projekti nimi ning algkoodi faili nimi. Algkoodi faili nimi peaks kindlasti lõppema laiendiga “.c”. Aknas on võimalik veel märkida valikud automaatseks projekti nimega kataloogi ja algkoodi faili tekitamiseks. Mõlemad valikud on mõistlik ära märkida. Samuti tuleks näidata kataloog, kuhu vastav projektikataloog tekitatakse. Pärast valikute tegemist vajutada nupule Next.
NB! Kui kompilaatori valikus puudub AVR GCC, siis ei ole WinAVR korrektselt paigaldatud ja seda tuleks enne C-keele programmi kirjutamist kindlasti teha.
3. Järgnevalt avaneb aken, kus tuleb märkida kasutatav silumise platvorm ja mikrokontrolleri tüüp. Kodulaboris on silumise platvormina kasutusel JTAG ICE programmaator ja mikrokontrolleriks on ATmega128. Projekti lõplikuks loomiseks vajutada nupule Finish.
4. Nüüd avaneb juba programmeerimise kasutajaliides, kuhu saab hakata kirjutama uut programmi lähtekoodi.
5. Enne koodi kompileerimist tuleb määrata projekti seaded. Olulisemad seaded on kontrolleri taktsagedus ja kompilaatori optimeerimismeetod. Kodulabori kontrolleri taktsagedus on 14,7456 MHz ehk 14745600 Hz. See sagedus tuleb hertsides määrata Project → Configuration Options → General aknas. Optimeerimise meetodiks jätta -Os, kui ei ole konkreetset vajadust teiste meetodite järgi.
6. Kodulabori teegi kasutamine AVR Studio-ga eeldab, et see on tarkvara paigaldamise juhendi kohaselt süsteemi paigaldatud. Iga projekti korral tuleb teek projekti seadetest Project → Configuration Options → Libraries lisada lingitavate objektide nimekirja.
Kui objekt libhomelab.a nimekirjast puudub, siis ei ole Kodulabori teek korrektselt süsteemi paigaldatud.
Kui arenduskeskkond on esimest korda paigaldatud ja seadistatud, on mõistlik testida, kas kõik sai tehtud õigesti. Selleks on lihtsaim viis teha üks väike programm, see ära kompileerida ja laadida kontrollerisse.
1. Ühendada programmaator ATmega128 plaadiga. Ühendamisel kontrollida, et programmaator saab ühendatud õigesse pesasse (JTAG) ja õigetpidi (kaabel on suunatud kontrolleri plaadist eemale - vaata järgmist pilti). Peale programmaatori ühendada kontrolleri toide (kontrollerplaadil peab süttima väike roheline LED). Sisestada lihtne C-kood:
#include <avr/io.h> #include <homelab/delay.h> int main(void) { // Viigu PB7 seadmine väljundiks DDRB = 0x80; // Lõputu tsükkel while (true) { // Viigu PB7 inverteerimine PORTB ^= 0x80; hw_delay_ms(500); } }
Kompileerida programm käsuga Build (kiirklahv F7) ja kontrollida, et kompileerimine õnnestus. Selleks peab teadete aknasse tekkinud kompilaatori väljundi lõpp olema järgmine:
Build succeeded with 0 Warnings...
2. Avada koodi laadimise aken nupust Tools → Program AVR → Auto Connect. Tulemuseks peaks avanema kompileeritud faili mikrokontrollerisse laadimise aken. Kontrollige, et avatud oleks kaart Program.
Kui eespool toodud aken ei avane ja avaneb aken Connection Failed, siis puudub ühendus programmaatoriga. Esmalt tuleks kontrollida, kas mikrokontrolleril on järel toide ja kas programmaator on ühendatud õigesti (JTAG pistikusse, kaabel õiges suunas). Kui see on korras, siis tuleks kontrollida, mis COM pordi numbri on Windows programmaatorile omistanud. Kui see on suurem 9-st, siis ei pruugi tarkvara seda leida ja pordile tuleb omistada väiksem järjenumber.
3. Programmaatori aknas sisestada Flash-sektsioonis tekstikasti Input HEX File kompileeritud fail. Seda saab teha “…” nuppu vajutades. Kompileeritud fail asub tavaliselt projekti alamkataloogis default ja see on sama nimega, mis projekt, kuid laiendiga “.hex”, näiteks “labor1.hex”. Pärast õige faili valimist vajutada nupule Program, mis laeb valitud programmi kontrollerisse. Kui kõik õnnestus, tekib programeerimiskeskkonna allosasse teade:
OK Reading FLASH input file.. OK Setting device parameters for jtag programming ..OK Entering programming mode.. OK Erasing device.. OK Programming FLASH .. OK Reading FLASH .. OK FLASH contents is equal to file.. OK Leaving programming mode.. OK
Programmi mõjul peaks kontrolleri plaadil olev oleku-LED PB7 perioodiliselt süttima ja kustuma. Kui programm töötab, on tarkvara paigaldatud edukalt ja esimene projekt tehtud. Palju õnne!
Programmi silumiseks (inglise keeles debugging) nimetatakse vigade otsimist programmist. Selleks on loodud eraldi vahendid - silurid (inglise keeles debugger), mis võimaldavad programmi täita samm-sammult, peatades seda soovitud kohtades. Selline programmi täitmine võimaldab igas programmi faasis kontrollida muutujate väärtusi, registrite sisusid ja programmi täitmise järjekorda. Eriti oluline on silumise võimaluse kasutamine keerukamate programmide juures, kus vea põhjust on tihti keeruline otsida. Mikrokontrollerite puhul on veel oluline, et tarkvara samm-sammult täitmine toimub reaalselt kontrolleris ja võimaldab nii lisaks registrite väärtuste vaatamisele näha ka reaalsete väljundite muutumist. Siluri kasutamiseks on eelkõige vaja kahte tingimust: kasutatav mikrokontroller peab silumist toetama ja peab olema silumist toetav riistvara - JTAG programmaator. Odavamad programmaatorid, mis kasutavad ISP programmeerimise liidest, võimaldavad laadida kontrollerisse kompileeritud programmi, kuid ei võimalda silumist.
Programmi käivitamiseks siluri režiimis AVR Studio-ga tuleks see esmalt kompileerida nupuga Build (kiirklahv F7) ja käivitada kompileeritud programm käsuga Run (kiirklahv F5). Programmi lähtekoodi võib enne seda soovitud kohtadele lisada katkestuspunkte (inglise keeles break point) (kiirklahv F9). Kui programmi täitmine jõuab katkestuspunktini, peatatakse programmi töö, võimaldades nii uurida mikrokontrolleri olekut sellesse punkti jõudmisel. Programmi täitmist võib jätkata jällegi käsuga Run või siis kasutada käskhaaval täitmist käsuga Step Into (kiirklahv F11).
Mõnikord tekib vajadus AVR programmis kasutada ujukoma-arve. Nendega arvutamiseks ja nende esitamiseks printf-tüüpi funktsioonidega tuleb projekti seadistustes teha järgmised muudatused:
1. Avada projekti seaded menüüst Project → Configuration Options. Seadete kaardil Libraries tuleb sinna, kuhu on lisatud Kodulabori teegi objekt libhomelab.a, järgi lisada ka libprintf_flt.a ja libm.a.
2. Seejärel tuleb avada Custom Options kaart ja valida [All files] sektsioon. Parempoolsesse kasti lisada read “-lprintf_flt” ja “-lm”. [Linker Options] sektsiooni lisada rida “-uvfprintf”.
3. Vajutada OK ja sulgeda seadete aken.
Järgnev juhend kirjeldab AVR arenduskeskkonna installeerimist ja kasutamist Ubuntu 9.10 operatsioonisüsteemis.
Installeerida järgnev tarkvara:
1. Linuxi tarkvarapaketid
Installeerimiseks kasutada terminali käsurida:
sudo apt-get install gcc-avr avrdude avr-libc
või graafilist paketihaldustarkvara (näiteks Ubuntu tarkvarakeskus või Synaptic pakihaldur).
2. Kodulabori teek
Teek lihtsustab programmikoodi kirjutamist, kuna madalama taseme funktsioonid on selles juba valmis kirjutatud. Teegi installeerimiseks salvestada arvutisse Kodulabori kodulehelt fail nimega Homelab library vX.X.run, kus X.X asemel on versiooni number, ning käivitada see järgmise käsuga:
sudo sh homelab_library_vX.X.run
Veendu, et Kodulabori teegi allalaadimine ja paigaldamine õnnestus.
3. KontrollerLab
KontrollerLab on IDE (inglise keeles integrated development environment) ehk integreeritud arenduskeskkond tarkvara kirjutamiseks, kompileerimiseks, pealelaadimiseks jms. Salvestada KontrollerLab tarkvarapakett kausta (näiteks ~/Dokumendid/AVR/KontrollerLab/) ning terminali aknas käivitada käsk selles kaustas:
sudo dpkg -i kontrollerlab*.deb
Kui tekib probleeme paketisõltuvuses, siis käivitada järgnev käsk, mis paigaldab puuduvad paketid:
sudo apt-get install –f
Ühendada programmaator arvutiga ning kontrollida, kas arvuti tunneb seadme ära. Terminali aknasse kirjutada käsk lsusb, mis näitab nimekirja ühendatud USB seadmetest. Programmaatori nimi on “Future Technology Devices International, Ltd FT 232 USB-Serial (UART) IC”.
Saamaks teada, millise pordi taha on programmaator ühendatud, kontrollida /dev kataloogi, kasutades käske cd /dev (määrab /dev kui aktiivse kataloogi) ja dir (kuvab kataloogi sisu). Kuna tegu on USB-Serial liidesega, siis on ta märgitud ttyUSBx-na, kus x märgib liidese numbrit. Kui eelnevalt ei ole mingeid teisi USB-serial seadmeid ühendatud, siis on see number 0.
AVR programmi kirjutamiseks tuleb luua uus projekt, mis tüüpiliselt sisaldab endas mitmeid erinevaid faile: programmikoodi(e), päisefaile, kompileeritud programmi jne. Selleks et projektid oleks korrektselt eristatavad, tuleks iga projekti jaoks luua uus kataloog (seda võimalust pakub ka uue projekti loomise abimees).
Uue projekti loomiseks järgi järgmisi samme:
1. Avada KontrollerLab (Rakendused → Programmeerimine → KontrollerLab) ning valida ülevalt menüüst File → New → New project. Avaneb aken, kus tuleb määrata projekti asukoht ning Location-väljale kirjutada projektifaili nimi. Toodud näites on loodud eraldi kataloog ../Homelab/blinkingLED/, kus hoitakse kõik näiteprogrammi (vilkuva LED) jaoks loodavad failid eraldi.
2. Kuna projekt on esialgu tühi, siis tuleb sellele juurde lisada C-fail, kuhu koodi saaks kirjutada. Valida menüü File → New → New. Avaneb faili lisamise aken, kus valida C source ja määrata faili nimi.
3. Seadistada KontrollerLabi projekt vastavalt Kodulabori riistvarale. Valida menüü Project → Configure Project, mispeale kuvatakse projekti seadistamise aken avatuna Common-kaardil. Määrata protsessoriks (CPU) ATmega128, taktsageduseks (clock) 14745600,0 Hz ning loodavate HEX ja MAP failide nimed. Vajutades nuppu Set as default, määrab see hetkeseadistused KontrollerLabis ka kõikide edaspidi loodavate projektide seadistusteks. Kuna sõltumata projektist jääb kodulabori riistvara samaks, siis on mõttekas määratagi sisestatud parameetrid vaikimisi parameetriteks. Samas jäävad ka KontrollerLabi poolt loodavate väljundfailide (HEX, MAP) nimed samaks. Siinkohal on kaks võimalust: igas projektis muuta HEX faili nime või panna mingi universaalsem nimi (nt out.hex), mis sobiks kõikidele projektidele. Hetkel on võetud teine variant, nii et projekti vahetamisel ei pea väljundfailide nimesid muutma.
NB! Kuna KontrollerLab programmis ei saa korrektselt teeki lisada Linker kaardil, siis tuleb Kodulabori teegi lisamine seadistada siin, kirjutades map faili nime taha -lhomelab .
Compiler kaardil määrata kompilaatori seaded, nagu näidatud juuresoleval pildil. Enne OK vajutamist määrata siin sisestatud parameetrid vaikimisi seadeteks.
4. Määrata programmaatori seaded, valides menüü Project → Configure Programmer. Choose Programmer-kaardil valida AVRDUDE ning AVR DUDE kaardil määrata programmaatori tüübiks jtagmkI ja ühendusliideseks eelnevalt leitud port /dev/ttyUSBx (vt. programmaatori peatükki). Määrata ka siin vastavad parameetrid vaikimisi seadeteks.
5. Määrata tekstiredaktori seaded nii, et tabulaatorit tõlgendataks 4 tühikuna. See on vajalik, kui juhtutakse lähtefaili avama mõne muu tekstiredaktoriga, mis tõlgendab tabulaatorit teisiti kui KontrollerLab. Sel juhul võib koodi liigendus muutuda, nii et inimese jaoks on kood raskesti jälgitav. Selleks, et seda ei juhtu, valida menüü Settings → Configure Editor ja avanenud aknas vasakult Editing. Märgi linnuke kasti “Insert spaces instead of tabulators” sisse. Samuti määra tabulaatori laiuseks 4 tühikut.
6. Seadista avanenud alamaknad KontrollerLabis oma käe järgi ning kirjuta mingi lihtne programm keskkonna testimiseks. Järgnevas alampeatükis on näitena toodud vilkuva LED programm.
Kui arenduskeskkond on esimest korda paigaldatud ja seadistatud, on mõistlik testida, kas kõik sai tehtud õigesti. Selleks on lihtsaim viis teha üks väike programm, see ära kompileerida ja laadida kontrollerisse.
1. Ühendada programmaator ATmega128 Kontrollerimooduli plaadiga. Kontrollida, et programmaator saab ühendatud õigesse pistikusse (JTAG) ja õigetpidi (kaabel on suunatud kontrolleri plaadist eemale - vaata järgmist pilti). Pärast programmaatori ühendamist ühendada kontrolleri toide (kontrollerplaadil peab süttima väike roheline oleku-LED).
2. Sisestada lihtne C-kood ja kompileerida see (compile).
#include <avr/io.h> #include <homelab/delay.h> int main(void) { // Viigu PB7 seadmine väljundiks DDRB = 0x80; // Lõputu tsükkel while (true) { // Viigu PB7 inverteerimine PORTB ^= 0x80; hw_delay_ms(500); } }
Veendu, et väljundaknasse tuleb teade “File compiled successfully”. Kui annab teate “Error(s) occurred: ”, siis kontrollida, et koodi sisestamisel ei ole tehtud mõnda kirjaviga.
3. Koodi pealelaadimiseks valida ignite käsk. Kui kõik õnnestub, siis väljundaknas viimase reana annab KontrollerLab teate “Project built and uploaded successfully”. Kontrolli, et oleku-LED hakkaks perioodiliselt vilkuma (500 ms põleb, 500 ms on kustund).
Kui LED vilgub, nii nagu eespool kirjeldatud, on tarkvara paigaldatud edukalt ja esimene labor läbitud. Palju õnne!
Mõnikord tekib vajadus AVR programmis kasutada ujukoma-arve. Nendega arvutamiseks ja nende esitamiseks printf-tüüpi funktsioonidega tuleb projekti seadistustes teha järgmised muudatused:
1. Avada projekti seaded menüüst Project → Configure Project ning valida Linker kaart. Märgistada Linker flags sektsioonis esimene linnuke (vaata ka juuresolevat pilti).
2. Vajutada OK ja sulgeda seadete aken.
Järgnevad peatükid tutvustavad lihtsaimat mikrokontrolleri funktsiooni - digitaalseid sisend-väljundviike. Viigud on mikrokontrolleri metallist kontaktid, kõnekeeles jalad, mille kaudu saab edastada ja vastu võtta digitaalseid signaale. Kui viik seadistada programmis sisendiks, saab selle kaudu mikrokontrollerisse lugeda lülitite või muude lihtsamate andurite olekut. Kui viik seadistada väljundiks, saab selle kaudu süüdata valgusdioode või juhtida elektriseadmeid.
Peaaegu kõigi tüüpiliste mikrokontrollerite viigud võimaldavad lihtsaid sisend-väljundfunktsioone täita, kuid tavaliselt on neil viikudel ka alternatiivfunktsioonid. Enne alternatiivfunktsioonidega tegelemist, tuleks aga lihtsamad funktsioonid endale selgeks teha.
Vajalikud teadmised: [HW] Kontrollermoodul, [HW] Kasutajaliidese moodul,
[ELC] LED-i takisti arvutamine, [AVR] Registrid, [AVR] Digitaalsed sisendid-väljundid,
[LIB] Bitioperatsioonid, [LIB] Sisend-väljundviigud
Valgusdiood on pooljuht, mille päripingestamisel kiirgab see valgust. Valgusdioodi nimetatakse inglise keelse lühendiga LED (light-emitting diode). On olemas erineva värvusega valgusdioode ja valgusdioodide kombinatsioone, millega saab tekitada ka valget valgust. Valgusdioodil on nagu tavalisel dioodilgi kaks kontakti - anood ja katood. Valgusdioodi joonistel on anood tähistatud + ja katood - sümboliga.
Päripingestamisel rakendatakse LED-i anoodile positiivne ja katoodile negatiivne pinge. LED-i päripinge sõltub selle värvusest – pikema lainepikkusega LED-ide (punased) puhul on see ~2V, lühema lainepikkusega (sinised) on see ~3V. Tavaliselt on LED-ide võimsus mõnikümmend millivatti, sellest tulenevalt peab ka vool samas suurusjärgus olema. Suurema pinge või voolu rakendamisel LED-ile on oht see lihtsalt läbi põletada.
Kui LED-e kasutatakse spetsiaalselt valgustamiseks, on mõistlik kasutada spetsiifilisi elektriskeeme nendele täpselt õige pinge ja voolu tekitamiseks. Tihti kasutatakse LED-e aga indikaatoritena ja neid toidetakse otse mikrokontrolleri viikudelt. Kuna mikrokontrollerite toitepinge on enamasti kõrgem LED-ide päripingest ja ka voolutugevus on suurem, siis tuleb LED-iga järjestikku lisada takisti, mis piirab voolu ja tekitab vajaliku pingelangu. Takisti arvutusvalemid leiab elektroonika peatükist.
LED-e toodetakse mitmesugustes kestades. Kõige levinumatel „jalgadega“ LED-idel on 3 mm või 5 mm läbimõõduga ümmargune kest ja 2 pikka metallist viiku. Pikem viik tähistab anoodi, lühem katoodi. Pindliides kestas (SMD) LED-idel on polaarsuse tähistamiseks põhja all T-kujuline tähis, kus T katus tähistab anoodi ja teravik katoodi asukohta.
Kodulabori Kontrollermooduli plaadil on üksik punane LED, mille anood on läbi takisti ühendatud +5 V toitega ja katood ATmega128 viiguga PB7. Selleks et Kontrollermooduli LED-i põlema süüdata ja kustutada, tuleb PB7 viik väljundiks defineerida ning seda vastavalt madalaks ja kõrgeks seada. Ehk siis viigu kõrges olekus LED ei põle ja madalas põleb. Põhimõtteliselt võib LED-e ka teistmoodi ühendada, nii et anood on mikrokontrolleri viiguga ja katood maaga ühendatud (kusagil vahel peab ka takisti olema) – sellisel juhul viigu kõrges olekus LED põleb ja madalas olekus ei põle.
Peaaegu kõik Kodulabori praktilised näited, kaasa arvatud LED-i süütamise näide, kasutavad Kodulabori viikude teeki. Viikude teegis on andmetüüp pin, mis sisaldab viiguga seotud registrite aadresse ja viigu bitimaski. Kui programmi tekitada pin-tüüpi muutuja ja see kohe programmi alguses makrofunktsiooniga PIN algväärtustada, saab selle muutuja abil viiku kogu programmi ulatuses vabalt kasutada, ilma et peaks oskama registreid kasutada. Järgnevalt on toodud 2 näiteprogrammi, mis teevad täpselt sama asja, kuid üks neist on kirjutatud Kodulabori teegi baasil, teine mitte.
// // Kodulabori Kontrollermooduli LED-i testimise programm. // Põhineb Kodulabori teegil. // #include <homelab/pin.h> // // LED-i viiguga seotud parameetrite määramine muutujale // pin debug_led = PIN(B, 7); // // Põhiprogramm // int main(void) { // LED-i viigu väljundiks seadmine pin_setup_output(debug_led); // LED-i süütamine pin_clear(debug_led); }
// // Kodulabori Kontrollermooduli LED-i testimise programm. // Põhineb otsesel registrite muutmisel. // #include <avr/io.h> // // Põhiprogramm // int main(void) { // LED-i viigu väljundiks seadmine DDRB |= (1 << 7); // LED-i süütamine PORTB &= ~(1 << 7); }
Esimene näide kasutab viikude teeki (pin.h fail). Esmalt luuakse programmis pin-tüüpi debug_led-nimeline muutuja, mis hoiab infot LED viigu kohta. Põhiprogrammis toimub selle viigu väljundiks seadmine läbi funktsiooni pin_setup_output ja seejärel selle viigu madalaks määramine funktsiooniga pin_clear, mille tulemusena LED süttib. Teises näites muutujaid ei kasutata, LED-i väljundiks määramine ja süütamine toimub viigu siini B suuna- ja väljundregistrite väärtuste muutmise teel. AVR-iga rohkem kursis olev lugeja märkab kindlasti, et tegelikult pole vaja anda LED-i põlema paneku käsku kummaski näites, kuna vaikimisi on AVR väljundite väärtus nagunii 0, kuid seda on siinkohal tehtud korrektsuse pärast.
Mis siis on viikude teegi ja registrite kasutamise vahe? Vahe on kasutusmugavuses - teegiga on see lihtsam, sest ei pea registrite nimesid ja nende toimet teadma. Kõige olulisem teegi eelis on aga kohandatavus. Registreid kasutades tuleb viigu muutmiseks kogu programmis registrite nimed ja bitimaskid ümber muuta, teegi puhul tuleb seda teha vaid programmi alguses, kus viigu muutuja algväärtustatakse. Otsesel registrite kasutamisel on üks näiline eelis - viigu kasutamine on vahetu ja see ei toimu läbi programmimälu ja aeganõudvate funktsioonide. Tegelikult on aga uuemad AVR-GCC kompilaatori versioonid niivõrd taibukad, et teisendavad teegi funktsioonid täpselt sama vahetuks registrite manipuleerimise käskudeks, nagu oleks seda otse programmis tehtud. Täpsustuseks tuleb öelda, et kompilaatori teisendusoskus kehtib ainult konstantsete pin-tüüpi üksikmuutujate kohta, mitte töö ajal muutuvate muutujate ja massiivide kohta.
Järgnevalt on osaliselt toodud viikude teegi lähtekood, mille eesmärk on selgitada teegis toimuvat. Paraku ei pruugi see algajale päris arusaadav olla kuna kasutusel on C-keele viidad (inglise keeles pointer), millest selle raamatu C-keele õpetuses kirjutatud pole. Viitade kohta kohta leiab huviline palju infomaterjali internetist ja programmeerimise õpikutest.
// Makro-konstant millega määratakse ära registri viit #define _REG_PTR_ volatile uint8_t * // // Viigu andmetüüp // typedef struct pin { _REG_PTR_ ddr; _REG_PTR_ port; _REG_PTR_ pin; uint8_t mask; } pin; // // Viigu andmetüüpi muutuja algväärtustamise makrofunktsioon // #define PIN(port_char, bit_index) \ { \ (_REG_PTR_)&DDR ## port_char, \ (_REG_PTR_)&PORT ## port_char, \ (_REG_PTR_)&PIN ## port_char, \ bit_mask(bit_index) \ } // // Viigu seadmine väljundiks // inline void pin_setup_output(pin pin) { bitmask_set(*pin.ddr, pin.mask); } // // Viigu seadmine kõrgeks // inline void pin_set(pin pin) { bitmask_set(*pin.port, pin.mask); } // // Viigu seadmine madalaks // inline void pin_clear(pin pin) { bitmask_clear(*pin.port, pin.mask); }
Peale Kontrollermooduli asuvad LED-id ka Digitaalsel sisend-väljundmooduli plaadil. Need on elektriliselt ühendatud samamoodi nagu Kontrollermooduli LED ehk katood on ühenduses AVR viiguga. Punane LED on ühenduses viiguga PC5, kollane viiguga PC4 ja roheline viiguga PC3. Nende Kodulabori teegi põhine näidisprogramm näeb välja järgmine:
// // Kodulabori Digitaalse sisend-väljundmooduli // LED-ide testimise programm. // #include <homelab/pin.h> // // LED-ide viikude määramine // pin led_red = PIN(C, 5); pin led_yellow = PIN(C, 4); pin led_green = PIN(C, 3); // // Põhiprogramm // int main(void) { // LED-ide viikude väljundiks seadmine pin_setup_output(led_red); pin_setup_output(led_yellow); pin_setup_output(led_green); // Punase ja rohelise LED-i põlema panek pin_clear(led_red); pin_clear(led_green); // Kollase LED-i kustutamine pin_set(led_yellow); }
Vajalikud teadmised: [HW] Kasutajaliidese moodul, [AVR] Registrid,
[AVR] Digitaalsed sisendid-väljundid, [LIB] Sisend-väljundviigud, [PRT] Valgusdiood
Lüliti on elektromehhaaniline seade elektriahela kokku- ja lahtiühendamiseks. Lüliteid on erinevaid, kuid tüüpiline mehhaaniline lüliti koosneb klemmidest, mida saab omavahel mehhaaniliselt ühendada. Klemmide ühenduse korral on elektriahel suletud ja lülitit võib läbida elektrivool. Kui klemmid on lahti, on elektriahel avatud ja elektrivool lülitit läbida ei saa.
Lülititega saab otseselt elektriahelaid pingestada, kuid neid saab kasutada ka anduritena. Lüliti anduri funktsioonis on ka selle harjutuse teema, seepärast on vaatluse alt välja jäetud spetsiifilised kõrgepinge ja suure voolu lülitid. Lülitid erinevad ka kontaktide arvu ja nende ühendamise meetodilt. On olemas kahe kontaktiga lüliteid, kuid ka duubellüliteid, kus ühendatakse kontaktide paarid. On surunupp-, klahv-, liug- ja pöiallüliteid ning lüliteid, mis vajutades ei ühenda, vaid katkestavad elektriahela.
Erinevat liiki lülititel on erinev skemaatiline tähis. Järgnevalt on toodud tüüpilisemad elektroonikaskeemides kasutatavad lülitid ja nende elektrilised tähised:
Lüliti kasutamiseks andurina mikrokontrolleri juures ühendatakse lüliti üks kontakt mikrokontrolleri viiguga, mis määratakse programmis sisendiks. Kui toimub kontakti ühendamine maa- või toitepotentsiaaliga, muutub ka mikrokontrolleri viigule vastava siini biti väärtus. Loogiline variant on kasutada pöiallülitit, mis võimaldab üht kontakti ühendada valitud kontaktiga (antud juhul siis maa või toitega), kuid see pole päris nii lihtne. Põhjus on selles, et ümberlülitamise hetkel ei ole kontaktid omavahel ühenduses. See hetk on väga lühike (millisekundites), kuid sellesama hetke jooksul pole mikrokontrolleri sisendviik kuhugi ühendatud ja sel on määramata väärtus. Elektromagnetiliste häirete tõttu (mida leidub kõikjal) võib mitte kuhugi ühendatud sisendviik täiesti suvalistel ajahetkedel omada 0 või 1 väärtust.
Häired teevadki lülitite kasutamise keerukamaks. Üks peamine meetod määramata olekute vältimiseks on mikrokontrolleri sisend ühendada läbi takisti kas maa- või toitepotentsiaaliga. Sellises funktsioonis olevat takistit nimetatakse inglise keeles kas pull-down või pull-up takistiks. Tavaliselt ulatub pull-up või pull-down takistite takistus mõnest kilo-oomist ühe mega-oomini. Kui lüliti on avatud, jääb sisendile, millele on ühendatud takisti, pinge, kui lüliti sulgeda, rakendub sisendile lüliti pinge, sest lüliti takistus on palju väiksem (nullilähedane) kui takisti oma. Sisuliselt on tegu pingejaguriga.
Pull-up või pull-down takistiga võib andurina kasutada ka lihtsat kahekontaktilist lülitit, nii et lüliti ühendab sisendi ühe potentsiaaliga ja takisti teisega. Tavaliselt on mikrokontrolleritel ka sisseehitatud pull-up või pull-down takisti kasutamise võimalus, mistõttu ei pea skeemi eraldi takistit lisamagi. Näiteks AVR mikrokontrollerites on IO viikudel 20 kuni 50 kilo-oomised pull-up takistid.
Olgu öeldud, et mehhaaniliste lülititega kaasneb siiski veel üks probleem – kontaktide põrkumine. See põhjustab lülitamise hetkel mitmeid väga lühiajalisi väärlülitusi. Seda teemat on käsitletud järgmises peatükis. Selle peatüki näiteid väärlülituse probleem praktiliselt ei mõjuta.
Kodulabori Digitaalse sisend-väljundmooduli plaadil on kolm surunupp-lülitit. Lülitid ühendavad mikrkontrolleri viike maaga, kuid mitte otse, vaid läbi takisti – seda põhjusel, et juhuslikul mikrokontrolleri viikude väljundiks määramisel neid nupuvajutusel ei lühistataks. Lülititel on ka pull-up takistid, kuid need on palju suurema takistusega kui kaitsetakistid, nii et nupu allavajutamisel jääb vastavale mikrokontrolleri viigule ikkagi 0 V lähedane pinge.
Lülitid asuvad viikudel PC0, PC1 ja PC2. Lülitite oleku lugemiseks tuleb mikrokontrolleri vastavad viigud määrata sisendiks. AVR siseseid pull-up takisteid ei pea tööle rakendama, sest, nagu öeldud, viikudel juba on välised takistid. Kui nupp alla vajutada, on viigule vastaval siinil biti väärtus 0, kui nupp lahti lasta, siis väärtus 1. Selleks et näha, kas mikrokontroller sai nupuvajutusest aru, võib kasutada plaadil olevaid LED indikaatoreid.
Nuppude kasutamise näidiskood põhineb Kodulabori viikude teegil, mida on tutvustatud valgusdioodi näites.
// // Kodulabori Digitaalse sisend-väljundmooduli // nuppude testimise programm. // #include <homelab/pin.h> // // LED-ide ja nuppude viikude määramine // pin leds[3] = { PIN(C, 5), PIN(C, 4), PIN(C, 3) }; pin buttons[3] = { PIN(C, 2), PIN(C, 1), PIN(C, 0) }; // // Põhiprogramm // int main(void) { unsigned char i; // LED-ide viikude väljundiks ja nuppude // viikude sisendiks seadmine for (i = 0; i < 3; i++) { pin_setup_output(leds[i]); pin_setup_input(buttons[i]); } // Lõputu tsükkel while (true) { // Igale nupule vastab üks LED, // mis süttib nuppu alla vajutades for (i = 0; i < 3; i++) { pin_set_to(leds[i], pin_get_value(buttons[i])); } } }
Toodud näites on LED-id ja nupud defineeritud massiivina – see võimaldab neid kasutada for tsüklis. Programmi käivitamisel määratakse LED-ide viigud väljundiks ja nuppude viigud sisendiks. Programmisiseses lõputus tsüklis toimub pidev nuppude oleku pärimine ja neile vastavate LED-ide oleku määramine. Esimene nupp süütab rohelise LED-i, teine kollase ja kolmas punase.
Vajalikud teadmised: [HW] Kasutajaliidese moodul, [AVR] Digitaalsed sisendid-väljundid, [LIB] Sisend-väljundviigud, [LIB] Viide, [PRT] Lüliti
Nii nagu lüliteid tutvustavas peatükis öeldud, eksisteerib mehhaaniliste lülititega kontaktide põrkumise probleem. Kuna kontaktid on tehtud metallist, millel on teatav elastsus, siis kontaktide ühendamise või lahti-ühendamise hetkel need põrkuvad ning tulemusena tekib hulga väärlülitusi. Lülituste arv ja kestus sõltub lülitist, kuid enamasti jääb see mõne millisekundi piiresse. Kui lülitit kasutatakse mõne elektriseadme käivitamiseks, siis pole see suur probleem, kuid kui lüliti on kasutusel seadme juhtimiseks, võib mitmekordne lülitumine probleemiks olla.
Põhiline kontaktide põrkumisest tekkinud väärlülitusi välistav meetod on filtreerimine. Filtreerida saab nii elektriliselt kui ka tarkvaraliselt. Elektriliseks filtreerimiseks tuleb lüliti ühendada läbi madalpääsu filtri – näiteks RC filter - mis silub pingemuutusi ja sellest tulenevalt ei omanda mikrokontrolleri viik hetkelisi väärtusi. Tarkvaraline filtreerimine toimub põhimõttel, et viigu, kuhu lüliti on ühendatud, väärtust loetakse mitmel korral ja kui kõikidel kordadel on viigu väärtus sama, siis sellest järeldatakse, et lüliti omab kindlat asendit ning tegu pole põrkumisega. Igasugusel filtreerimisel peab aga arvestama viitega, mis tekib oleku määratlemisel.
Kodulabori lülititel ei kasutada elektrilist filtreerimist, sest siis ei saaks harjutada tarkvaralist väärlülituste elimineerimise ülesannet. Harjutus koosneb kahest osast. Esimese ülesande eesmärk on demonstreerida Digitaalse sisend-väljundmooduli nuppude kontaktide põrkumist. Selleks on järgmine programm, mis iga nupuvajutuse peale paneb põlema järgmise LED-i. Väär-nupuvajutuste tõttu süttivad LED-id aga mitmeid kordi ja näib, et lausa suvaliselt.
// // Kodulabori digitaalse sisend-väljundmooduli // nuppude kontaktide põrkumise demonstreerimise programm. // #include <homelab/pin.h> // // LED-ide ja nupu viikude määramine // pin leds[3] = { PIN(C, 5), PIN(C, 4), PIN(C, 3) }; pin button = PIN(C, 0); // // Põhiprogramm // int main(void) { unsigned char new_value, old_value = 0; unsigned char index, counter = 0; // LED-ide viikude väljundiks seadmine for (index = 0; index < 3; index++) { pin_setup_output(leds[index]); } // Nupu viigu sisendiks määramine pin_setup_input(button); // Lõputu tsükkel while (true) { // Nupu oleku lugemine new_value = pin_get_value(button); // Kontroll, kas nupp vajutati alla, // ehk kas uus olek on 1 ja vana 0 if ((new_value) && (!old_value)) { // Loenduri suurendamine ja mooduli 3 võtmine counter = (counter + 1) % 3; // Loenduri väärtusele vastava LED-i süütamine for (index = 0; index < 3; index++) { pin_set_to(leds[index], index != counter); } } // Peame vana olekut meeles old_value = new_value; } }
Tarkvaraliseks filtreerimiseks on mitmeid meetodeid. Seda võib teha lihtsalt ja keeruliselt, mõlemal variandil on oma eelised ja puudused. Kui programm on selline, et nupuvajutusi oodatakse harva, võib pärast nupu allavajutamise registreerimist lisada pika pausi, mis välistab reageerimise põrkumisest tekkinud lisalülitustele. Samas tuleb sellise lahenduse puhul arvestada, et kui kasutaja hoiab nuppu pikalt all, reageerib programm ka nupu lahtilaskmisel tekkinud väärlülitustele.
Töökindlam on programm, mis kontrollib nupu olekut teatud aja jooksul mitu korda (mida rohkem ja mida pikema aja jooksul, seda kindlam). Järgnevalt on toodud Digitaalse sisend-väljundmooduli nupu filtreeritud väärtuse lugemise funktsioon:
// // Funktsioon mõne IO laiendusplaadi lüliti filtreeritud väärtuse lugemiseks // unsigned char pin_get_debounced_value(pin button) { unsigned char buffer = 0xAA; unsigned char timeout = 100; // Ootame, kuni nupu olek on selgunud või oleku selgitamine aegunud while (timeout-- > 0) { // 8-kohalise (bitise) olekupuhvri pidamine // Kõik eelmised olekud (bitid) nihutatakse vasakule // ja paremale lisatakse uus olek (bitt). buffer <<= 1; buffer |= (pin_get_value(button) ? 0x01 : 0x00); // Kui kõik 8 bitti on kõrged, siis // nupp on kindlasti alla vajutatud if (buffer = 0xFF) { return 1; } // Kui kõik 8 bitti on madalad, siis // nupp on kindlasti üleval if (buffer = 0x00) { return 0; } // Paus 1 millisekund // See funktsioon sisaldub Kodulabori teegis sw_delay_ms(1); } // Kui olekut ei õnnestunud välja selgitada, siis oletame, // et nuppu ei vajutatud return 0; }
See funktsioon kasutab viite tekitamise funktsiooni, millest räägib lähemalt vastav harjutusülesanne. Siinkohal pole viite funktsiooni kohta vaja suurt midagi teada peale selle, et see tekitab 1-millisekundilise viite iga nupu oleku lugemise tsükli lõpus. Kui nupp on kaheksa lugemise korral samas asendis, tagastab see loetud asendi. Kogu protseduur võib nupu ebastabiilsuse korral kesta kuni 100 ms. Funktsioon sisaldub juba viikude teegis, nii et näite läbimiseks ei pea seda oma programmi lisama. Selle proovimiseks tuleb ülesande esimest poolt natukese muuta – kaasata programmi viite tekitamise teek ja kohas, kus nupu väärtust otse loeti, kasutada filtriga funktsiooni. Tulemus on järgmine:
// // Kodulabori digitaalse sisend-väljundmooduli // nuppude kontaktide põrkumise filtreerimise programm. // #include <homelab/delay.h> #include <homelab/pin.h> // // LED-ide ja nupu viikude määramine // pin leds[3] = { PIN(C, 5), PIN(C, 4), PIN(C, 3) }; pin button = PIN(C, 0); // // Põhiprogramm // int main(void) { unsigned char new_value, old_value = 0; unsigned char index, counter = 0; // LED-ide viikude väljundiks seadmine for (index = 0; index < 3; index++) { pin_setup_output(leds[index]); } // Nupu viigu sisendiks määramine pin_setup_input(button); // Lõputu tsükkel while (true) { // Nupu oleku lugemine new_value = pin_get_debounced_value(button); // Kontroll, kas nupp vajutati alla, // ehk kas uus olek on 1 ja vana 0 if ((!new_value) && (old_value)) { // Loenduri suurendamine ja mooduli 3 võtmine counter = (counter + 1) % 3; // Loenduri väärtusele vastava LED süütamine for (index = 0; index < 3; index++) { pin_set_to(leds[index], index != counter); } } // Peame vana olekut meeles old_value = new_value; } }
Kui nüüd programmi proovida, siis LED-id süttivad täpselt sellises järjekorras nagu kasutaja nupplülitit vajutab.
Eesmärgiks on koostada programm, mis täidab kirjeldatud ülesannet.
Käesolev peatükk tutvustab mikrokontrollerite ajastuse võimalusi - taimereid ja viiteid. Need on abiks rakendustes, kus on vaja mõõta aega, tekitada pause või protsesse täpselt juhtida. Oma olemuselt on taimerid ja viited väga sarnased, kuid on ka selgesti eristatavaid erinevusi. Taimerid on mikrokontrolleri füüsilised moodulid, mis töötavad mikrokontrolleri protsessorist sõltumatult, viited on aga tarkvaralised programmilõigud, mis just nimelt kulutavad protsessori tööaega. Sarnasuse poole pealt töötavad nad mõlemad aga mikrokontrolleri töötakte lugedes.
Mõlemal meetodil on omad head ja vead, millest lähemalt räägivad nende kohta käivad harjutused. Korrektsuse huvides võib öelda, et algselt olid taimerid ikkagi eraldiseisvad integraallülitused elektriskeemis, mitte osa mikrokontrollerist. Eraldiseisvad taimerite kiibid pole ka tänapäeval kuhugi kadunud, sest mõnes rakenduses pole mikrokontrollerit ennast vajagi ja mõned taimerid on võimekamad kui mikrokontrolleri sisesed taimerid.
Taimerid on ka lihtsast aja loendamise seadmest arenenud keerukateks signaalide vastuvõtmise või genereerimise süsteemideks. Nad moduleerivad ja demoduleerivad signaale ning nad on võimelised taktsignaali kordistama või jagama. On olemas ka spetsiaalsed aeg-digitaalmuundurid (TDC, inglise keeles time-to-digital converter), mis suudavad registreerida aega pikosekundites. Siinkohal piirduvad harjutused siiski lihtsamate taimeritega.
Vajalikud teadmised: [HW] Kontrollermoodul, [AVR] Arhitektuur, [LIB] Sisend-väljundviigud, [LIB] Viide
Tihti on mikrokontrollerite programmis vaja tekitada viiteid, et tegevusi ajastada või nende lõppu oodata. Üks idee poolest lihtsamaid meetodeid mikrokontrolleri töös paus tekitada on selle protsessor mingi muu tegevusega üle koormata - näiteks panna see lugema suuri arve. Protsessori taktsagedusest saab välja arvutada, mitmeni see arve loendama peaks, et kindlat ajalist viidet tekitada. Mingi arvu loendamine nullist protsessori taktsageduse väärtuseni hertsides tekitaks teoreetiliselt viite üks sekund. Praktikas see erinevatel põhjustel päris nii lihtne ei ole.
Kui mikrokontrolleri protsessor arvutab arvudega, mille kahendkuju on sama lai kui selle sisemine siin (AVR puhul 8-bitti), siis protsessoritel võtab üks aritmeetiline tehe, näiteks arvu liitmine ühega, aega 1 protsessori töötakt. Selleks, et arvutada tuhandete või miljonitega, peab arv olema 16- või 32-bitine ja nende arvutamiseks kulub 8-bitistel protsessoritel rohkem kui 1 töötakt. Niisiis, suurte arvude puhul peab tundma protsessori sisemust - täpsemalt selle käsustikku.
Kuna kõrgtaseme keeles (näiteks C-keeles) programmeerides ei kirjutata programmi otse käsustiku baasil, peab tarkvaralise viite tekitamiseks tundma ka kompilaatorit, mis programmi masinkoodi teisendab. Just sellest sõltub, mitu instruktsiooni (ja sellest tulenevalt mitu takti) kulub aritmeetilisteks arvutusteks. Keerukust lisab veel asjaolu, et kompilaator võib programmi masinkoodi teisendada mitut moodi - näiteks tehes masinkoodi võimalikult mälusäästlikuks või võimalikult kiiresti täidetavaks. Neid kompilaatori tegevusi nimetatakse optimeerimiseks. Erinevate optimeerimise režiimidega tulevad ka tarkvaralise viite masinkood ja selle ajaline kestus erinevad.
Järgnevalt on toodud näide tarkvaralise viite tekitamisest AVR mikrokontrolleriga. Kirjutatud on C-keele programmilõik, mis loendab for-tsüklis muutujat x nullist sajani. Iga tsükli sees toimub ühe mittemidagitegeva tühiinstruktsiooni täitmine. Seda on seal vaja, kuna tsükli sisu tühjaks jättes optimeerib kompilaator tsükli programmist üldse välja, sest see on tema arvates kasutu.
unsigned char x; // Tsükkel seni kuni x on 100 for (x = 0; x < 100; x++) { // Tühiinstruktsiooniga nop asm volatile ("nop"); }
Siinkohal on aga toodud sama C-keele programmilõik pärast kompileerimist. Vasakpoolsed 2 heksadetsimaalarvu on masinkood ja paremal on assemblerkeeles käsk koos operandi(de)ga. Masinkood ja assemblerkeel on üks-üheselt seotud, assembler on lihtsalt masinkoodi inimesele loetaval kujul esitamiseks. Kompileerimisel on kasutatud programmi pikkuse optimeerimist (kompilaatori parameeter -Os).
80 e0 ldi r24, 0x00 ; r24 registrisse arvu 0 laadimine 00 00 nop ; Tühioperatsioon 8f 5f subi r24, 0xFF ; r24 registrist 255 lahutamine, ehk +1 liitmine 84 36 cpi r24, 0x64 ; r24 registri võrdlemine arvuga 100 e1 f7 brne .-8 ; Kui võrdlus oli väär, siis siire 8 baiti tagasi
Kompileeritud kujul on näha, mis tegelikult C-keele tsüklist saab, ja selle järgi saab arvutada, mitu takti ühe tsükli perioodi täitmiseks kulub. Infot instruktsioonide toime ja tööaja kohta leiab AVR käsustiku andmelehest. Antud näites kulub ühe tsükli perioodis 4 instruktsiooni täitmiseks 4 takti, sest kõik instruktsioonid võtavad ühe töötakti. Lisaks kulub enne tsüklit 1 takt laadimisinstruktsiooni jaoks ja tsüklist väljudes 1 lisatakt. Oletades, et kontrolleri töötakt on 14,7456 MHz, võib välja arvutada kogu programmilõigu tekitatud ajalise viite:
(1 + 100 ⋅ 4 + 1) / 14745600 = 27,26 μs
Näites tekitatud viide on mikrosekundites ja kasutatav muutuja on 8-bitine, seega on ka masinkood üsna lihtne. Selleks, et tekitada pausi millisekundites, on vaja loendada palju suuremaid arve ja siis läheb ka masinkood pikemaks. Võib kasutada ka üksteise sees töötavaid tsükleid, kuid selle meetodi puhul pole kogu viide lineaarses sõltuvuses tsüklite arvust, sest iga tsükli tasemega tekivad pisikesed lisaviited.
Käesoleva harjutuse eesmärk ei ole siiski masinkoodi tasandil täpset tarkvaralist viidet tekitada, sest see on üsna peen töö ja pealegi on viite tekitamiseks avr-libc ja Kodulabori teegis juba funktsioonid olemas. Need kasutatakse ka järgmistes näidetes.
Tarkvaralise viite puhul on aga oluline teada, et hoolimata oma põhimõttelisest lihtsusest on see äärmiselt ebaefektiivne meetod energiatarbe seisukohast. Kõigil neil taktidel, mil mikrokontroller tegeleb kasutu loendamisega, kulub energiat. Patareidega rakenduses ei ole seega soovitatav pikki tarkvaralisi viiteid teha, vaid tuleks kasutada raudvaralisi taimereid, mis töötavad iseseisvalt ning äratavad protsessori uneolekust üles, kui on vaja tööd jätkata.
Järgnev programmikood käib tarkvaralise viite funktsiooni sw_delay_ms kohta, mis tekitab parameetriga count etteantud viite millisekundites. Funktsioon kasutab omakorda avr-libc teegi poolenisti assemblerkeeles kirjutatud funktsiooni _delay_ms. Põhjus, miks harjutuses pole kohe _delay_ms kasutatud, on selles, et _delay_ms puhul võivad pikkade viidetega probleemid tekkida. sw_delay_ms funktsioon võimaldab aga probleemideta kuni 65535 ms viidet.
// // Tarkvaraline viide millisekundites // void sw_delay_ms(unsigned short count) { // Viite muutuja nullini loendamine while (count-- > 0) { // 1ms viide spetsiaalse funktsiooniga _delay_ms(1); } }
Toodud funktsiooni kasutamiseks on järgnev programm, mis tekitab lõputus tsüklis kaks viidet: 100 ms ja 900 ms. Lühema viite jooksul LED põleb ja pikema ajal on kustunud - tulemusena LED perioodiliselt vilgatab.
// // Kodulabori tarkvaralise viite demonstratsioonprogramm. // Programm vilgutab ~1 sekundi järel hetkeks LED-i. // #include <homelab/pin.h> #include <homelab/delay.h> // // Test LED-i viigu määramine // pin debug_led = PIN(B, 7); // // Põhiprogramm // int main(void) { // LED-i viigu väljundiks seadmine pin_setup_output(debug_led); // Lõputu tsükkel while (true) { // LED-i süütamine pin_clear(debug_led); // Tarkvaraline paus 100 millisekundit sw_delay_ms(100); // LED kustutamine pin_set(debug_led); // Tarkvaraline paus 900 millisekundit sw_delay_ms(900); } }
Kuigi näib, et LED vilgatab tõesti 1 sekundi järel, on aeg tegelikult siiski natuke pikem, sest LED-i ja viite funktsioonide väljakutsumised võtavad ka mõned mikrokontrolleri taktid aega.
Vajalikud teadmised: [HW] Kontrollermoodul, [AVR] Loendurid/Taimerid, [LIB] Sisend-väljundviigud, [LIB] Viide, [LIB] Taimerid, [PRT] Tarkvaraline viide
Tarkvaraline viide pole ainus meetod pausi tekitamiseks. Sama asja saab teha ka taimeriga. Taimer on riistvaraline kindla sagedusega suurenev või vähenev loendur. Loenduri taktsignaali saab enamasti tekitada mikrokontrolleri töötaktist või mingist välisest taktist. Taktsignaali sagedust saab üldjuhul ka mingi teguriga jagada väiksem taktsageduse saavutamiseks - seda tehakse taktijaguriga, mida inglise keeles nimetatakse prescaler. Oluline on siinkohal siiski fakt, et fikseeritud taktsagedusega loenduri väärtus on lineaarses sõltuvuses ajast. Aja saab välja arvutada, korrutades loenduri taktisignaali perioodi loenduri väärtusega.
AVR loendurit saab panna teavitama loenduri ületäitumisest (inglise keeles overflow) või kindla väärtuse saavutamisest (inglise keeles compare match). Ületäitumine tekib hetkel, kui loendur on omistanud maksimaalse võimaliku väärtuse ja alustab uuesti nullist loendamist. Kindla väärtuse saavutamise puhul aga toimub loenduri suurendamise hetkel selle uue väärtuse võrdlemine kasutaja poolt määratud väärtusega. Sündmuse tekkimise korral seatakse AVR olekuregistrites vastavad bitid automaatselt kõrgeks.
Selleks, et taimeriga viide tekitada, piisabki vaid loenduri seadistamisest ja olekubiti kõrgeks minemise ootamisest. Erinevalt tarkvaralisest viitest ei sõltu taimerite töö kompilaatorist, mis teeb nende kasutamise töökindlamaks. Samas võib AVR loendurite mitmekesisuse (või ka segasuse) tõttu nende seadistamine üsna tülikas tunduda. Olenevalt mikrokontrolleri taktsignaalist võib ka juhtuda, et see ei jagu täpselt soovitud viite perioodiga ja viide ei ole täpne.
Allpool olev programmikood on taimeril põhinev viitefunktsioon, mida on natuke lihtsustatud. Loendamise põhimõte on sama, mis tarkvaralise viite funktsioonilgi - tekitatakse soovitud arv 1 ms pikkuseid viiteid. Viite tekitamiseks on kasutusel ATmega128 8-bitine loendur 0. Eelnevalt on juba välja arvutatud, et 14,7456 Mhz taktsageduse puhul peab loenduri taktsignaal olema vähemalt 64-ga jagatud, et 1 ms jooksul 8-bitine loendur üle ei täituks. See, mis väärtust loendur omama peab, et ületäitumine toimuks 1 ms järel, on esitatud avaldise kujul ja omistatud muutujale timer_start. F_CPU on makro-keele konstant, mis näitab taktsagedust hertsides. Nimetatud taktsageduse puhul peaks loenduri väärtus 25,6 olema, kuid kuna murdarve kasutada ei saa, siis loenduri algväärtuseks saab 26. Siin tekib paraku ka viga viite ajas, kuid see on üsna väike (-1,7 μs).
Tsüklis toimub loenduri algväärtustamine ja ületäitumise lipukese nullimine (sellesse 1 kirjutades). Seejärel oodatakse, kuni loendur loendab algväärtusest 256-ni, ehk ületäitumiseni. Ületäitumise hetkel läheb ületäitumise lipuke kõrgeks ja 1 ms viide ongi toimunud. Funktsiooni lõpus taimer peatatakse.
// // Riistvaraline viide millisekundites // void hw_delay_ms(unsigned short count) { // Taimeri algväärtuse arvutamine register unsigned char timer_start = 256 - F_CPU / 1000 / 64; // Taimeri käivitamine timer0_init_normal(TIMER0_PRESCALE_64); // Viite muutuja nullini loendamine while (count-- > 0) { // Taimeri algväärtustamine timer0_set_value(timer_start); // Ületäitumise lipukese nullimine timer0_overflow_flag_clear(); // Ületäitumise ootamine while (!timer0_overflow_flag_is_set()) { asm volatile ("nop"); } } // Ületäitumise lipukese nullimine timer0_overflow_flag_clear(); // Taimeri peatamine timer0_stop(); }
Esitatud viite funktsioon kasutab aga taimerite teeki, mille lähtekood näeb välja järgmine:
// // Taimer 0 taktijaguri valiku tüüp // typedef enum { TIMER0_NO_PRESCALE = 0x01, TIMER0_PRESCALE_8 = 0x02, TIMER0_PRESCALE_32 = 0x03, TIMER0_PRESCALE_64 = 0x04, TIMER0_PRESCALE_128 = 0x05, TIMER0_PRESCALE_256 = 0x06, TIMER0_PRESCALE_1024 = 0x07 } timer0_prescale; // // Taimer 0 normaalrežiimi seadistamine // inline void timer0_init_normal(timer0_prescale prescale) { TCCR0 = prescale & 0x07; } // // Taimer 0 peatamine // inline void timer0_stop() { TCCR0 = 0x00; } // // Taimer 0 loenduri väärtuse määramine // inline void timer0_set_value(unsigned char value) { TCNT0 = value; } // // Taimer 0 ületäitumise lipukese nullimine // inline void timer0_overflow_flag_clear(void) { bit_set(TIFR, TOV0); } // // Taimer 0 ületäitumise lipukese oleku lugemine // inline bool timer0_overflow_flag_is_set(void) { return (bit_is_set(TIFR, TOV0) ? true : false); }
Järgnevalt on toodud samasugune programm nagu tarkvaralise viite näiteski. Lühemal 100 ms poolperioodil LED süüdatakse, pikemal 900 ms poolperioodil kustutatakse. Tulemusena vilgatab LED iga sekundi järel. Paraku pole ka selles näites periood täpselt 1 sekund, sest programmi muude funktsioonide täitmine igas tsüklis võtab samuti aega. Täpseks ajastuseks tuleb kasutada 16-bitist taimerit koos katkestustega.
// // Kodulabori riistvaralise viite demonstratsioonprogramm. // Programm vilgutab ~1 sekundi järel hetkeks LED-i. // #include <homelab/pin.h> #include <homelab/delay.h> // // Test LED viigu määramine // pin debug_led = PIN(B, 7); // // Põhiprogramm // int main(void) { // LED-i viigu väljundiks seadmine pin_setup_output(debug_led); // Lõputu tsükkel while (true) { // LED-i põlema panek pin_clear(debug_led); // Riistvaraline paus 100 millisekundit hw_delay_ms(100); // LED-i kustutamine pin_set(debug_led); // Riistvaraline paus 900 millisekundit hw_delay_ms(900); } }
Vajalikud teadmised: [HW] Kontrollermoodul, [HW] Kasutajaliidese moodul,
[AVR] Katkestused, [AVR] Loendurid/Taimerid, [LIB] Sisend-väljundviigud, [LIB] Viide,
[LIB] Taimerid, [PRT] Tarkvaraline viide
Käesoleva praktilise harjutuse eesmärk on demonstreerida katkestuste kasutamist loendurite näitel. Katkestused on mikrokontrolleris esinevatele sündmustele reageerivad programmilõigud. Katkestusi kasutatakse tavaliselt kiireks sündmusele reageerimiseks, kuid neid võib kasutada ka mitme paralleelse protsessi või täpset ajastust nõudvate tegevuste täitmiseks ning voolu säästmiseks. Näiteks on katkestuste abil võimalik panna vilkuma LED, mille vilkumise sagedus ei sõltu sellest, mis programmis parasjagu toimub.
Järgnev programm näitab, kuidas seadistada loendurit tekitama katkestust. Programmis on kasutusel kaks Digitaalse sisend-väljundmooduli LED-i, millest punase olekut muudetakse perioodiliselt tarkvaralise viitega ja roheline, mille olekut muudetakse katkestuse tekkimisel. Tarkvaralise viitega LED-i vilgutamise kohta on olemas eraldi harjutus ja seda siinkohal selgitatud pole. Põhieesmärk on selgitada loendurite teegi ja katkestuste kasutamist.
Programmi alguses toimub 16-bitise loendur/taimer 1 seadistamine funktsiooniga timer1_init_ctc. Selle funktsiooni abil seatakse loendur CTC (inglise keeles clear timer on compare match) režiimi, kus taimeri maksimaalseks väärtuseks pole mitte 216 - 1, vaid see on valitav. Antud juhul määratakse maksimaalseks väärtuseks ICR1 registri väärtus. Loenduri jaguriks on 1024 ja ICR1 väärtuseks 14400, mille tulemusena 14,7456 Mhz taktsageduse puhul on loenduri perioodiks täpselt 1 sekund. Seda on lihtne arvutada valemist:
f = 14745600 Hz / 1024 / 14400 = 1
Pärast loendur 1 maksimaalse väärtuse saavutamise katkestuse lubamist tuleb katkestuse tekkimine lubada ka globaalselt ehk üle kogu mikrokontrolleri. Globaalseks katkestuste lubamiseks on funktsioon sei ja keelamiseks cli. Nende funktsioonide ja katkestuste programmilõigu defineerimiseks peab programmi kaasama ka avr/interrupt.h päisefaili. Katkestuse programmilõik defineeritakse makrofunktsiooniga ISR, mille parameetriks on katkestuse vektori nimi. Nimetatud seadistuste juures on loendur 1 maksimaalse väärtuse saavutamise katkestuse vektoriks TIMER1_CAPT_vect.
// // Kodulabori loenduri katkestusega vilkuva LED-i näide. // Võrdluseks katkestusega vilkuvale LED-ile // töötab paralleelselt ka tarkvaralise viitega vilkuv LED. // #include <homelab/pin.h> #include <homelab/delay.h> #include <homelab/timer.h> #include <avr/interrupt.h> // // LED-ide viikude määramine // pin led_red = PIN(C, 5); pin led_green = PIN(C, 3); // // Katkestus // ISR(TIMER1_CAPT_vect) { // Rohelise LED oleku muutmine pin_toggle(led_green); } // // Põhiprogramm // int main(void) { // LED-ide viikude väljundiks seadmine pin_setup_output(led_red); pin_setup_output(led_green); // Taimeri seadistamine CTC režiimi timer1_init_ctc( TIMER1_PRESCALE_1024, TIMER1_CTC_TOP_ICR); // Taimeri maksimaalne väärtus 14400, mis // teeb perioodi pikkuseks 1s // Valem: 14,7456Mhz / 1024 = 14400 timer1_set_input_capture_value(14400); // Väärtuse saavutamise katkestuse lubamine timer1_input_capture_interrupt_enable(true); // Globaalne katkestuste lubamine sei(); // Lõputu tsükkel while (true) { // Tarkvaraline paus 1000 millisekundit sw_delay_ms(1000); // Punase LED oleku muutmine pin_toggle(led_red); } }
Programmi käivitades on näha, et hoolimata sellest, mida mikrokontroller põhiprogrammis teeb, toimuvad katkestused ja roheline LED vilgub.
Kui programmil lasta töötada mõni minut, tuleb välja oluline aspekt, mida tarkvaralise viite harjutuses nii lihtsalt näha polnud. Kuigi punase LEDi vilgutamise viide on 1000 ms, siis tegelik aeg, mis kulub iga tsükli täitmiseks, on natuke suurem. Põhjus on selles, et ka LED-i oleku muutmine, viite funktsiooni väljakutsumine ja tsükli täitmine võtavad protsessoril mõned taktid täitmise aega. Tulemusena jääb punase LED-i vilkumine rohelise LED-i vilkumisest pidevalt maha. Just sel põhjusel ei ole soovitatav ka kellaaja loendureid ja muid täpselt ajastatud tegevusi teha viitega, vaid loenduri katkestustega.
Eesmärgiks on koostada programm, mis täidab kirjeldatud ülesannet.
Üks lihtsamaid meetodeid veendumaks mikrokontrolleri töö korrektsuses on lisada programmi koodilõik, mis vilgutab LED-i või mitut kindla tegevuse korral. Tihtipeale jääb sellest aga väheks, sest vaja oleks edastada rohkem infot kui LED-iga võimalik, ning mõni rakendus eeldab kasutajaliidest, kus kuvatakse tekste või numbreid. Siinkohal tulevad appi kõiksugu indikaatorid ja ekraanid, kus saab kuvada numbreid, tekste või lausa pilte. Arvuti monitor on üks tuntumaid info kuvamise seadmeid, mille kasutamises tüüpiline programeerija vaevalt et midagi erilist näeb, kuid mikrokontrolleritega tuleb iga piksli ekraanile saamisega omajagu vaeva näha.
Järgnevad peatükid tutvustavad lihtsamat liiki näidikuid ja ekraane - LED segmentidega indikaatorit ja kahte liiki monokromaatilist LCD ekraani. Peale nende kasutatakse mikrokontrolleritega aktiivselt ka LED maatrikseid ja tänapäeval levinud värvilisi orgaanilisi LED (OLED) ekraane. Kunagi olid levinud ka hõõgniidiga numberindikaatorid, kus iga numbri jaoks oli eraldi helendav hõõgniit. Olemas on ka elektromehaanilised ekraanid, kus erinevat värvi tahkudega segmente pööratakse füüsiliselt. Viimase ajal on järjest populaarsemaks muutumas elektrooniline paber, mis imiteerib juba trükist. Kui esmased e-paberid (lühend elektroonilisest paberist) koosnesid erinevat värvi külgedega kuulikestest, mida pöörati elektriväljas, siis uuemad e-paberid sisaldavad aga pisikesi kapsleid, kus kahe värvi erinevalt laetud osakesi mõjutatakse elektriväljaga kas põhja vajuma või pinnale tõusma. Viimased nimetatud näidikud ja ekraanid on toodud infoks näitamaks visualiseerimise erinevaid võimalusi, kuid need lähemat käsitlemist Kodulabori kontseptsioonis ei leia.
Vajalikud teadmised: [HW] Kasutajaliidese moodul, [LIB] Viide,
[LIB] 7-segmendiline LED indikaator, [PRT] Valgusdiood
7-segmendiline LED numberindikaator on seitsmest number 8-kujuliselt paigutatud valgusdioodist koosnev näidik. Vastavaid LED-e (segmente) süüdates või kustutades saab nendega kuvada numbreid nullist üheksani ning mõningaid tähti.
Elektriliselt on kõigi LED-ide anoodid ühendatud ühise anoodi viiguga ca. LED-e süüdatakse nende katoode (a, b, c…) lülitades. Olemas on ka vastupidi ühendusi, kus indikaatoritel on ühine katood cc. Tavaliselt kasutatakse mitut numberindikaatorit, et kuvada mitmekohalisi arve - selleks puhuks on indikaatorid varustatud ka koma(punkti) segmendiga dp. Kokkuvõttes on ühel indikaatoril siiski 8 segmenti, kuid nimetatakse neid ikkagi numbrisegmentide arvu järgi 7-segmendilisteks.
LED numberindikaatoreid on lihtne kasutada, sest neid võib juhtida kas või otse mikrokontrolleri viikudelt, kuid on ka spetsiaalseid ajureid, mis võimaldavad numberindikaatorit juhtida vähemate mikrokontrollerite viikude arvuga. LED numberindikaatoreid on erinevat värvi, nad võivad olla väga eredad ja väga suured. Kogu ladina tähestiku kuvamiseks on olemas ka lisasegmentidega indikaatoreid.
Digitaalse mooduli plaadil on üks 7-segmendiline LED numberindikaator. Seda juhitakse läbi järjestikliidesega ajuri A6275. Ajuri järjestikliides on sarnane SPI-ga, kus kasutatakse ka taktsignaali ja andmesignaali. Erinevalt SPI-st pole kasutusel kiibi valikut (inglise keeles chip-select), kuid selle asemel on andmete lukustussignaal (inglise keeles latch). Nimetatud kolm liini on ühendatud ATmega128-ga järgnevalt:
Andmed edastatakse bitthaaval andmeviigu kaudu. Iga kord, kui taktsignaal kõrgeks läheb, nihutatakse nihkeregistri sisu paremale ja kõige vasakpoolsemasse pesasse loetakse andmeviigult tulev bitt. Niiviisi laaditakse nihkeregistrisse 8 bitti. Kui lukustussignaal kõrgeks seada, laetakse nihkeregistri väärtus lukustusregistrisse, kus see jääb püsima kuni uue laadimiseni. Iga lukustusregistri pesa (bitt) on läbi voolulülituse seotud ühe numberindikaatori segmendiga. Segment põleb kõrge bitiväärtuse korral.
Numbrite kuvamiseks Kodulabori Digitaalse mooduli indikaatoril on Kodulabori teeki kirjutatud järgnev funktsionaalsus:
// // Viikude seadistus // static pin segment_display_latch = PIN(G, 2); static pin segment_display_data_out = PIN(C, 6); static pin segment_display_clock = PIN(C, 7); // // Märgikaart. // Bitid tähistavad segmente. Madalaim järk A, kõrgeim DP. // static const unsigned char segment_char_map[11] = { 0b00111111, 0b00000110, 0b01011011, 0b01001111, 0b01100110, 0b01101101, 0b01111100, 0b00000111, 0b01111111, 0b01100111, 0b01111001 // E like Error }; // // 7-segmendilise indikaatori käivitamine // void segment_display_init(void) { // Set latch, data out and clock pins as output pin_setup_output(segment_display_latch); pin_setup_output(segment_display_data_out); pin_setup_output(segment_display_clock); }
// // 7-segmendilisel indikaatoril numbri kuvamine // void segment_display_write(unsigned char digit) { unsigned char map; signed char i; // Numbri kontroll if (digit > 9) { digit = 10; } // Number segmentide kaardiks. map = segment_char_map[digit]; // Lukustussignaal maha pin_clear(segment_display_latch); // Bittide saatmine. Kõrgeim järk esimesena. for (i = 7; i >= 0; i--) { // Viigu seadmine vastavalt kaardi biti väärtusele pin_set_to(segment_display_data_out, bit_is_set(map, i)); // Taktsignaal kõrgeks hetkeks pin_set(segment_display_clock); _delay_us(1); // Taktsignaal madalaks pin_clear(segment_display_clock); _delay_us(1); } // Lukustussignaal peale pin_set(segment_display_latch); }
Numbrite ja “E” tähe kuvamiseks segmentidena on loodud konstantne massiiv segment_char_map, kus iga segmendi põlemine on tähistatud bitiga 1 ja kustumine bitiga 0. Bitid madalamast kõrgemaks (binaarkujul paremalt vasakule) tähistavad segmente A, B, C, D, E, F, G ja DP. Ajuri juhtliides on teostatud tarkvaralise SPI-ga ehk andmesideviike programmis tarkvaraliselt juhtides. Funktsiooniga segment_display_init seatakse kõik kolm viiku väljundiks. Märgi kuvamiseks on segment_display_write funktsioon, mis leiab massiivist märgi segmendikaardi ja edastab kõigi segmentide väärtused bitthaaval ajurile. Taktsignaali sageduseks on tarkvaraliste pausidega saadud ligikaudu 500 kHz.
Järgnevalt on toodud konkreetsem numberindikaatori kasutamise näiteprogramm. Programmis kasutatakse teegi eelnevalt kirjeldatud funktsioone. Programm loeb ligikaudu sekundilise intervalliga numbreid nullist üheksani. Selline loendamine on saavutatud suuremast arvust mooduli võtmisega.
// // Kodulabori sisend-väljundmooduli 7-segmendilise // LED indikaatori näidisprogramm // #include <homelab/module/segment_display.h> #include <homelab/delay.h> // // Põhiprogramm // int main(void) { int counter = 0; // 7-segmendilise indikaatori seadistamine segment_display_init(); // Lõputu tsükkel while (true) { // Loenduri üheliste väärtuse näitamine segment_display_write(counter % 10); // Loendamine väga pikalt counter++; // Paus 1 sekund sw_delay_ms(1000); } }
Vajalikud teadmised: [HW] LCD moodul, [LIB] Alfabeetiline LCD, [LIB] Viide,
[PRT] Perioodiline katkestus
Alfabeetiline LCD on vedelkristall-ekraan (inglise keeles liquid crystal display), mis on ette nähtud tähtede ja numbrite kuvamiseks. Inglise keeles nimetatakse seda kui alphanumeric LCD. Lihtsamates vedelkristall-ekraanides kasutatakse läbipaisvate elektroodide vahele paigutatud vedelat kristalli, mis muudab elektriväljas läbiva valguse polarisatsiooni. Elektroode katavad veel polarisatsioonifiltrid, mis tagavad, et kogu ekraani saab läbida vaid ühtpidi polariseeritud valgus. Kui vedelkristall elektrivälja mõjul polarisatsiooni muudab, siis valgus ekraani või selle osa (segmenti) läbida ei saa ning see paistab tumedana.
Põhiline iseloomustaja on alfabeetilise LCD juures tema segmentide paigutus. Ekraan on jagatud paljudeks indikaatoriteks. Igal indikaatoril on kas piisavalt palju segmente tähtede ja numbrite kuvamiseks või moodustub see väikeste ruudukujuliste segmentide (pikslite) maatriksist. Näiteks 5×7 pikslisest maatriksist piisab kõigi numbrite, ladina tähestiku ja täppidega tähtede kuvamiseks. Indikaatoreid on tavaliselt 1-4 rida ja 8-32 tulpa. Igal indikaatoril on väike vahe sees, täpselt nagu tekstis tähtedelgi.
Alfabeetiline LCD ekraan koosneb peale ekraani enda veel ka kontrollerist, mis vastavalt sideliidesest tulevatele käskudele juhib ekraani segmente. Kontrollerisse on eelnevalt sisse programmeeritud tähekaart, kus igal tähel, numbril või märgil on oma järjekorranumber ehk indeks. Ekraanil teksti kuvamine toimub põhimõtteliselt LCD kontrollerile tähtede indekseid saates. Tegelikkuses tuleb LCD kontrolleritele ka mitmeid juhtkäske saata, enne kui midagi kuvama hakatakse. Iga konkreetse LCD ekraani kasutamiseks tuleb tutvuda enne selle andmelehega, kuna neid on väga erinevaid ning ühtlasi ka nende juhtimine toimub erinevalt.
Alfabeetilised LCD ekraanid on üldjuhul passiivmaatriksiga, kus segmentide elektrivälja uuendamine toimub kordamööda. Sellest tulenevalt on passiivmaatriksiga ekraanid aeglasemad ja kehvema kontrastiga kui aktiivmaatriks-ekraanid, kus iga segmendi laengut juhib eraldi transistor. LCD ekraane on nii peegelduva taustaga kui taustvalgustusega, vahel isegi mitme erinevat värvi taustvalgustusega. Segmendi värve on alfabeetlistel LCD ekraanidel enamasti siiski üks - reeglina must, kuid esineb ka valge ja värvilise kirjaga ekraane.
Kodulabori digitaalse mooduli külge ühendub 2×16 märgiline alfabeetiline LCD WC1602A. Ekraani juhtimiseks on 4-bitine andmesiin ja 3 juhtviiku, kuid selle suhtlusprotokoll on liiga mahukas, et seda siinkohal lahti seletada. Lihtsuse huvides on ekraani kasutamiseks Kodulabori teegis olemas vastavad funktsioonid, mille lähtekoodi leiab Kodulabori veebilehelt.
Esimene asi, mis ekraani kasutamiseks teha tuleb, on see algseadistada. Vastavaks otstarbeks on funktsioon lcd_alpha_init, millega saab lisada ekraanile ka vilkuva kursori. Ekraanil on olenemata sellest, kas seda on näha või mitte, pidevalt üks aktiivne kursori positsioon, kuhu sisestatakse järgmine täht. Seega tuleb enne teksti sisestamist viia kursor soovitud asukohale. Kursori asukoha muutmiseks on lcd_alpha_goto_xy ja teksti kuvamiseks lcd_alpha_write_string funktsioon. Kõik alfabeetilise LCD funktsioonid on lahti seletatud selle teegis.
Järgnev programmikood demonstreerib alfabeetilise LCD kasutamist kellana. Kellaaeg algab alates “00:00:00” ja suureneb iga ligikaudu sekundiga. Kuna aja lugemine toimub viite funktsiooniga, siis pole see päris täpne. Ebatäpsust selgitab perioodilise katkestuse harjutus. Programm loeb sekundeid ja teisendab need arvutuste abil minutiteks ja sekunditeks. Kellaaja teksti kujule viimiseks on kasutusel C-keele standardfunktsioon sprintf.
// // Kodulabori alfabeetilise LCD kasutamise näide. // LCD-le kuvatakse kellaaeg programmi algusest alates. // #include <stdio.h> #include <homelab/module/lcd_alpha.h> #include <homelab/delay.h> // // Põhiprogramm // int main(void) { int seconds = 0; char text[16]; // LCD ekraani seadistamine lcd_alpha_init(LCD_ALPHA_DISP_ON); // LCD ekraani puhastamine lcd_alpha_clear(); // Programmi nimi lcd_alpha_write_string("Aja loendur"); // Lõputu tsükkel while (true) { // Sekundite teisendamine kellaaja kujule // hh:mm:ss sprintf(text, "%02d:%02d:%02d", (seconds / 3600) % 24, (seconds / 60) % 60, seconds % 60); // Kellaaja teksti kuvamine LCD teise rea alguses lcd_alpha_goto_xy(0, 1); lcd_alpha_write_string(text); // Sekundi suurendamine 1 võrra seconds++; // Riistvaraline paus 1000 millisekundit hw_delay_ms(1000); } }
Vajalikud teadmised: [HW] LCD moodul, [LIB] Graafiline LCD, [LIB] Viide,
[PRT] Teksti LCD
Graafiline LCD on vedelkristall-ekraan, millega saab peale teksti ka kujundeid kuvada. Selle ehitus sarnaneb alfabeetilisele LCD-le ja põhiline erinevus seisneb selles, et graafilisel ekraanil on kõik pikslid jaotatud üle ekraani ühe suure maatriksina. Kui tegu on monokromaatilise graafilise LCD ekraaniga, siis piksel on üks pisike ruudukujuline segment. Värvilistel ekraanidel moodustab üks piksel kolmest alampikslist, millest igaüks laseb läbi värvifiltri kas punast, rohelist või sinist valgust. Kuna alampikslid on lähestikku, paistavad need kui üks piksel.
Monokromaatilised graafilised ekraanid on tavaliselt passiivmaatriksiga, suured värvilised ekraanid, kaasa arvatud arvutiekraanid, on aktiivmaatriksiga. Kogu tausta- ja pikslite värvi puudutav info on graafilistel LCD-del sarnane alfabeetiliste LCD omadustega ja sarnaselt alfabeetiliste ekraanidega on ka graafilistel ekraanidel eraldi kontroller, mis hoolitseb sideliidese kaudu info vastuvõtmise ja segmentide elektrivälja tekitamise eest. Kui alfabeetilisele LCD ekraanile piisab teksti kuvamiseks märkide indeksite saatmisest, siis graafilised ekraanid ise tähti ei moodusta - kõik tekstid ja pildid tuleb kasutajal ise pikselhaaval tekitada.
Kodulabori komplekti kuulub mõõtudega 84 x 48 pikslit monokromaatiline graafiline LCD ekraan. See ekraan on sama, mida kasutatakse Nokia 3310 mobiiltelefonides. Ekraani küljes on Philipsi PCD8544 kontroller, millega saab suhelda läbi SPI-taolise järjestikliidese. Eraldi juhitav on veel ekraanimooduli taustvalgustus. Ekraaniga suhtlemine pole kuigi keeruline, kuid funktsioonide suure arvu tõttu pole siinkohal seda lahti seletatud. Kodulabori teegis on olemas funktsioonid selle kasutamiseks.
Graafilise LCD teegi funktsioonid on sarnased alfabeetilise LCD omadele. Esmalt tuleb ekraan algväärtustada funktsiooniga lcd_gfx_init. Pärast käivitust on soovitatav ekraan, õigemini kontrolleri mälu, puhastada funktsiooniga lcd_gfx_clear. Teeki on sisse kirjutatud tähekaart kogu ladina tähestiku, numbrite ja üldkasutatavate märkidega. Tähe kõrgus on 7 ja laius 5 pikslit. Iga tähe vahe on horisontaalselt 6 ja vertikaalselt 8 pikslit, ehk kokku mahub ekraanile 6 rida ja 14 tulpa tähti. Tähe või teksti kuvamiseks tuleb eelnevalt lcd_gfx_goto_char_xy funktsiooniga määrata selle asukoht. Tähe kuvamiseks on lcd_gfx_write_char ja teksti kuvamiseks lcd_gfx_write_string funktsioon.
Järgnevalt on toodud näide aja loenduri kohta. Programm loendab sekundeid (ligikaudu), minuteid ja tunde. Aja tekstiks teisendamiseks on kasutusel sprintf funktsioon.
// // Kodulabori graafilise LCD kasutamise näide. // LCD-le kuvatakse kellaaeg programmi algusest alates. // #include <stdio.h> #include <homelab/module/lcd_gfx.h> #include <homelab/delay.h> // // Põhiprogramm // int main(void) { int seconds = 0; char text[16]; // LCD ekraani algseadistamine lcd_gfx_init(); // Ekraani puhastamine lcd_gfx_clear(); // Taustavalgustuse tööle lülitamine lcd_gfx_backlight(true); // Programmi nime kuvamine lcd_gfx_goto_char_xy(1, 1); lcd_gfx_write_string("Aja loendur"); // Lõputu tsükkel while (true) { // Sekundite teisendamine kellaaja kujule // hh:mm:ss sprintf(text, "%02d:%02d:%02d", (seconds / 3600) % 24, (seconds / 60) % 60, seconds % 60); // Kellaaja teksti kuvamine lcd_gfx_goto_char_xy(3, 3); lcd_gfx_write_string(text); // Sekundi suurendamine 1 võrra seconds++; // Riistvaraline paus 1000 millisekundit hw_delay_ms(1000); } }
Eesmärgiks on koostada programm, mis täidab kirjeldatud ülesannet.
Andurid on seadmed, mis teisendavad mingi füüsikalise suuruse, näiteks temperatuuri, valgustugevuse, jõu, kiirenduse jne. inimesele või masinale arusaadavale kujule. Nende abil saab mikrokontrolleri programm infot ümbritsevast keskkonnast ja selle põhjal otsuseid teha. Andureid on väga erinevat liiki, Wikipedias on näiteks loetletud ligikaudu 195 andurit. Mikrokontrolleritega saab siiski ühendada vaid andureid, mille väljundiks on elektriline signaal. Elektrilise väljundsignaali järgi võib andurid jagada väga üldiselt kahte tüüpi: analoog- ja digitaalandurid.
Analooganduris muutub füüsikalise suuruse muutudes mõni selle elektriline parameeter, tavaliselt kas pinge, vool või takistus. Kuna mikrokontrollerid on digitaalsed seadmed, siis analooganduri info edastamiseks kontrollerile tuleb see digitaalseks teisendada. Selleks kasutatakse peamiselt mikrokontrolleritesse integreeritud analoog-digitaalmuundureid.
Kui analoogandur juba sisaldab info digitaliseerijat, nimetatakse seda digitaalseks anduriks. Peale digitaliseerimise võivad digitaalsed andurid infot ka normeerida, andurit kalibreerida ja palju muid funktsioone täita. Digitaalse anduri info edastamine mikrokontrollerile võib toimuda mitmel viisil - lihtsamal juhul loogiliste signaalidega, keerukamal juhul mõne andmesideliidese kaudu. Järgmised harjutused tutvustavad siiski lihtsamaid ja robootikas levinuimaid andureid.
Vajalikud teadmised: [HW] Andurite moodul, [HW] Kasutajaliidese moodul,
[ELC] Pingejagur, [AVR] Analoog-digitaalmuundur, [LIB] Analoog-digitaalmuundur,
[LIB] 7-segmendiline LED indikaator
Potentsiomeeter on kolme kontaktiga muuttakisti, mille kahe äärmise kontakti vahel on fikseeritud takistus ja äärmiste ning keskmise kontakti vahel muutuv takistus. Potentsiomeeter on põhimõtteliselt ka pingejagur, kus takistid moodustuvad äärmiste kontaktide ja keskmise kontakti vahel. Potentsiomeetri (inglise keeles potentiometer) sünonüüm on reostaat, mis pärineb venekeelsest sõnast реостат.
Tüüpiline potentsiomeeter koosneb voolu juhtiva pinnaga takistist ja sellel liuglevast liikuvast kontaktist ehk liugurist. Mida lähemal on liugur takisti servale, seda väiksem on liuguri ja selle serva vaheline takistus ning vastupidi. Takisti rolli võib täita kas suure eritakistusega materjal või takistustraadist keritud mähis. Potentsiomeetreid on olemas nii lineaarse kui ka logaritmilise takistuse ja positsiooni suhtega. Suurem osa potentsiomeetritest on pööratavad (näide kõrvaloleval pildil), kuid eksisteerib ka liugtakisteid. Potentsiomeetrite eriliik on digitaalsed potentsiomeetrid, milles takistuse reguleerimine toimub mikroskeemi sees vastavalt juhtsignaalidele.
Kodulabori Andurite mooduli plaadil asub pööratav 4,7 kΩ potentsiomeeter. Potentsiomeeter on ühendatud maa ja +5 V potentsiaalide vahele ning liugur ühendub mikrokontrolleri analoog-digitaalmuunduri kanaliga 3. Selliselt ühendatuna saab potentsiomeetri väljundpinget reguleerida vahemikus 0 kuni 5 V. Kui ka AVR-i analoog-digitaalmuunduri võrdluspinge võtta AVCC viigult, saab potentsiomeetri väljundpinge digitaalse väärtuse kogu selle reguleerimispiirkonna ulatuses. AVR ADC kasutamiseks on Kodulabori teegis kirjutatud järgmised funktsioonid:
// // Seadistuse andmetüübid // typedef enum { ADC_REF_AREF = 0x00, ADC_REF_AVCC = 0x01, ADC_REF_2V56 = 0x03 } adc_reference; typedef enum { ADC_PRESCALE_2 = 0x01, ADC_PRESCALE_4 = 0x02, ADC_PRESCALE_8 = 0x03, ADC_PRESCALE_16 = 0x04, ADC_PRESCALE_32 = 0x05, ADC_PRESCALE_64 = 0x06, ADC_PRESCALE_128 = 0x07 } adc_prescale; // // ADC käivitamine // void adc_init(adc_reference reference, adc_prescale prescale) { // ADC töötamise lubamine, sagedusjaguri valimine ADCSRA = bit_mask(ADEN) | (prescale & 0x07); // Võrdluspinge valimine ADMUX = (reference & 0x03) << REFS0; } // // ADC määratud kanali väärtuse muundamine // unsigned short adc_get_value(unsigned char channel) { // Kanali määramine ADMUX = (ADMUX & 0xF0) | (channel & 0x0F); // Muundamise alustamine bit_set(ADCSRA, ADSC); // Muundamise lõpu ootamine while (bit_is_set(ADCSRA, ADSC)) { asm volatile ("nop"); } // Tulemuse tagastamine return ADCW; }
Funktsioon adc_init tuleb välja kutsuda programmi alguses, millega seatakse AVR-i ADC töövalmis. Valida tuleb võrdluspinge kas AREF või AVCC viigult või hoopis sisemine fikseeritud 2,56 V pinge. Lisaks tuleb määrata muunduri töötakt, täpsemalt sagedusjaguri tegur, millega jagatakse läbi mikrokontrolleri töötakt. Kõrgema taktiga käib muundamine kiiremini, kuid võib kannatada mõõtmistäpsus. Mõõtmiseks on adc_get_value funktsioon, millega saab valida kanali ja mis tagastab 16-bitise täisarvuna 10-bitise mõõtmistulemuse. Mõõtmisfunktsioon on blokeeruv ehk see jääb ootama muundamise lõppu ja tagastab väärtuse alles siis, kui mõõtmine on tehtud.
Näiteprogrammis kasutatakse äsja selgitatud analoog-digitaalmuunduri ja 7-segmendilise LED numberindikaatori teeki. 10-bitine analoog-digitaalmuunduri väärtus korrutatakse kümnega ja jagatakse 1024-ga, et saada väärtus vahemikus 0 kuni 9. Väärtus 10 ei saa tekkida, sest C-keeles arvutatakse jagatises täisosa väärtus, mitte ümardatud tulemus. Täpsema mõõtetulemuse saamiseks kasutatakse muunduri tulemuse keskmistamise funktsiooni. Tulemusena näitab töötav programm vastavalt potentsiomeetri asendile indikaatoril numbreid 0 kuni 9.
// // Kodulabori Andurite mooduli potentsiomeetri // näidisprogramm. 7-segmendilisel numberindikaatoril // kuvatakse potentsiomeetri asendit. // #include <homelab/adc.h> #include <homelab/module/segment_display.h> // // Kanali valimine // // 1 = fototakisti // 2 = termotakisti // 3 = potentsiomeeter // #define ADC_CHANNEL 3 // // Põhiprogramm // int main(void) { int value; // 7-segmendilise indikaatori seadistamine segment_display_init(); // ADC muunduri seadistamine adc_init(ADC_REF_AVCC, ADC_PRESCALE_8); // Lõputu tsükkel while (true) { // Kanali 4-kordselt ümardatud väärtuse lugemine value = adc_get_average_value(ADC_CHANNEL, 4); // Näidu sajandike näitamine segment_display_write(value * 10 / 1024); } }
Vajalikud teadmised: [HW] Andurite moodul, [HW] LCD moodul, [ELC] Pingejagur,
[AVR] Analoog-digitaalmuundur, [LIB] Analoog-digitaalmuundur, [LIB] Alfabeetiline LCD,
[LIB] Andurid
Termistor on takisti, mille takistus muutub temperatuuriga. Termistore on kahte liiki: positiivse ja negatiivse temperatuuri koefitsiendiga. Positiivse koefitsiendiga termistori takistus temperatuuri tõustes kasvab ja negatiivsel väheneb. Vastavad lühendatud ingliskeelsed nimed on neil PTC (positive temperature coefficient) ja NTC (negative temperature coefficient).
Termistori kasutamise teeb keeruliseks tema takistuse temperatuurisõltuvuse mittelineaarsus. Lineaarne on sõltuvus vaid väikestes vahemikes, mitmekümnekraadise ja suurema mõõtepiirkonna arvutamiseks sobib Steinhart-Harti kolmandat järku eksponentsiaalne võrrand. NTC termistoride jaoks on olemas järgmine B-parameetriga lihtsustatud võrrand:
kus:
B-parameeter on koefitsient, mis tavaliselt antakse termistori andmelehes. Samas on see ainult teatud temperatuurivahemikes piisavalt konstantne, näiteks 25–50 °C või 25–85 °C. Kui mõõdetav temperatuurivahemik on suurem, tuleb võimalusel kasutada andmelehel antud võrrandit.
Termistori takistust mõõdetakse kaudselt pingejaguriga, kus ühe takisti asemel on termistor ja mille sisendpinge on konstantne. Mõõdetakse pingejaguri väljundpinget, mis muutub koos termistori takistuse muutusega. Pinget rakendades läbib termistori aga elektrivool, mis termistori selle takistuse tõttu soojendab ja seega omakorda takistust muudab. Termistori soojenemisest tekkivat viga saab arvutuslikult kompenseerida, kuid lihtsam on kasutada suurema takistusega termistorit, mis soojeneb vähem.
Piiratud ressurssidega ja suurt täpsust mittenõudvates rakendustes kasutatakse eelnevalt välja arvutatud temperatuuri ja takistuse vahelise sõltuvuse tabelit. Tabelis on üldjuhul kirjas kindla vahemikuga temperatuurinäitude vastavus anduri takistuse, pinge või analoog-digitaalmuunduri väärtusega. Tabeli puhul on kogu eksponentsiaalne arvutus eelnevalt ära tehtud ja programmis tuleb vaid mõõdetud parameetrile vastav rida üles otsida ja temperatuur välja lugeda.
Kodulabori Andurite mooduli plaat on varustatud 10 kΩ nimitakistusega NTC tüüpi termistoriga. Temperatuuril 25-50 °C on termistori B-parameeter 3900. Termistori üks viik on ühendatud +5 V toitega ja teine mikrokontrolleri analoog-digitaalmuunduri kanaliga 2 (viik PF2). Sama mikrokontrolleri viigu ja maaga on ühendatud ka tavaline 10 kΩ takisti, mis koos termistoriga moodustab pingejaguri. Kuna tegu on NTC termistoriga, mille takistus väheneb temperatuuri kasvades, siis samaaegselt tõuseb ka pingejaguri väljundpinge.
Temperatuuri leidmiseks on AVR-i peal otstarbekas kasutada temperatuuri ja analoog-digitaalmuunduri väärtuste teisendustabelit. Mõistlik on leida soovitud temperatuurivahemikust igale kraadile vastav analoog-digitaalmuunduri väärtus, sest vastupidine tabel läheb 10-bitise ADC väärtuste hulga tõttu liiga suureks. Tabeli tegemiseks on soovitatav kasutada mõnd tabelarvutuse programmi (MS Excel, Openoffice Calc vmt.). Eespool toodud NTC termistorite jaoks kohandatud Steinhart-Harti valemiga saab leida temperatuurile vastava termistori takistuse. Takistusest saab arvutada pingejaguri väljundpinge ning sellest omakorda ADC väärtuse. Leitud väärtused saab järgneval viisil programmi sisse kirjutada:
// // Temperatuuri ADC väärtuseks teisendamise tabel. // Iga massiivi element tähistab ühte Celsiuse kraadi. // Elemendid algavad -20 kraadist ja lõpevad 100 kraadiga. // Kokku on massiivis 121 elementi. // const signed short min_temp = -20; const signed short max_temp = 100; const unsigned short conversion_table[] = { 91,96,102,107,113,119,125,132,139,146,153, 160,168,176,184,192,201,210,219,228,238,247, 257,267,277,288,298,309,319,330,341,352,364, 375,386,398,409,421,432,444,455,467,478,489, 501,512,523,534,545,556,567,578,588,599,609, 619,629,639,649,658,667,677,685,694,703,711, 720,728,736,743,751,758,766,773,780,786,793, 799,805,811,817,823,829,834,839,844,849,854, 859,863,868,872,876,880,884,888,892,896,899, 903,906,909,912,915,918,921,924,927,929,932, 934,937,939,941,943,945,947,949,951,953,955 };
Et tabelist ADC väärtuse järgi temperatuur leida, võib kasutada järgmist algoritmi:
// // ADC väärtuse teisendamine Celsiuse kraadideks. // signed short thermistor_calculate_celsius(unsigned short adc_value) { signed short celsius; // Tabeli tagurpidi läbikäimine for (celsius = max_temp - min_temp; celsius >= 0; celsius--) { // Kui tabeli väärtus on sama või suurem kui // mõõdetud tulemus, siis temperatuur on vähemalt // sama kõrge kui elemendile vastav temperatuur if (adc_value >= conversion_table[celsius]) { // Kuna tabel algab nullist, aga elementide // väärtus -20 kraadist, siis tuleb väärtust nihutada return celsius + min_temp; } } // Kui väärtust ei leitud, tagastatakse minimaalne temperatuur return min_temp; }
Algoritm otsib tabelist vahemikku, kuhu ADC väärtus jääb, ja saab teada selle vahemiku aluspiiri järjekorranumbri. Järjekorranumber tähistab kraade, sellele tuleb ainult algtemperatuur otsa liita ja nii saadaksegi 1 kraadi täpsusega temperatuur.
Toodud teisendustabel ja funktsioon on juba olemas Kodulabori teegis, nii et käesolevas harjutuses neid ise kirjutama ei pea. Teisendamise funktsioonil on teegis nimeks thermistor_calculate_celsius. Arvestama peab, et teisendus kehtib ainult Kodulabori Andurite moodulil asuva termistori kohta. Muu termistori kasutamiseks tuleb ise teisendustabel luua ja kasutada teegi juhendis kirjeldatud keerukamat funktsiooni. Harjutuse näidisprogrammiks on termomeeter, mis mõõdab temperatuuri Celsiuse kraadides ja kuvab seda alfabeetilisel LCD ekraanil.
// // Kodulabori Andurite mooduli termistori näidisprogramm. // LCD ekraanil kuvatakse temperatuur kraadides. // #include <stdio.h> #include <homelab/adc.h> #include <homelab/module/sensors.h> #include <homelab/module/lcd_alpha.h> // // Põhiprogramm // int main(void) { unsigned short value; signed short temperature; char text[16]; // LCD ekraani seadistamine lcd_alpha_init(LCD_ALPHA_DISP_ON); // LCD ekraani puhastamine lcd_alpha_clear(); // Programmi nimi lcd_alpha_write_string("Termomeeter"); // ADC muunduri seadistamine adc_init(ADC_REF_AVCC, ADC_PRESCALE_8); // Lõputu tsükkel while (true) { // Termistori pinge 4-kordselt ümardatud väärtuse lugemine value = adc_get_average_value(2, 4); // ADC väärtuse kraadideks ümberarvutamine temperature = thermistor_calculate_celsius(value); // Temperatuuri tekstiks teisendamine // Kraadi märgi kuvamiseks on oktaalarv 337 sprintf(text, "%d\337C ", temperature); // Teksti kuvamine LCD teise rea alguses lcd_alpha_goto_xy(0, 1); lcd_alpha_write_string(text); } }
Vajalikud teadmised: [HW] Andurite moodul, [HW] LCD moodul, [ELC] Pingejagur,
[AVR] Analoog-digitaalmuundur, [LIB] Analoog-digitaalmuundur, [LIB] Alfabeetiline LCD,
[PRT] Arenduskeskkond AVR Studio (Windows) ATMega128
Fototakisti on andur, mille elektriline takistus muutub sõltuvalt temale pealelangeva valguse intensiivsusest. Mida intensiivsem on valgus, seda rohkem tekib vabu laengukandjaid ning seda väiksemaks jääb elemendi takistus. Fototakisti kaks välist metallkontakti ulatuvad läbi keraamilise alusmaterjali valgustundliku kileni, mis oma geomeetria ja materjali omaduse poolest määravad elektrilised takistuslikud omadused. Kuna fototundlik materjal on iseloomult suure takistusega, siis peenikese käänulise rajaga elektroodide vahel saavutatakse madal elemendi kogutakistus keskmise valguse intensiivsuse juures. Nii nagu inimese silm, on ka fototakisti tundlik kindlale valguse lainepikkuse vahemikule. Fotoelemendi valikul tuleb sellega kindlasti arvestada, kuna vastasel juhul ei pruugi see rakenduses kasutatavale valgusallikale üldse reageeridagi. Siinkohal olgu ära toodud nähtava valguse lainepikkused jaotatuna lihtsustatult värvide järgi.
Värv | Lainepikkuse vahemik (nm) |
---|---|
Lilla | 400 – 450 |
Sinine | 450 – 500 |
Roheline | 500 – 570 |
Kollane | 570 – 590 |
Oranž | 590 – 610 |
Punane | 610 – 700 |
Fototakistil on kindlasti määratud ka töötemperatuuri vahemik. Kui tahta lasta anduril töötada erinevatel temperatuuridel, siis tuleb kindlasti sisse viia täpsustavad teisendused, kuna anduri takistuslik omadus sõltub välistemperatuurist.
Valguse intensiivsuse iseloomustamiseks kasutatakse füüsikalist suurust valgustustihedus (tähis E), mis näitab mingile pinnale jõudva valgusvoo hulka. Mõõdetavaks ühikuks on luks (lx), kus 1 luks tähendab, et 1 m2 suurusele pinnale langeb ühtlaselt valgusvoog 1 luumen. Reaalses elus praktiliselt kunagi aga ei lange valgus (elamis)pinnale ühtlaselt ning seetõttu valgustustihedus saadakse rohkem keskmise väärtusena. Võrdluseks olgu ära toodud ka mõningad valgustustiheduse näited:
Keskkond | Valgustustihedus (lx) |
---|---|
Täiskuu | 0,1 |
Hämarus | 1 |
Auditoorium | 10 |
Klassiruum | 30 |
Päikesetõus või -loojang | 400 |
Haigla operatsioonisaal | 500 - 1000 |
Otsene päikesevalgus | 10000 |
Kodulabori Andurite mooduli plaat on varustatud VT935G fototakistiga. Selle üks viik on ühendatud +5 V toitega ja teine mikrokontrolleri analoog-digitaalmuunduri kanaliga 1 (viik PF1). Sama mikrokontrolleri viigu ja maaga on ühendatud ka tavaline 10 kΩ takisti, mis koos fototakistiga moodustab pingejaguri. Kuna fototakisti elektriline takistus väheneb temale langeva valguse intensiivsuse kasvades, siis mõõdetav pinge mikrokontrolleri viigu peal kasvab valguse intensiivsuse kasvades. Tasuks arvestada, et Kodulaboris kasutatav fototakisti reageerib kõige intensiivsemalt kollasele ja oranžile valgusele.
VT935G andur ei olegi tegelikult mõeldud konkreetseks mõõteseadmeks, pigem üldiste valgustingimuste määramiseks - näiteks kas ruumis põleb lamp või mitte. Sel juhul tuleb lihtsalt mõõta anduri takistus poolpimedas ruumis, see programmi kirja panna ja selle abil võrrelda mõõdetavat - kas on heledam või pimedam.
Käesolev harjutus on aga natukese keerulisem, kuna leitakse andurile valgeva valguse valgustustihedust luksides. Selle tegemiseks on kasutusel ligikaudne arvutusvalem ja ujukoma arvud. Ujukoma arvud on C-keeles float ja double tüüpi, millega saab esitada murdarve. Nende puuduseks on suhteliselt suur ressursinõudlikkus. Arvutites on nende arvutamiseks spetsiaalne riistvara, 8-bitisel AVR mikrokontrolleril tehakse arvutused tarkvaras, mis võtab suhteliselt palju programmimälu ja aega. Kui puudused pole olulised, on ujukoma arvud väärt kasutamist.
Fototakisti valgustustiheduse ja elektritakistuse vahelise seose kohta annab anduri andmeleht ligikaudse valemi. Nagu kõrvalolevalt graafikult näha, on logaritmskaalas valgustustihedus ja takistus ligikaudu lineaarses seoses ning moodustavad sirge võrrandi, sest kehtib teisendus:
log(a/b) = log(a) - log(b)
Seost iseloomustab γ faktor (sirge tõus), mis VT935G anduril on 0,9. Teada on ka joone ühe punkti andmed: 18,5 kΩ takistus (RA) 10 lx valgustustiheduse (EA) juures. Seega on olemas 1 punkti koordinaadid ja sirge tõus ning iga muu punkti arvutamiseks piisab vaid ühest koordinaadist. Ehk kui mõõta anduri takistus (RB), saab joone võrrandist arvutada andurile langeva valgustustiheduse (EB). Avaldame joone võrrandist EB:
log(EB) = log(RA/RB) / γ + log(EA)
EB = 10log(RA/RB) / γ + log(EA)
Sellega on takistusest valgustustiheduse arvutamise valem olemas. Takistust otse aga mikrokontrolleriga mõõta ei saa - selleks on fototakisti pingejaguris, mille väljundpinge teisendab analoog-digitaalmuundur konkreetseks arvuks (ADC). Takistuse leidmiseks tuleb kõigepealt arvutada ADC väärtusest pingejaguri väljundpinge (U2), arvestades ka muunduri võrdluspinget (Uref). Valem on selline:
U2 = Uref ⋅ (ADC / 1024)
Pingejaguri valemist (vaata pingejaguri peatükki) saab leida skeemis ülemise fototakisti takistuse (R1):
R1 = (R2 ⋅ U1) / U2 - R2
Järgnevalt on pinge ja takistuse arvutamisel teadaolevad tegurid asendatud väärtustega ja alaindeksid ära jäetud:
U = 5 ⋅ (ADC / 1024)
R = (10 ⋅ 5) / U - 10
Valgustustiheduse leidmisel saab teha lihtsustavaid teisendusi:
E = 10log(18,5/R) / 0.9 + 1 = 10log(18,5/R) ⋅ 10/9 ⋅ 101 =
= 10log18,5 ⋅ 10/9 - logR ⋅ 10/9 ⋅ 10 = (10log18,5 ⋅ 10/9 / 10logR ⋅ 10/9) ⋅ 10 =
= (18,510/9 / R10/9) ⋅ 10 = 18,510/9 ⋅ 10 ⋅ R-10/9
Arvutades välja muutuja R ees oleva konstandi, jääb avaldis kujule:
E = 255,84 ⋅ R-10/9
Nende valemite abil saab kasutada vaid Kodulabori Andurite mooduli plaadil olevat fototakistit. Teiste komponentidega skeemi kasutades tuleks valemites muuta vastavaid arvväärtusi. Järgnevalt on toodud näidisprogrammi lähtekood, mis teostab ADC-ga mõõtmist, arvutamist ja valgustustiheduse kuvamist LCD ekraanile. Kuid veel enne programmi kompileerimist tuleb projektis teha seadistused ujukoma arvude kasutuselevõtuks. Selle kohta on lühiõpetus tarkvara paigaldamise peatükis.
Näidisprogrammis defineeritakse pinge, takistuse ja valgustustiheduse muutujad ujukoma tüüpi arvuna double. Arvud, mida soovitakse kindlasti ujukoma tehetes kasutada, peavad alati sisaldama komakohta (C-keeles punkti), olgu kas või nulli, sest siis ei tõlgenda kompilaator neid valesti. sprintf abil ujukoma arvu tekstiks teisendades tuleb kasutada “%f” formaati, mida võib täiendada täis- ja komakohtade arvuga, näiteks “%3.2”, mis kuvab alati 3 täis- ja 2 komakohta.
// // Kodulabori Andurite mooduli fototakisti näidisprogramm. // LCD ekraanil kuvatakse ligikaudne valgustustihedus luksides // #include <stdio.h> #include <math.h> #include <homelab/module/lcd_alpha.h> #include <homelab/adc.h> #include <homelab/delay.h> // // Põhiprogramm // int main(void) { char text[16]; unsigned short adc_value; double voltage, resistance, illuminance; // LCD ekraani seadistamine lcd_alpha_init(LCD_ALPHA_DISP_ON); // LCD ekraani puhastamine lcd_alpha_clear(); // Programmi nimi lcd_alpha_write_string("Luksmeeter"); // ADC muunduri seadistamine adc_init(ADC_REF_AVCC, ADC_PRESCALE_8); // Lõputu tsükkel while (true) { // Fototakisti keskmistatud väärtuse lugemine adc_value = adc_get_average_value(1, 10); // Pinge arvutamine ADC sisendis voltage = 5.0 * ((double)adc_value / 1024.0); // Fototakisti takistuse arvutamine pingejaguris resistance = (10.0 * 5.0) / voltage - 10.0; // Valgustustiheduse luksides arvutamine illuminance = 255.84 * pow(resistance, -10/9); // Valgustustiheduse tekstiks teisendamine sprintf(text, "%0.1f lux ", illuminance); // Näidu LCD-l kuvamine lcd_alpha_goto_xy(0, 1); lcd_alpha_write_string(text); // Viide 500 ms sw_delay_ms(500); } }
Vajalikud teadmised: [HW] Andurite moodul, [HW] LCD moodul, [AVR] Analoog-digitaalmuundur, [LIB] Analoog-digitaalmuundur, [LIB] Alfabeetiline LCD, [LIB] Andurid
Objekti kauguse mõõtmiseks on olemas triangulatsioonimeetodil töötavad optilised andurid. Levinuimad neist on firma Sharp poolt toodetavad infrapuna (inglise keeles infra-red, lühend IR) lainepikkusel töötavad analoogpinge väljundiga kaugusandurid. Sharp-i anduritel on läätsega IR LED, mis kiirgab kitsast valguskiirt. Objektilt peegeldunud kiir suunatakse läbi teise läätse positsioonitundlikule fotoelemendile (inglise keeles position-sensitive detector, lühend PSD). PSD-le langeva kiire asukohast sõltub selle juhtivus. Juhtivus muundatakse pingeks ja seda näiteks mikrokontrolleri analoog-digitaalmuunduriga digitaliseerides saab välja arvutada kauguse. Erinevatelt kaugustelt peegelduvate kiirte teekonda näitab kõrvalolev joonis.
Sharp-i kaugusandurite väljund on pöördvõrdeline - kauguse kasvades see väheneb ja järjest aeglasemalt. Täpne kauguse ja väljundi vaheline graafik on toodud andurite andmelehel. Anduritel on vastavalt tüübile ka mõõtepiirkond, milles nende väljund on usaldusväärne. Maksimaalsele reaalselt mõõdetavale kaugusele seab piiri kaks aspekti: peegelduva valguse intensiivsuse vähenemine ja PSD-e võimetus registreerida väikest peegeldunud kiire asukoha muutust. Liiga kaugete objektide mõõtmisel jääb anduri väljund ligikaudu samaks, mis maksimaalselt mõõdetava kauguse puhulgi. Minimaalne mõõdetav kaugus on piiratud Sharp-i andurite omapära tõttu - nimelt hakkab väljundpinge kauguse vähenedes teatud kaugusel (olenevalt andurist 4-20 cm) järsult jälle vähenema. Sisuliselt tähendab see, et ühele väljundpinge väärtusele vastab kaks kaugust. Probleemide ärahoidmiseks tuleb vältida objektide andurile liiga lähedale sattumist.
Kodulabori andurite komplektis on Sharp-i infrapuna kaugusmõõdik GP2Y0A21YK mõõtepiirkonnaga 10-80 cm. Anduri väljundpinge on kuni 3 V sõltuvalt mõõdetavast kaugusest. Andur ühendub andurite mooduli külge ja selle väljundpinge suunatakse AVR-i analoog-digitaalmuunduri kanalisse 0. Eelnevate andurite harjutuste baasil saab lihtsalt teha programmi, mis mõõdab kaugusmõõdiku väljundpinget, kuid lisaks on selle harjutuse eesmärk veel pinge kauguseks teisendamise protsessi tutvustamine.
GP2Y0A21YK andmelehel on toodud väljundpinge ja mõõdetud kauguse vahelise sõltuvuse graafik. See pole lineaarne, kuid väljundpinge ja kauguse pöördväärtuse graafik peaaegu juba on, ning sellest on suhteliselt lihtne leida valem pinge kauguseks teisendamiseks. Valemi leidmiseks tuleb sama graafiku punktid sisestada mõnda tabelarvutuse programmi ja nendest uuesti graafik luua. Tabelarvutusprogrammides on graafiku punktide põhjal võimalik arvutada automaatselt välja trendijoon. Järgnevalt on toodud GP2Y0A21YK väljundpinge ja kauguse korrigeeritud pöördväärtuse vahelise seose graafik koos lineaarse trendijoonega. Väljundpinge on valemi lihtsustamise nimel juba teisendatud 10-bitiseks +5 V võrdluspingega analoog-digitaalmuunduri väärtuseks.
Nagu graafikult näha, kattub trendijoon (sinine) üsna täpselt graafiku punktidega (punane joon). Selline kattuvus on saavutatud kauguse korrigeerimiskonstandi abil. Korrigeerimiskonstant on leitud katse-eksitusmeetodil - läbi on proovitud erinevaid arve, kuni on leitud selline, mille korral graafik kattub trendijoonega kõige rohkem. Antud graafiku puhul on see +2, ehk kõigile reaalsetele kaugustele on graafikus 2 otsa liidetud. Kuna nii on graafik väga sarnane lineaarsele trendijoonele, võib teha üldistuse ja öelda, et kauguse ja pinge vaheline seos on järgmine:
1 / (d + k) = a ⋅ ADC + b
kus
Valemist saab avaldada kauguse d:
d = (1 / (a ⋅ ADC + B)) - k
Põhimõtteliselt saakski selle valemiga kauguse välja arvutada, kuid see eeldaks ujukoma-arvutusi, sest jagatises tekivad murdarvud. Täisarvudega opereeriva mikrokontrolleri jaoks tuleb valemit lihtsustada ja suuremate tegurite peale ümber teisendada. Valemi jagatist lineaarliikmega läbi jagades saab see kuju:
d = (1 / a) / (ADC + B / a) - k
Viies valemisse korrigeerimiskonstandi väärtuse ja trendijoone võrrandist saadud lineaar- ja vabaliikme (saadud jooniselt), tuleb kauguse arvutamise valemiks:
d = 5461 / (ADC - 17) - 2
See valem on arvutatav 16-bitiste täisarvudega ja täiesti jõukohane AVR-ile. Enne arvutamist tuleb aga veenduda, et ADC väärtus oleks üle 17, sest muidu tekib nulliga jagamine või negatiivne kaugus, mis on ebaloogiline.
Järgnevalt on toodud Kodulabori teegis kirja pandud funktsioon ADC väärtuse sentimeetriteks teisendamise kohta. Lineaar- ja vabaliige ning korrigeerimiskonstant pole funktsiooni jäigalt sisse kirjutatud, vaid need antakse ette IR kaugusanduri parameetrite struktuuri objektiga. Hoides parameetreid eraldi konstandis, saab hiljem programmi lihtsalt lisada uusi IR kaugusandurite mudeleid.
// // IR kaugusanduri parameetrite struktuur // typedef const struct { const signed short a; const signed short b; const signed short k; } ir_distance_sensor; // // GP2Y0A21YK anduri parameetrite objekt // const ir_distance_sensor GP2Y0A21YK = { 5461, -17, 2 }; // // IR kaugusanduri ADC väärtuse sentimeetriteks teisendamine // Tagastab -1, kui teisendus ei õnnestunud // signed short ir_distance_calculate_cm(ir_distance_sensor sensor, unsigned short adc_value) { if (adc_value + sensor.b <= 0) { return -1; } return sensor.a / (adc_value + sensor.b) - sensor.k; }
Teisenduse tegemiseks tuleb välja kutsuda ir_distance_calculate_cm funktsioon, mille esimene parameeter on IR kaugusanduri parameetrite objekt, teine aga ADC väärtus. Funktsioon tagastab arvutatud kauguse sentimeetrites. Väära tehte (ehk siis ebaloomuliku ADC väärtuse) korral tagastab funktsioon -1. IR kaugusanduri ja teisendusfunktsiooni kasutamist demonstreerib järgnev programm. Kasutusel on alfabeetiline LCD ekraan, kus kuvatakse mõõtetulemust. Ebaloomuliku kauguse puhul kuvatakse küsimärki.
// // Kodulabori IR kaugusmõõdiku näidisprogramm. // LCD ekraanil kuvatakse mõõdetud kaugus sentimeetrites. // #include <stdio.h> #include <homelab/adc.h> #include <homelab/delay.h> #include <homelab/module/sensors.h> #include <homelab/module/lcd_alpha.h> // // Põhiprogramm // int main(void) { signed short value, distance; char text[16]; // LCD ekraani seadistamine lcd_alpha_init(LCD_ALPHA_DISP_ON); // LCD ekraani puhastamine lcd_alpha_clear(); // Programmi nimi lcd_alpha_write_string("Kaugusandur"); // ADC muunduri seadistamine adc_init(ADC_REF_AVCC, ADC_PRESCALE_8); // Lõputu tsükkel while (true) { // Anduri väljundpinge 4-kordselt ümardatud väärtuse lugemine value = adc_get_average_value(0, 4); // ADC väärtuse kauguseks ümberarvutamine distance = ir_distance_calculate_cm(GP2Y0A21YK, value); // Kas saab kauguse või veateate kuvada ? if (distance >= 0) { sprintf(text, "%d cm ", distance); } else { sprintf(text, "Viga "); } // Teksti kuvamine LCD teise rea alguses lcd_alpha_goto_xy(0, 1); lcd_alpha_write_string(text); // Paus sw_delay_ms(500); } }
Vajalikud teadmised: [HW] Andurite moodul, [HW] LCD moodul, [AVR] Loendurid/Taimerid, [LIB] Taimerid, [LIB] Alfabeetiline LCD, [LIB] Andurid, [PRT] Riistvaraline viide
Ultraheli kaugusmõõdik määrab objekti(de) kaugust, mõõtes helilaine objektilt tagasipeegeldumise aega. Helilaine sagedus asub ultraheli sageduse piirkonnas, mis tagab kontsentreerituma helilaine suuna, sest kõrgema sagedusega heli hajub keskkonnas vähem. Tüüpiline ultraheli kaugusmõõdik koosneb kahest membraanist, millest üks genereerib heli ja teine registreerib tagasipeegelduva kaja. Piltlikult öeldes on tegu kõlari ja mikrofoniga. Heligeneraator tekitab lühikese, mõne perioodi pikkuse ultraheli impulsi ja käivitab taimeri. Teine membraan registreerib peegeldunud impulsi saabumise ja peatab taimeri. Taimeri ajast on heli kiiruse järgi võimalik välja arvutada helilaine läbitud teepikkus. Objekti kaugus on ligikaudu pool helilaine teepikkusest.
Ultraheli kaugusmõõdikutel on igapäevaelus mitmeid rakendusi. Neid kasutatakse mõõdulintide asendajatena kauguse mõõtmise seadmetes, näiteks ehitusel. Tänapäeva autod on varustatud tagurdamisel takistusest hoiatavate ultraheliandurite ja hoiatussignaaliga. Peale kauguse mõõtmise võivad nad lihtsalt registreerida objekti olemasolu mõõtepiirkonnas, näiteks tööstusmasinate ohualades. Kui ultraheli kiirgur ja vastuvõtja eraldada, saab mõõta nende vahel voolava aine voolukiirust, sest vastuvoolu levib helilaine aeglasemalt ja pärivoolu kiiremini.
Kodulabori Andurite mooduli komplektis on Devantech SRF04 või SRF05 ultraheli kaugusmõõdik. SRF04/SRF05 on ainult andur, mis otseselt kauguse infot ei väljasta. Anduril on peale toiteviikude veel päästiku ja kaja viik. Päästiku viiku kõrgeks seades genereerib andur 8-perioodilise 40 kHz ultraheli laine. Sel hetkel läheb kõrgeks kaja viik ja jääb kõrgeks niikauaks, kuni peegeldunud helilaine on andurini jõudnud. Seega põhimõtteliselt näitab kaja signaal aega, mille jooksul heli levib objektini ja tagasi. Mõõtes seda aega, korrutades seda heli levimise kiirusega ja jagades kahega, saab leida objekti kauguse. Päästiku, helilaine kiirguri ja kaja signaale ajas iseloomustab kõrvalolev graafik.
Devantech-i ultrahelianduri AVR-iga kasutamiseks tuleb selle päästiku ja kaja viigud ühendada mõnede AVR-i viikudega. Aja mõõtmiseks on sobiv kasutada 16-bitist taimerit, näiteks timer3. Järgnevalt on toodud funktsioon, mis teostab kogu mõõtmisprotseduuri - genereerib päästiku signaali, käivitab taimeri, mõõdab kajasignaali pikkust ja teisendab selle kauguseks sentimeetrites. Funktsioon on blokeeruv ehk protsessor on sellega hõivatud senikaua, kuni mõõtetulemus on käes või mõõtmine venib lubatust pikemaks. Mida kiiremini kaja saabub, seda kiiremini saab mõõtetulemuse. Kui kaja ei saabugi, ootab funksioon seda ~36 ms ja tagastab seejärel 0. Oluline on mõõtmiste vahele jätta mõnikümmend millisekundit pausi, et eelmisel mõõtmisel tekitatud helilaine jõuaks sumbuda ega rikuks uut mõõtmist. Kui kasutatakse samaaegselt mitut ultraheli andurit, tuleb samuti jälgida, et helilained ei kattuks.
#define ULTRASONIC_SPEED_OF_SOUND 33000 // cm/s // // Ultraheli kaugusanduriga mõõtmine // unsigned short ultrasonic_measure(pin trigger, pin echo) { // Viikude seadistus pin_setup_output(trigger); pin_setup_input_with_pullup(echo); // Taimer 3 normaalrežiimi // perioodiga F_CPU / 8 timer3_init_normal(TIMER3_PRESCALE_8); // Päästiku viik kõrgeks pin_set(trigger); // Taimeri nullimine timer3_overflow_flag_clear(); timer3_set_value(0); // ~10 us ootamine while (timer3_get_value() < 18) {} // Päästiku viik madalaks pin_clear(trigger); // Kaja signaali alguse ootamine while (!pin_get_value(echo)) { // Liiga kaua oodatud ? if (timer3_overflow_flag_is_set()) { return 0; } } // Taimeri nullimine timer3_set_value(0); // Kaja signaali lõpu ootamine while (pin_get_value(echo)) { // Liiga kaua oodatud ? if (timer3_overflow_flag_is_set()) { return 0; } } // Mõõdetud aja kauguseks teisendamine // kaugus = aeg * (1 / (F_CPU / 8)) * heli kiirus / 2 return (unsigned long)timer3_get_value() * ULTRASONIC_SPEED_OF_SOUND / (F_CPU / 4); }
Toodud funktsioon jätab päästiku ja kaja viigu kasutaja valida, nii et andurit saab ühendada sinna, kus on sobivam või kus on ruumi. Lisaks võimaldab viikude valiku vabadus funktsiooni kasutada ka mujal kui Kodulabori komplektis. Toodud funktsioon kuulub ka Kodulabori teeki, nii et seda ei pea oma programmi eraldi kirjutama. Peab aga arvestama, et Kodulabori teegis on see funktsioon jäigalt seotud Kodulabori Kontrollermooduli taktsagedusega 14,7456 Mhz ja muude taktsageduste puhul annaks funktsioon vale tulemuse. Muu taktsageduse korral tuleb see funktsioon ise oma programmmi kirjutada. Järgnevalt esitatud programmikood demonstreerib SRF04/SRF05 ultrahelianduri kasutamist Kodulabori teegiga.
// // Kodulabori ultraheli kaugusanduri näidisprogramm. // Kauguse mõõtmise funktsioon on blokeeruv. // #include <stdio.h> #include <homelab/pin.h> #include <homelab/delay.h> #include <homelab/module/sensors.h> #include <homelab/module/lcd_alpha.h> // // Ultraheli anduri viigud // pin pin_trigger = PIN(G, 1); pin pin_echo = PIN(G, 0); // // Põhiprogramm // int main(void) { unsigned short distance; char text[16]; // LCD ekraani seadistamine lcd_alpha_init(LCD_ALPHA_DISP_ON); // LCD ekraani puhastamine lcd_alpha_clear(); // Programmi nimi lcd_alpha_write_string("Ultraheli"); // Väike paus sw_delay_ms(100); // Lõputu tsükkel while (true) { // Mõõtmine distance = ultrasonic_measure(pin_trigger, pin_echo); // Mõõtmine õnnestus ? if (distance > 0) { // Kauguse tekstiks teisendamine sprintf(text, "%d cm ", distance); } // Mõõtmisel tekkis viga ? else { // Vea tekst sprintf(text, "Viga "); } // Teksti kuvamine LCD teise rea alguses lcd_alpha_goto_xy(0, 1); lcd_alpha_write_string(text); // Väike paus sw_delay_ms(500); } }
Eesmärgiks on koostada programm, mis täidab kirjeldatud ülesannet.
Mootorid on täiturseadmed, õigemini vaid üks osa neist, ja neidki leidub väga erinevaid, alates tööpõhimõttest ja lõpetades võimsuse ja suurusega. Robootikas on kasutusel peamiselt erinevad elektrimootorid. Elektrimootor on seade, mis muudab elektrienergia mehaaniliseks pöörlevaks energiaks ja mille töö põhineb elektromagnetismi nähtusel.
Elektrimootorite liigitamiseks on mitu erinevat viisi, kuid olulisim on mootorite jaotamine alalisvoolu ja vahelduvvoolu mootoriteks. Lisaks sellele saab elektrimootoreid liigitada harjadega ja harjadeta mootoriteks, lineaarmootoriteks ja pöördmootoriteks, nano- ja maksiskaalas mootoriteks jne. Samas on mitmed liigitused tinglikud. Näiteks lineaarliikumine saadakse tihti ikkagi pöörleva elektrimootori abil, mis on integreeritud ühte korpusesse kruvimehhanismiga ja käsitletakse nii lineaartäiturina. Käesolevas peatükis on tähelepanu pööratud kolmele enimlevinud elektrimootorile robootikas: püsimagnetiga alalisvoolu mootor, RC (radio-controlled)) servomootor ja samm-mootor.
Vajalikud teadmised: [HW] Mootorite moodul, [AVR] Digitaalsed sisendid-väljundid,
[LIB] Mootorid, [LIB] Viide
Püsimagnetiga alalisvoolumootorid on laialt levinud erinevates rakendustes, kus olulised on väikesed mõõtmed, suur võimsus ja madal hind. Nende suhteliselt suure pöörlemiskiiruse tõttu kasutatakse neid tihti koos ülekandega (reduktoriga) madalama kiiruse ja suurema pöördemomendi saavutamiseks.
Püsimagnetiga alalisvoolumootorid on lihtsa ehitusega ja elementaarse juhtimisega mootorid. Kuigi juhtimine on lihtne, ei ole nende pöörlemiskiirus üldjuhul täpselt juhtsignaaliga määratletav, sest see sõltub mitmetest teguritest, eelkõige võllile rakendatavast koormusest ja toitepingest. Ideaalse alalisvoolumootori jõumomendi ja kiiruse suhe on lineaarne, mis tähendab seda, et mida suurem koormus on võllil, seda madalam on kiirus ja seda suurem on mähist läbiv vool.
Harjadega alalisvoolumootorid töötavad alalispingel ning põhimõtteliselt ei vaja eraldi juhtelektroonikat, kuna kogu vajalik kommutatsioon toimub mootori sees. Mootori töötamise ajal libisevad kaks staatilist harja rootori pöörleval kommutaatoril ning hoiavad mähiseid pinge all. Mootori pöörlemissuuna määrab toitepinge polaarsus. Kui mootorit on vaja juhtida ainult ühes suunas, võib toitevoolu anda relee või muu lihtsa lülitusega, kui mõlemat pidi, siis kasutatakse H-silla-nimelist elektriskeemi.
H-sillas tüürivad mootori pöörlemiseks vajalikku voolu neli transistori (või nende gruppi). H-silla elektriskeem meenutab H-tähte - sellest ka nimi. H-silla eripära seisneb mootorile mõlemat pidi polaarsuse rakendamise võimaluses. Kõrvaloleval pildil on toodud H-silla põhimõtteskeem lülitite näitel. Kui selles skeemis sulgeda kaks diagonaalis asetsevat lülitit, hakkab mootor tööle. Mootori pöörlemissuund sõltub aga sellest, kummas diagonaalis lülitid suletakse. Reaalses H-sillas on lülitite asemel muidugi transistorid, mis on valitud vastavalt mootori voolule ja pingele.
H-sillaga saab peale pöörlemissuuna muuta ka mootori pöörlemiskiirust - selleks tuleb transistore pulsilaiusmodulatsiooniga (PWM) pidevalt avada ja sulgeda, nii et summaarne mootorile antav energia on midagi seismise ja täisvõimsuse vahepealset. Avatud aega kogu PWM perioodist nimetatakse ka töötsükliks (inglise keeles duty cycle), mida tähistatakse protsentidega. 0% tähendab, et transistor on pidevalt suletud, ehk ei juhi voolu, 100% tähendab, et transistor on pidevalt avatud, ehk juhib voolu. PWM sagedus peab olema piisavalt kõrge, et vältida mootorivõlli vibreerimist. Madalal sagedusel tekitab mootor lisaks ka müra ja seepärast kasutatakse enamasti üle 20 kHz moduleerimissagedust. Samas kannatab väga suurtel sagedustel H-silla efektiivsus. Mootorivõlli vibreerimist vähendavad ka rootori inerts ja mootori mähiste induktiivsus.
Väiksemate voolude juhtimiseks leiab H-sildu integreeritud komponendina ehk ajurina, suuremate voolude jaoks kasutatakse spetsiaalseid võimsustransistore (Power MOSFET). H-silda koos sinna kuuluva elektroonikaga nimetatakse ka mootorikontrolleriks.
Märkus: Mitte ajada segamini RC (raadiojuhitav servomootor) PWM signaali tavaliste PWM signaalidega.
Kodulaboris kasutatav alalisvoolumootorite ajur L293D sisaldab endas kahte integreeritud H-silda ja kaitsedioode. Mootorit juhitakse kolme digitaalse signaaliga, millest üks on üldine tööd lubav signaal (inglise keeles enable). Teised kaks signaali määravad H-silla transistoride oleku. Kunagi ei tohi olla avatud kaks vertikaalset transistorit, sest see lühistaks toiteallika. Seega on ajur tehtud n-ö. lollikindlana ja valida saab madala või kõrge väärtusega vaid seda, kumb transistor (kas ülemine või alumine) ühest H-silla poolest ehk poolsillast avatud on. Teisisõnu valitakse kahe juhtsignaaliga polaarsust, mis kummalegi mootori mähise otsale rakendatakse.
Kodulabori Mootorite mooduli plaadil on võimalus kuni nelja alalisvoolumootori ühendamiseks. Skeemid ja ühendamise õpetuse leiab Mootorite mooduli peatükist. Sisuliselt on iga mootori jaoks H-sild, mida juhitakse kahe mikrokontrolleri digitaalse väljundviiguga, sest lubamise viik on konstantselt kõrge. Kui mõlemal juhtviigul on sama väärtus, siis mootor ei liigu, kui erinev, siis mootor pöörleb vastavas suunas. H-silla olekut iseloomustab järgmine tabel:
Sisend A | Sisend B | Väljund A | Väljund B | Tulemus |
---|---|---|---|---|
0 | 0 | - | - | Mootor seisab |
1 | 1 | + | + | Mootor seisab |
1 | 0 | + | - | Mootor pöörleb ühtpidi |
0 | 1 | - | + | Mootor pöörleb teistpidi |
Alalisvoolumootoreid võib juhtida otse, manipuleerides mikrokontrolleri viikudega mootoriajuri sisendviike, kuid Kodulabori teegis on selleks olemas ka lihtsustavad funktsioonid:
// // Alalisvoolumootori kontrolleri viikude seadistus // static pin dcmotor_pins[4][2] = { { PIN(B, 7), PIN(B, 4) }, { PIN(D, 1), PIN(D, 0) }, { PIN(D, 7), PIN(D, 6) }, { PIN(D, 5), PIN(D, 4) } }; // // Valitud alalisvoolumootori juhtimise lubamine // void dcmotor_init(unsigned char index) { pin_setup_output(dcmotor_pins[index][0]); pin_setup_output(dcmotor_pins[index][1]); } // // Valitud alalisvoolumootori töötamise ja töötamise suuna määramine // void dcmotor_drive(unsigned char index, signed char direction) { pin_set_to(dcmotor_pins[index][0], direction < 0); pin_set_to(dcmotor_pins[index][1], direction > 0); }
Teegis defineeritakse dcmotor_pins massiiviga ära nelja mootorikontrolleri juhtviigud. Enne mootorite juhtimist tuleb välja kutsuda dcmotor_init funktsioon koos mootorikontrolleri numbri (0 kuni 3) parameetriga, mis seab vastavad viigud väljundiks. Juhtimiseks on dcmotor_drive funktsioon, millega antakse valitud mootorile negatiivse direction parameetriga üks ja positiivse parameetriga teine pöörlemissuund ning 0 puhul mootor peatatakse.
Järgnevalt on toodud näidisprogramm, mis juhib esimest ja teist alalisvoolumootorit, nii et need muudavad oma pöörlemissuunda iga sekundi järel. Kiirust saaks muuta, kui üht juhtviiku moduleerida PWM signaaliga.
// // Kodulabori mootorite mooduli // alalisvoolumootori testprogramm // #include <homelab/module/motors.h> #include <homelab/delay.h> // // Põhiprogramm // int main(void) { // Suuna muutuja signed char direction = 1; // Mootorite 0 ja 1 seadistamine dcmotor_init(0); dcmotor_init(1); // Lõputu tsükkel while (true) { // Üks mootor käib ühtepidi, teine teistpidi dcmotor_drive(0, -direction); dcmotor_drive(1, +direction); // Paus 1 sekund sw_delay_ms(1000); // Suuna ümberpööramine direction = -direction; } }
Vajalikud teadmised: [HW] Mootorite moodul, [HW] Andurite moodul, [AVR] Digitaalsed sisendid-väljundid, [AVR] Loendurid/Taimerid, [LIB] Mootorid, [LIB] Analoog-digitaalmuundur
RC (lühend, inglise keeles radio-controlled) servomootor on mudelismis ja robootikas laialt levinud täiturmehhanism, mis koosneb väikesest alalisvoolu mootorist, hammasreduktorist ja juhtloogikast. Servomootori rootor liigub üldjuhul mingisse kindlasse asendisse ja üritab siis seda asendit püsivalt hoida. Rootori asend sõltub servomootorile etteantavast juhtsignaalist. Sõltuvalt mootori tüübist võib maksimaalne pöördenurk olla erinev. Harvem esineb pideva pöörlemisega servomootoreid. Sellisel juhul määrab juhtsignaal mitte rootori asendi, vaid pöörlemiskiiruse. Levinud on ka servomootori nn. häkkimine, mille käigus asendit määrav servomootor tehakse ümber pidevalt pöörlevaks. Sisuliselt tähendab see, et asendist tagasisidet andev potentsiomeeter asendatakse kahe fikseeritud takistiga ja eemaldatakse hammasrattalt täispööret takistav mehaaniline takistus. Servomootori üks oluline tunnus on tema hea kaalu ja võimsuse suhe.
Servomootori juhtsignaaliks on spetsiifiline pulsilaiusmodulatsiooni (PWM) signaal, kus pulsi laius määrab ära rootori asendi. Signaali perioodiks on 20 ms (sagedus 50 Hz) ja kõrge poolperioodi laiuseks 1-2 ms. 1 ms tähistab rootori üht äärmist asendit ja 2 ms teist rootori äärmist asendit. 1,5 ms tähistab rootori keskasendit.
Traditsiooniline RC servomootor kannab ka analoog-servomootori nime. Põhjus on selles, et viimasel kümnendil tekkisid ka nii-öelda digitaalsed servomootorid. Nende kahe vahe seisneb selles, et analoog-servomootoris juhitakse mootorit sellesama 50 Hz PWM sisendsignaaliga, digitaal-servomootoris juhib mootorit aga eraldi mikrokontroller palju kõrgema sagedusega. Sisendsignaal on digitaalsel servomootoril küll sama, kuid kõrgem mootori moduleerimissagedus võimaldab täpsemat ja kiiremat asendi määramist.
Kodulabori Mootorite mooduli plaadil on kaks pistikut RC servomootorite ühendamiseks. Pistikute PWM signaali otsad on ühendatud mikrokontrolleri PB5 ja PB6 viikudega, mille alternatiivfunktsioonideks on 16-bitise taimer 1 võrdlusüksuste A ja B väljundid. Taimer 1 on võimeline raudvaraliselt tekitama PWM signaali ja seetõttu on mootorite juhtimine programmis väga lihtne. Keerulisem on ainult taimeri seadistamine.
Taimer 1 tuleb seadistada PWM signaali tekitamise režiimi, kus taimeri maksimaalne väärtus on määratud ICR registriga. Taimeri taktijaguri ja programmis muudetava maksimaalse väärtusega saab täpselt ära määrata servomootori juhtimiseks vajaliku PWM signaali sageduse. Taimeri võrdlusregistriga saab määrata kummagi PWM signaali kõrge poolperioodi pikkuse. Taimeritel on nimelt spetsiaalsed võrdlusüksused, mis jälgivad loenduri väärtust ja kui see saab samaks võrdlusregistri väärtusega, siis muudavad võrdlusüksuse väljundi väärtust. Järgnevalt on toodud servomootoreid juhtiva Kodulabori teegi programmikood, mis universaalsuse eesmärgil kasutab makrofunktsioonidega määratud taimeri parameetreid. Näiteks kasutatakse perioodi leidmiseks F_CPU konstanti, mis tähistab mikrokontrolleri taktsagedust. Makrodega ei pea taimeri parameetreid erinevate taktsageduste jaoks ise välja arvutama ja kompilaator teisendab makrodega tehted niikuinii konstantideks, nii et programmimälu ei suurene ja ei võta ka rohkem täitmisaega.
// // Taimeri väärtus PWM täisperioodi (20 ms) saavutamiseks. // F_CPU on mikrokontrolleri taktsagedus, mis jagatakse 8-ga // ja 50 hertsiga. // #define PWM_PERIOD (F_CPU / 8 / 50) // // PWM servo keskasend (1,5 ms / 20 ms) // Keskasend saadakse täisperioodist 15/200 võtmisega // #define PWM_MIDDLE_POS (PWM_PERIOD * 15 / 200) // // Kordamistegur, et protsentidest (-100% kuni 100%) vajalik periood saada // +1 liidetakse selleks, et poolperiood kindlasti ulatuks 1 ja 2 ms // piiridesse või siis natuke üle. // #define PWM_RATIO (PWM_PERIOD / 20 / 2 / 100 + 1) // // Viikude seadistus // static pin servo_pins[2] = { PIN(B, 5), PIN(B, 6) }; // // Määratud servomootori tööks valmistamine. // void servomotor_init(unsigned char index) { // PWM signaali viik väljundiks pin_setup_output(servo_pins[index]); // Taimer 1 seadistamine // Taktijagur 8 // Kiire PWM režiim kus TOP = ICR // OUTA ja OUTB võrdusel madalaks timer1_init_fast_pwm( TIMER1_PRESCALE_8, TIMER1_FAST_PWM_TOP_ICR, TIMER1_FAST_PWM_OUTPUT_CLEAR_ON_MATCH, TIMER1_FAST_PWM_OUTPUT_CLEAR_ON_MATCH, TIMER1_FAST_PWM_OUTPUT_DISABLE); // Perioodi määramine maksimaalse väärtuse kaudu timer1_set_input_capture_value(PWM_PERIOD); } // // Servomootori positsiooni määramine // Positsiooni parameeter on -100 kuni 100 protsenti // void servomotor_position(unsigned char index, signed short position) { switch (index) { case 0: timer1_set_compare_match_unitA_value( PWM_MIDDLE_POS + position * PWM_RATIO); break; case 1: timer1_set_compare_match_unitB_value( PWM_MIDDLE_POS + position * PWM_RATIO); break; } }
Näiteprogramm kasutab kirjeldatud Kodulabori teegi funktsioone. Programmi alguses pannakse esimese servomootori PWM signaali genereeriv taimer tööle servomotor_init funktsiooniga. Servomootori asendi väärtus saadakse analoog-digitaalmuunduri kanalist 3, kuhu on Andurite mooduli plaadil ühendatud potentsiomeeter. Et servomootori juhtimiseks vajalikku -100 kuni 100 vahemikku saavutada, lahutatakse ADC väärtusest pool maksimumi (ehk 512) ja jagatakse viiega. Tulemuseks on küll ±102, kuid pisike ebatäpsus ei loe, sest servomootorid ise ka erinevad PWM signaali ja pöördenurga suhtelt. Täpseks liigutuseks tuleb rakendustes PWM poolperioodi laius siiski katse- ja eksitusmeetodil määrata. Ka raadiojuhitavate mudelite pultidel on täpseks seadistuseks vastavad võimalused (inglise keeles trim). Programmi käivitades muutub vastavalt potentsiomeetri asendile ka servomootori võlli asend.
// // Kodulabori mootorite mooduli servomootori // testprogramm. // #include <homelab/adc.h> #include <homelab/module/motors.h> // // Põhiprogramm // int main(void) { short position; // ADC seadistamine adc_init(ADC_REF_AVCC, ADC_PRESCALE_8); // Mootori seadistamine servomotor_init(0); // Lõputu tsükkel while (true) { // Potentsiomeetrist positsiooni lugemine ja servo- // mootori piirkonda teisendamine position = ((short)adc_get_value(3) - (short)512) / (short)5; // Servomootori positsiooni määramine servomotor_position(0, position); } }
Vajalikud teadmised: [HW] Mootorite moodul, [AVR] Digitaalsed sisendid-väljundid,
[LIB] Mootorid, [LIB] Viide
Samm-mootoreid kasutatakse laialdaselt täpsust nõudvates rakendustes. Erinevalt alalisvoolumootorist puuduvad samm-mootoris harjad ja kommutaator - selleks on seal mitu eraldiseisvat mähist, mida kommuteeritakse välise elektroonikaga (ajuriga). Rootori pööramine toimub mähiseid sammhaaval kommuteerides, ilma tagasisideta. Siit avaldub ka üks samm-mootorite puudus - mehhaanilise ülekoormuse korral, kui rootor ei pöörle, lähevad sammud sassi ja liikumine muutub ebatäpseks. Mähiste järgi eristatakse kahte liiki samm-mootoreid: unipolaarsed- ja bipolaarsed samm-mootorid. Ehituse järgi jaotatakse neid veel kolmeks:
Muutuva magnetilise takistusega samm-mootorites on hambulised mähised ja hambuline rauast rootor. Suurim tõmbejõud tekib mõlema poole hammaste kattumisel. Püsimagnetiga samm-mootorites on, nagu nimigi ütleb, püsimagnet, mis orienteerub vastavalt mähise polaarsusele. Hübriidides on kasutusel mõlemad tehnoloogiad.
Sõltuvalt samm-mootori mudelist läheb mootori võlli ühe täispöörde (360 kraadi) tegemiseks vaja sadu kommuteerimissamme. Stabiilse ja sujuva liikumise tagamiseks kasutatakse sobivat juhtelektroonikat, mis juhib mootorit vastavalt selle parameetritele (rootori inerts, pöördemoment, resonants jne.). Lisaks võib juhtelektroonikas rakendada erinevaid kommuteerimise meetodeid. Järjest ühe mähise kaupa kommuteerimist nimetatakse täissammuks, kuid vaheldumisi ühe ja kahe mähise kommuteerimist nimetatakse poolsammuks. Kasutatakse ka sinusoidaalset mikrosammu, mis annab eriti täpse ja sujuva juhtimise.
Unipolaarne samm-mootor
Unipolaarne samm-mootor on viie või kuue juhtmega. Vastavalt ajami skeemile käivitatakse korraga ainult üks neljandik mähistest. Vcc liinid on tavaliselt ühendatud mootori positiivse toitepingega. Mähiste otsad 1a, 1b, 2a, ja 2b ühendatakse kommuteerimisel läbi transistoride ainult maaga, mistõttu nende juhtelektroonika on suhteliselt lihtne.
Bipolaarne samm-mootor
Bipolaarne samm-mootor erineb unipolaarsest samm-mootorist selle poolest, et mähiste polaarsust muudetakse kommutatsiooni ajal. Korraga aktiveeritakse pooled mähised, mis tagab võrreldes unipolaarse samm-mootoritega suurema efektiivsuse. Bipolaarsetel samm-mootoritel on neli juhet, mis ühendatakse kõik eraldi poolsillaga. Kommuteerimisel rakendavad poolsillad mähiste otstele kas positiivset või negatiivset pinget. Unipolaarseid samm-mootoreid saab käivitada ka bipolaarse ajuri abil: selleks tuleb ühendada vaid mähiste liinid 1a, 1b, 2a ja 2b (Vcc jääb ühendamata).
Mõlemat liiki mähisega samm-mootori juhtimiseks vajalikku kommutatsiooni täissammu ja poolsammu režiimis kujutab järgnev tabel. Kuna unipolaarsete samm-mootorite ajurite puhul toimub vaid transistoride avamine, siis nende samme on kujutatud loogiliste arvudega 0 ja 1. Bipolaarse samm-mootori juhtimine võib vajada rohkem signaale, ja selle samme on kujutatud ajuri väljundite polaarsusega.
Unipolaarne | Bipolaarne | |||||||
---|---|---|---|---|---|---|---|---|
Samm | 1A | 2A | 1B | 2B | 1A | 2A | 1B | 2B |
Täissamm | ||||||||
1 | 1 | 0 | 0 | 0 | + | - | - | - |
2 | 0 | 1 | 0 | 0 | - | + | - | - |
3 | 0 | 0 | 1 | 0 | - | - | + | - |
4 | 0 | 0 | 0 | 1 | - | - | - | + |
Poolsamm | ||||||||
1 | 1 | 0 | 0 | 0 | + | - | - | - |
2 | 1 | 1 | 0 | 0 | + | + | - | - |
3 | 0 | 1 | 0 | 0 | - | + | - | - |
4 | 0 | 1 | 1 | 0 | - | + | + | - |
5 | 0 | 0 | 1 | 0 | - | - | + | - |
6 | 0 | 0 | 1 | 1 | - | - | + | + |
7 | 0 | 0 | 0 | 1 | - | - | - | + |
8 | 1 | 0 | 0 | 1 | + | - | - | + |
Harjutuse eesmärk on tööle panna bipolaarne samm-mootor, mille asemel saab eespool nimetatud meetodil kasutada ka unipolaarset samm-mootorit. Mootorite mooduli plaadil on olemas kaks ajurit L293D, mida tuleb mikrokontrollerist nelja sisendviiguga juhtida. Iga viik tähistab ühe mähise otsa polaarsust. Mähiseotsa pinge on positiivne, kui viik on kõrge, ja negatiivne, kui viik on madal. Otstele 1A, 1B, 2A ja 2B vastavad mikrokontrolleri viigud on PB0, PB1, PB2 ja PB3.
Bipolaarse samm-mootori juhtimiseks on Kodulabori teegis olemas funktsioon bipolar_init, mis seadistab viigud väljundiks ja funktsioon bipolar_halfstep, mis teostab pöörlemist määratud arvu poolsammude võrra. Kommuteerimine toimub poolsammude tabeli järgi, mille tekitamiseks kasutatakse keerukamaid bitioperatsioone.
// // Bipolaarse samm-mootori juhtimise ettevalmistamine // void bipolar_init(void) { DDRB |= 0x0F; PORTB &= 0xF0; } // // Bipolaarse samm-mootori liigutamine poolsammudega // void bipolar_halfstep(signed char dir, unsigned short num_steps, unsigned char speed) { unsigned short i; unsigned char pattern, state1 = 0, state2 = 1; // Suuna kindlustamine +- 1 dir = ((dir < 0) ? -1 : +1); // Poolsammude teostamine for (i = 0; i < num_steps; i++) { state1 += dir; state2 += dir; // Mustri loomine pattern = (1 << ((state1 % 8) >> 1)) | (1 << ((state2 % 8) >> 1)); // Väljundi määramine PORTB = (PORTB & 0xF0) | (pattern & 0x0F); // Pausi tegemine sammu teostamise ootamiseks sw_delay_ms(speed); } // Mootori peatamine PORTB &= 0xF0; }
Funktsioonide kasutamist demonstreerib näiteprogramm, mis pöörab mootorit vaheldumisi ühele ja teisele poole 200 poolsammu. Mootori pöörlemise kiiruse määrab sammude vahel tehtava pausi pikkus. Kui paus liiga väikeseks seada, ei jõua mootor rootori intertsi tõttu pööret teostada ja võll ei liigu.
// // Kodulabori mootorite mooduli bipolaarse // samm-mootori testprogramm // #include <homelab/module/motors.h> // // Põhiprogramm // int main(void) { // Mootori seadistamine bipolar_init(); // Lõputu tsükkel while (true) { // Pööramine ühele poole 200 poolsammu kiirusega 30 ms/samm bipolar_halfstep(+1, 200, 30); // Pööramine teisele poole 200 poolsammu kiirusega 30 ms/samm bipolar_halfstep(-1, 200, 30); } }
Eesmärgiks on koostada programm, mis täidab kirjeldatud ülesannet.
Mikrokontrolleritega saab juhtida täitureid, lugeda andurite väärtusi ja teha mitmeid muid toiminguid, kuid alati jääb vajadus ühendada seadmeid, millega ei saa suhelda lihtsaid digitaalseid signaale edastades. Põhjuseks võib olla näiteks seadme juhtimiseks vajaminevate juhtsignaalide liiga suur arv või suur andmehulk. Seepärast on nii mikrokontrolleritele kui muule elektroonikale välja arendatud terve hulk erinevaid andmesideliideste standardeid. Standardid määravad ära signaalide elektrilised parameetrid ja nende signaalide edastamise reeglid ehk protokolli.
Üks lihtne näide protokollist on morse kood, kus infot edastatakse piiksude ja pausidega ning nende pikkustega. Sarnaselt toimivad ka digitaalsed andmesideprotokollid, kus infot edastatakse bitiväärtustega ja olenevalt liidesest vahel ka moduleeritud kujul. Erinevaid andmesideliideseid koos nende protokollidega on loodud küll vastavalt vajadusele, kuid edastamist vajavad andmehulgad on alati kasvanud ja pidevalt lisandub uusi meetodeid. Rahulikum on olukord elektroonikakomponentidevahelise andmesidega, kus juba pikka aega kasutatakse I²C, SPI ja UART liideseid. Traditsioonilisemad süsteemidevahelised sideliidesed on RS-232, RS-485, LIN ja CAN, kuid palju mikrokontrollereid toodetakse ka juba USB, Ethernet ja juhtmevaba ZigBee liidestega. Käesolev peatükk aga keskendub Kodulaborile, kus peamine andmesideliides on RS-232.
Vajalikud teadmised: [HW] Kontrollermoodul, [AVR] USART, [LIB] Jadaliides,
[LIB] Alfabeetiline LCD
RS-232 on füüsilise andmesideliidese standard, mida kasutatakse binaarandmete edastamiseks. Standard on kasutusel peamiselt arvutite jadaportides, mida kutsutakse kõnekeeles ka “COM” portideks. Tänapäeval on RS-232 suures osas asendunud USB liidesega, kuid oma lihtsuse tõttu kasutatakse hobirakendustes RS-232 edukalt edasi, eriti veel siis, kui on olemas USB - RS-232 muundurid. RS-232 standard määrab ära pistikud, elektrilised parameetrid ja signaalide tähenduse, kuid mitte protokolli.
RS-232 liidest kasutatakse peamiselt koos UART nime kandva riistvaralise andmesidemooduliga, millel on protokoll standardiseeritud, kuid mis jällegi ei määra ära pistikuid jms. Seega RS-232 täiendab UART-i. Kuna UART on enamasti üks perifeeriamoodul mikrokontrolleris, mille digitaalsed sisendid-väljundid ei vasta RS-232 elektrilistele parameetritele, siis omavahel viiakse need kokku spetsiaalsete nivoomuunduritega. Üks tuntumaid RS-232 ja TTL/CMOS vahelisi nivoomuundureid on näiteks MAX232.
UART on lahtitõlgituna “universaalne asünkroonne vastuvõtja/saatja” (inglise keeles universal asynchronous receiver/transmitter). USART on peaaegu sama asi, kuid selle erinevusega, et andmeid edastatakse koos taktsignaaliga. UART-i võib nimetada ka jadaliideseks. Jadaliides on andmete ülekandmise mehhanism, kus iga bitt edastatakse ükshaaval. Näiteks selleks, et edastada 1 bait, edastatakse kindla ajaintervalliga 8 bitti. Ehk siis füüsiliselt toimub jadaliidese liinil, mis on 1 mikrokontrolleri viik, kindla ajavahemiku järel selle viigu pingeväärtuse muutus kõrgeks või madalaks. Jadaliidesega on üldjuhul ühendatud 2 seadet, millest üks edastab infot (viigu väärtust muutes) ja teine võtab seda vastu (viigu väärtust registreerides). Edastava viigu lühend on TX, vastuvõtval RX. Info liigub ühel liinil alati ühes suunas. Andmete teistpidi saatmiseks kasutatakse teist liini. Kui andmeid liigutatakse kahel liinil samaaegselt on tegu täisdupleks-siiniga.
Andmete edastamine toimub UART liideses kaadri (inglise keeles frame) kaupa, milles on andmebitte olenevalt seadistusest 5 kuni 9. Enamlevinud andmehulk on siiski 8 bitti, ehk 1 bait. Peale andmebittide edastatakse kaadriga ka lisabitte, mille abil toimub andmete saabumise ja lõppemise hetke äratundmine vastuvõtja poolel. Esimest neist nimetatakse startbitiks, mis on alati 0, teist aga stoppbitiks (või bittideks), mis on alati 1. Enne stoppbitti võib tulla ka paarsuse bitt, mida kasutakse andmete korrektsuse kontrolliks. Paarsuse bitt näitab, kas andmebittide hulgas on paaris või paaritu arv ühtesid. See, kumba näitu see omab, sõltub UART liidese häälestusest. Paarsuse bitti tänapäeval enam üldjuhul ei kasutata ja selle saab häälestuses ka ära keelata. Nii nagu saab paarsuse bitti seadistada, saab ka andmebittide ja stoppbittide arvu.
Peale kaadri struktuuri on veel üks tähtis parameeter - see on boodikiirus (inglise keeles baud rate), millega määratakse edastatavate sümbolite arv ühes sekundis. Bood näitab nimelt sümbolite arvu. UART puhul on 1 bood aga 1 bitt ja seepärast kaadri juures bittidest saigi räägitud. Põhimõtteliselt võib andmete edastamiseks kasutada ükskõik millist boodikiirust, kuid on olemas hulk üldkasutavaid boodikiirusi, mida tasub kasutada. Näiteks: 9600 bps, 19200 bps, 38400 bps, 57600 bps, 115200 bps.
Lisainformatsioonina võiks teada, et RS-232 standard sisaldab peale andmesignaalide (RX, TX) veel andmevoo-kontrolli viike DTR, DCD, DSR, RI, RTS ja CTS, mida kasutatakse seadmetevahelise suhtluse juhtimiseks. Näiteks võib seade nende kaudu teada anda, kas ta on valmis andmeid vastu võtma või mitte. Kuna RS-232 liidese originaaleesmärk oli ühendada arvuteid modemiga, siis mõned signaalid on (pigem olid) kasutusel telefoniliini seisundi näitamiseks.
Kodulabori Kontrollermooduli plaadil on RS-232 isa-tüüpi pesa. Selle kaudu saab kontrolleri arvutiga või teise kontrolleriga ühendada. Arvutiga ühendamiseks tuleb kasutada tavalist pööramata kaablit, mille üks pistik on ema-tüüpi, teine isa-tüüpi. Teise kontrolleriga ühendamiseks tuleb kasutada kaablit, kus RX ja TX ning vookontrolli signaalid on risti keeratud ja mõlemad pistikud on ema-tüüpi. Pööratud kaablit nimetatakse ka nullmodemi kaabliks. Järgnevalt on toodud UART jadaliidese kasutamise näiteprogramm. Programm saadab käivitades RS-232 liidese kaudu tervituse ja kuvab sõnumeid, mis saabuvad. Kasutatud on LCD ja USART teeke.
// // Kodulabori Kontrollerimooduli arvutiga RS-232 kaudu liidestamine. // Näide kasutab Digitaalset sisend-väljundmoodulit koos LCD ekraaniga. // Arvuti terminalis sisestatud tekst kuvatakse LCD-l. // #include <homelab/usart.h> #include <homelab/module/lcd_alpha.h> // // USART liidese määramine // usart port = USART(0); // // Põhiprogramm // int main(void) { char c; unsigned char row = 1; // USART liidese seadistamine usart_init_async(port, USART_DATABITS_8, USART_STOPBITS_ONE, USART_PARITY_NONE, USART_BAUDRATE_ASYNC(9600)); // LCD ekraani seadistamine lcd_alpha_init(LCD_ALPHA_DISP_ON_BLINK); // Ekraanil tervituse ütlemine lcd_alpha_write_string("Ootan teadet"); // Kursori teise rea algusesse viimine lcd_alpha_goto_xy(0, row); // Arvutile tere ütlemine usart_send_string(port, "Tere, kirjuta midagi!\r\n"); // Lõputu tsükkel while (true) { // Jadaliidesest märgi lugemine if (usart_try_read_char(port, &c)) { // Kas tegu on reavahetuse märgiga? if (c = '\r') { // Rea vahetamine row = 1 - row; // Rea tühjendamine eelmisest teatest lcd_alpha_clear_line(row); } else { // Märgi otse ekraanile väljastamine lcd_alpha_write_char(c); } } } }
Windows XP operatsioonisüsteemiga on kaasas programm HyperTerminal. See avaneb Start menüüst Accessories → Communications → HyperTerminal valides. Ühenduse seadeteks valida 9600 bps, 1 start- ja 1 stoppbitt ilma paarsuse- ja vookontrollita. Kui HyperTerminal on avatud mikrokontrolleri tööle panemise ajal, tekib ekraanile tervitussõnum. Aknas sisestatud tähed kuvatakse aga alfabeetilise LCD ekraanil. Klahvi Enter vajutus muudab rida LCD ekraanil.
Eesmärgiks on koostada programm, mis täidab kirjeldatud ülesannet.
Näidisprojektis üritatakse tuua konkreetsed juhised, kuidas koostada projekti dokumentatsiooni, milliseid teemasid tuleks käsitleda ja mis iga teema alla kirjutada. Praktilisuse huvides on näiteks toodud ühe tüüpilise projekti dokumentatsioon. Paraku on projekti dokumentatsioon tavaliselt tänu graafilisele materjalile küllalt mahukas ja poleks siia raamatusse kuidagi ära mahtunud. Sellest tulenevalt on näiteprojektis püütud kajastada kõiki punkte, kuid mitte täies mahus. Näiteks joonistest on toodud ainult ühe detaili joonis ja elektroonikaskeemi juures samuti ainult ühe plaadi skeem. Reaalses dokumentatsioonis tuleks sellegipoolest lisada kõigi loodud detailide joonised ja elektroonikaplaatide skeemid. Loodetavasti on näiteprojektist abi ka õpetajatele, kellel on seeläbi lihtsam seletada, mida ta ootab õpilastelt projekti lõpus ja kuidas seda esitada. Sõltuvalt õpilaste tasemest ja konkreetsest situatsioonist võib vabalt osa punkte dokumentatsioonist välja jätta.
Lihtsa mehhatroonikaseadme koostamisel on vaja projekteerida seadme konstruktsioon ja mehaanika, elektroonika ja sensoorika ning juhtimine ja tarkvara. Projektide lõppemisel tuleks koostada töö aruanne - dokumentatsioon, mis peaks koosnema vähemalt järgmistest sisulistest punktidest:
Järgnevalt on esitatud näiteprojekt, mis näitlikustab dokumentatsiooni koostamist ja on abiks oma projekti aruande koostamiseks. Aruanne on raamatu piiratud mahu tõttu paraku lühendatud kujul, kuid püütud on näidata dokumenteerimise erinevaid aspekte.
Liikurrobot (mobiilne robot) on üks tüüpilisemaid roboteid, mida soovitakse ehitada. Väga populaarsed on sumorobotid, mängurobotid (jalgpall, võrkpall jms.), päästeoperatsioone simuleerivad (tuletõrje, isiku või objekti leidmine jms.) robotid ja mitmed muud. Sellistele robotitele korraldatakse maailmas ja ka Eestis mitmeid erinevaid võistlusi ja on isegi kujunenud välja standardklassid (näiteks sumorobotid). Kõigi seda tüüpi robotite ühiseks jooneks on tavaliselt liikuv platvorm, mis võib olla küll erineva konstruktsiooni ja võimekusega, kuid oma baasfunktsionaalsuselt jääb samaks. Selleks baasfunktsionaalsuseks on eelkõige mootorite juhtimine ja baasnavigeerimine, mis hõlmab endas objektidest eemalhoidmist ja soovitud sihtkohta sõitmist. Baasfunktsionaalsusele lisandub tavaliselt ülesande spetsiifiline funktsionaalsus, mis projekteeritakse lähtuvalt projektile esitatavatest nõuetest ja võimalustest.
Alljärgnevalt vaatame ühte tüüpilist liikurroboti platvormi projekti dokumentatsiooni ja selle projekteerimise erinevaid etappe.
Projekteerida ja valmistada Kodulabori komponentide baasil multifunktsionaalne liikurroboti platvorm koos baasnavigatsiooni funktsionaalsusega. Robotplatvorm peab võimaldama lihtsalt muuta tema operatiivfunktsionaalsust, varustades teda erinevate seadmetega:
Robot peab olema võimeline liikuma tasasel pinnal sisetingimustes.
Süsteemi üldine mudel on esitatud plokkdiagrammidena. Süsteemi mudel kirjeldab süsteemi struktuuri, käitumist jt. olulisi aspekte. Alljärgnevalt on näiteks toodud süsteemi struktuuri üldine hierarhiline mudel.
Antud ülesande lahenduseks kasutas meeskond ajurünnaku metoodikat ja genereeris 3 põhimõtteliselt erinevat lahendust. Koostati hindamismaatriks, mille abil leiti optimaalseim konstruktsioon. Lahenduste põhiline erinevus seisnes erinevates liikumisskeemides.
Lihtsustatud hindamismaatriks oli järgmine:
Funktsioon/Lahendus | I | II | III | Kaalutegur |
---|---|---|---|---|
Maksumus | 3 | 4 | 6 | 0,8 |
Valmistamise keerukus | 2 | 4 | 7 | 0,7 |
Manööverdamisvõime | 4 | 8 | 8 | 0,5 |
Läbivus | 5 | 8 | 2 | 0,3 |
Kodulabori rakendatavus | 5 | 4 | 5 | 0,9 |
Kaal | 5 | 6 | 7 | 0,8 |
Kokku (koos kaaluteguriga) | 19 | 27 | 28 |
Hindamisskaala oli 1-10 punkti ja kaalutegur 0-1. Kaalutegurid olid valitud lähtuvalt süsteemile esitatud nõuetest ja piirangutest. Kuigi näiteks lahendus 2 oli oluliselt võimekam raskel maastikul liikumisel, ei olnud seda lähteülesandes nõutud ja vastava funktsionaalsuse kaalutegur oli sellest tulenevalt madal.
Hindamise tulemusena osutus antud ülesande optimaalseimaks lahenduseks ratastel liikuv kahe eraldi mootoriga platvorm. Edasine töö jätkus valitud lahenduse edasiarendusega reaalseks süsteemiks.
Mehaanika püüti valmistada võimalikult lihtne, järgides samal ajal modulaarsuse põhimõtet. Esimene ja tagumine põrkeraud on identsed moodulid. Elektroonika osas on kasutatud kolme moodulit, mis on paigutatud üksteise peale, võimaldades nii lihtsaid ribakaabelühendusi ja tagades samal ajal moodulite suhteliselt lihtsa vahetatavuse. Mootoriteks on valitud Kodulabori komplektis olevad integreeritud reduktori ja koodriga mootorid, mis on ühendatud otse mootorite ajurplaadiga. Ratasteks on kasutatud mudellennuki rattaid, mis on väga kerged ja piisavalt tugevad antud roboti jaoks. Valmistamise lihtsuse huvides on roboti alusplaat ja pealmine plaat identsed. Plaadid on varustatud avadega, võimaldades nii pealmisele plaadile kinnitada erinevaid seadmeid. Kahe plaadi vahele mahub lisaks elektroonikamoodulitele ka aku.
Eraldi on projekteeritud roboti põrkeraud, mis on integreeritud puute- ja joonejälgimise anduritega. Põrkerauad on valmistatud trükiplaatidest, omades lisaks konstruktsioonile ka elektriühendusi. Joonejälgimise andurid on joodetud otse põrkeraua alumisele plaadile. Puuteandurid (mikrolülitid) on paigutatud kahe põrkeraua plaadi vahele ja eestpoolt kaetud ühtse kummiribaga. Kummiriba summutab põrkejõudu ja võimaldab samal ajal täpsemalt tuvastada, mis suunalt löök tuli.
Süsteemi elektroonika on kirjeldatud põhimõttelahendusena ja klassikalise elektriskeemina koos trükiplaadi montaažiskeemina.
Näitena on toodud roboti põrkeraua joonejälgimise andurite elektriskeem ja vastava trükiplaadi (PCB) montaažiskeemiga.
Roboti juhtimine tuleneb süsteemi käitumismudelist ja on määratud lähteülesande funktsionaalsusega ning nõuete ja piirangutega. Süsteemi käitumismudelist luuakse täpsustatud juhtprogrammi algoritm, millest omakorda lähtutakse tarkvara programmikoodi koostamisel. Kõik kolm taset (käitumismudel-algoritm-lähtekood) peavad olema omavahel kooskõlas.
Algoritm kirjeldab süsteemi juhtloogikat ja on esitatud plokkdiagrammina. Lihtsama algoritmi koostamiseks piisab paarist elemendist ja nendevaheliste seoste kirjeldamisest. Kui roboti algoritm on koostatud korrektselt, siis on sellest roboti juhtprogrammi juba suhteliselt lihtne koostada. Algoritmis on kasutatud põhiliselt kahte erinevat objekti: ümardatud nurkadega ristkülik, mis tähistab mingit tegevust ja väike romb mingi tingimuse kontrollimiseks, millele järgneb vastavalt kontrolli tulemusena edasiste tegevuste käivitamine.
Algoritmis kasutatud tähiste tähendused:
Tähis | Tähendus | 0 | 1 | -1 |
---|---|---|---|---|
M1 | vasak mootor | seisab | pöörleb päripäeva | pöörleb vastupäeva |
M2 | parem mootor | seisab | pöörleb päripäeva | pöörleb vastupäeva |
F | esimene keskmine puuteandur | signaal puudub | signaal olemas | |
FR | esimene parem puuteandur | signaal puudub | signaal olemas | |
FL | esimene vasak puuteandur | signaal puudub | signaal olemas | |
d | viide |
Lihtne navigeerimine
#include <homelab/module/motors.h> #include <homelab/pin.h> #include <homelab/delay.h> // Põrkeandurite viikude defineerimine pin front = PIN(C, 0); pin frontleft = PIN(C, 1); pin frontright = PIN(C, 2); // // Põhiprogramm // int main(void) { // Mootorite 0 ja 1 algseadistamine dcmotor_init(0); dcmotor_init(1); // Andurite viigud sisendiks pin_setup_input_with_pullup(front); pin_setup_input_with_pullup(frontleft); pin_setup_input_with_pullup(frontright); // Lõputu tsükkel while (true) { // Mootorite päripäeva käivitamine dcmotor_drive(0, 1); dcmotor_drive(1, 1); // Keskmise anduri signaali kontroll if (pin_get_value(front)) { // Mootorite reverseerimine dcmotor_drive(0, -1); dcmotor_drive(1, -1); // Paus 1 sekund sw_delay_ms(1000); // Vasaku mootori päripäeva käivitamine dcmotor_drive(0, 1); // Paus 2 sekundit sw_delay_ms(2000); } // Vasaku anduri signaali kontroll else if (pin_get_value(frontleft)) { // Parema mootori reverseerimine dcmotor_drive(1, -1); // Paus 2 sekundit sw_delay_ms(2000); } // Parema anduri signaali kontroll else if (pin_get_value(frontright)) { // Vasaku mootori reverseerimine dcmotor_drive(0, -1); // Paus 2 sekundit sw_delay_ms(2000); } } }
Projekti raames valminud robotplatvorm on valmistatud üldjoontes plastikust, välja arvatud mootori kinnitused, mis on valmistatud alumiiniumprofiilist. Elektroonikamoodulid on paigutatud üksteise peale, aku on lahtiselt kahe plaadi vahel. Põrkerauad on valmistatud trükkplaadist ja värvitud mustaks. Roboti pealmine plaat on täiesti sile, võimaldades sinna kinnitada erinevaid soovitud seadmeid. Projekti raames paigaldati robotplatvormile lihtne radar, mis koosnes väikesest RC servomootorist ja infrapunaandurist. Teise lahendusena paigaldati platvormile intelligentne kaameramoodul masinnägemise ülesannete lahendamiseks. Mõlemad variandid on näidatud allolevatel piltidel. Kolmandaks seadmeks katsetati standardmanipulaatorit, mille lülisid juhitakse samuti standardsete RC servomootoritega, kasutades nende ajuri juhtimiseks jadaliidest.
Majanduslik kalkulatsioon hõlmab endas komponentide maksumust ja roboti detailide valmistamise ning koostamise kulusid.
Komponentide maksumuse tabel
Komponent | Mark | Kogus | Hind | Maksumus |
---|---|---|---|---|
Mootor | M LE149.6.43 | 2 | 500.- | 1000.- |
Mikrokontroller | uC ATmega128 | 1 | 900.- | 900.- |
Mootorite juhtplaat | Actuator Board v1.2 | 1 | 700.- | 700.- |
Toiteplaat | TP | 1 | 500.- | 500.- |
Joonejälgimise andurid | LFS QRD1114 | 8 | 30.- | 240.- |
Puuteandurid | TS Microswitch | 8 | 25.- | 200.- |
Kere plaat | ABS | 4 | 50.- | 200.- |
Trükiplaadi toorik | 2 | 50.- | 100.- | |
Mootorikinnituse profiil | Al-L | 2 | 10.- | 20.- |
Ratas | 60/10 mm | 2 | 30.- | 60.- |
Aku | NI-MH 9,6 V | 1 | 350.- | 350.- |
Erinevad kaablid | 10 | 20.- | 200.- | |
Mutrid-poldid | 1 | 50.- | 50.- | |
Muud tarvikud | 1 | 100.- | 100.- | |
Kokku | 4620.- |
Hinnanguline tööjõu- ja tootmiskulu üksikeksemplari korral.
Töö | Aeg (h) | Hind | Maksumus |
---|---|---|---|
Konstruktsioonidetailide freesimine | 1 | 300.- | 300.- |
Trükiplaatide (põrkerauad) freesimine | 0,5 | 500.- | 250.- |
Roboti konstruktsiooni koostamine | 0,5 | 250.- | 125.- |
Põrkeraudade koostamine (komponentide jootmine) | 1 | 300.- | 300.- |
Programmeerimine | 5 | 300.- | 1500.- |
Dokumentatsiooni koostamine | 3 | 250.- | 750.- |
Kokku | 11 | 3225.- |
Roboti hinnanguline maksumus kokku 7845.-
Arvutatud roboti maksumus on siiski hinnanguline, kuna tegemist on õppeotstarbelise projektiga, kus enamik tööd ja koostamist on tehtud oluliselt suuremas mahus, kuid otsese rahalise tasuta. Seetõttu on töö- ja ajakulu ligikaudne ja ei kajasta tegelikku olukorda.
Mehhatroonikasüsteem (Robot) on loodud meeskonnatööna ja kindla ajakava ning eelarvega, omades seega enamuse olulisi projekti tunnuseid. Projektijuhtimise seisukohalt olid olulised tegevused: aja planeerimine, meeskonnatöö planeerimine ja juhtimine, eelarve jälgimine ja vahendite hankimine, jooksev aruandlus juhendajale, lõpptulemuse presentatsioon ja dokumenteerimine. Projekti aruandele lisatakse töögruppide koosolekute protokollid, projekti plaan (soovitavalt Gantti diagrammina), ressursijaotus (k.a. inimressurss) ja planeeritud ning tegelik eelarve. Näiteks on toodud lihtne tegevuste plaan Gantti diagrammina.
Majanduslik kalkulatsioon näitas meile, et roboti tootmishind on üsna kõrge, eriti kui tegemist on ainueksemplariga, kuid jäi siiski lähteülesandes etteantud piiridesse. Tootmise hinda saaks kindlasti oluliselt alandada, optimeerides komponentide ja materjalikulu ning tootes korraga suurema koguse roboteid. Projekti käigus tutvusime mehhatroonikasüsteemi projekteerimise, valmistamise ja testimisega, mis andis meile esmakordse sellelaadse kogemuse.
Töö lõpus selgus tõsiasi, et roboti korralikuks töötamiseks on vaja oluliselt rohkem aega planeerida testimisele, seda eriti tarkvara osas. Erinevad moodulid ei pruugi alati koos korrektselt töötada, kuigi eraldi katsetades oli kõik korras. See näitab, et süsteemi moodulite integreerimine on tõsine väljakutse ja selleks tuleb planeerida oluliselt rohkem aega ja ressurssi.
Kokkuvõteks arvame, et projekt oli väga huvitav ja hariv ning andis aimu integreeritud süsteemide projekteerimisest ja valmistamisest.
Kui oled jõudnud selle raamatuga lõpule, on sul juba päris palju praktilisi oskusi nii programmeerimise kui ka erinevate seadmete kasutamise osas. Kui oled näiteid ja harjutusi kasutanud valikuliselt, ei ole ka midagi katki. Loodetavasti aitasid need leida lahenduse probleemile, millega tegelesid ja andsid juurde natuke ka teoreetilisi teadmisi. Järgmine loogiline samm oleks hakata koostama intelligentseid seadmeid vastavalt siis oma huviks või ka tööstuslikele rakendustele. Õpilastel soovitaks vaadata ringi ja osaleda mõnel robootika võistlusel või konkursil, näiteks Robotex, Baltic Robot Sumo Cup jms. Kindlasti tasuks aga saadud teadmisi ja oskusi rakendada ka oma igapäevaelu lihtsamaks, turvalisemaks ja huvitavamaks muutmiseks. Näiteks võite endale koju, suvilasse või garaaži lihtsa vaevaga ehitada turvarakenduse, mis kontrollib erinevate anduritega toimuvat ja vajadusel käivitab alarmi ning edastab sõnumi omanikule.
Kui jääd hätta, küsi abi. See raamat ei ole lõplik ja areneb edasi elektroonilises versioonis. Raamat on üks osa robootika õppimise kontseptsioonist, mis sisaldab endas lisaks spetsiifilist veebikeskkonda, mis toetab kogu õpet. Peale infomaterjalide leiab veebist ka kasutajafoorumi, kus saad kindlasti vastused oma tekkinud küsimustele. Raamatu elektroonilises versioonis on lisamaterjale ja peatükid ka sellistel teemadel, nagu näiteks Kohtvõrk (Ethernet), Sinihammas (Bluetooth), RFID (Radio-frequency identification), Masinnägemine (Machine Vision) jt.
Õpetajale: Registreerige ennast kindlasti ka robootikaõppe tugikeskkonnas ning andke administraatorile märku, et olete õpetaja. Siis saate juurdepääsu harjutusülesannete lahendustele ja kordamisküsimuste vastustele ;)
Veebikeskkond asub aadressil
http://www.roboticlab.eu
Mikrokontrollerite arendusplaadid, andurid ja programmaatorid –
KÕIK VAJALIK HOBIROBOOTIKAKS e-poest http://pood.ittgroup.ee
Arduino, Mikrovega, Devantech Ltd (Robot Electronics) ametlik esindaja Eestis.