====== Programmeerimine ====== ===== Programmi struktuur ===== Arduino programmeerimiskeeles on kohustuslikud funktsioonid //setup()// ja //loop()//, mis peavad alati eksisteerima, et kood kompileeruks. Esimest neist läbitakse vaid ühe korra ja on mõeldud üldjuhul seadistuste tegemiseks. Teist funktsiooni kutsutakse välja pidevalt ehk tegemist on lõpmatu tsükliga. **Näide Arduino programmi struktuurist:** /* Programmi selgitav kommentaar ja autor */ // Makro-deklaratsioonid #define PI 3.141 // Globaalsed muutujad int e; // Seadistuste funktsioon void setup() { // Funktsiooni läbitakse vaid ühe korra } // Peatsükkel void loop() { // Funktsiooni täidetakse korduvalt, // Tavaliselt on siin programmi põhitegevused } ===== Kommentaarid ===== 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äited kahte liiki kommentaarist:** // Üherealine kommentaar // Kommentaariks loetakse kahe kaldkriipsu järel olevat teksti /* Mitmerealine kommentaar Kommentaari algus ja lõpp määratakse kaldkriipsude ja tärnidega */ ===== Muutujad ja konstandid ===== Muutujad ja konstandid on erinevate andmete hoidmiseks defineeritavad mälupesad. Muutujatele saab programmi täitmise ajal omistada erinevaid ühte tüüpi väärtusi, konstantidele omistatakse kindel väärtus ühe korra ja seda programmi täitmise ajal enam ei muudeta. === Andmetüübid === Arduino programmeerimiskeele baasandmetüübid (enamus neist on täisarvud, kaks viimast on ujukomaarvud): ^ Tüüp ^ Miinimum ^ Maksimum ^ Bitte ^ | boolean | false(0) | true(1-255)| 8 | | byte | 0 | 255 | 8 | | (signed) char | -128 | 127 | 8 | | unsigned char | 0 | 255 | 8 | | (signed) int | -32768 | 32767 | 16 | | unsigned int | 0 | 65535 | 16 | | (signed) long | -2 147 483 648 | 2 147 483 647 | 32 | | unsigned long | 0 | 4 294 967 295 | 32 | | float | -3.438 | 3.438 | 32 | | double | -1.7308 | 1.7308 | 64 | Sulgudes olevat sõna //signed// ei pea kasutama, kuna vaikimisi on andmetüübid bipolaarsed. Arduino programmeerimiskeeles on teksti hoidmiseks //String// objekt, mis lubab teha erinevaid tekstitöötluse toiminguid: teksti lisamine ja eemaldamine, võrdlus ning toimingud tähemärkide kaupa.\\ \\ Konstante saab tekitada kahel viisil: * makro #define kaudu * muutuja deklareerimisega lisades ette märksõna //const// === Muutujate deklareerimine ja defineerimine === Muutujate deklareerimisel ehk loomisel peab olema vähemalt 2 elementi: andmetüüp ja nimi. Muutuja deklareerimisel on võimalik see kohe ka algväärtustada ehk defineerida. Muutuja deklareerimisel väljaspool funktsiooni on tegemist globaalse muutujaga ja sellele pääsevad ligi kõik funktsioonid. Globaalsete muutujate väärtused säilivad kuni mikrokontrollerilt toite eemaldamiseni. Muutuja deklareerimisel funktsiooni sees on see kasutatav vaid selles kindlas funktsioonis ja pärast funktsiooni sulgemist kustutatakse kõik lokaalsed muutujad mälust. **Muutuja nime valikul kehtivad reeglid:** * Muutuja nimi võib sisaldada väikseid ja suuri ladina tähestiku tähti a - z, alakriipsu(_) ja numbreid 0-9. * Muutuja nimi peab olema terviklik ehk ei tohi vahel olla tühikuid. * Muutujate nimed on tõstutundlikud: "summa" ja "Summa" deklareerimisel on tegemist kahe eraldi muutujaga. * Muutuja nimi ei tohi alata numbriga. \\ **Soovitused muutujate deklareerimisel:** * Vältida sama nimega globaalsete ja lokaalsete muutujate deklareerimist. * Muutuja nime valikul proovida jääda lühidaks, kuid piisavalt konkreetseks, et oleks selge muutuja eesmärk. * Kasutada eesmisi suuri tähti mitmesõnaliste muutujate deklareerimisel: analoogAndur, vasakServoAsend, indikaatorLedOlek jne. \\ **Näited muutujate deklareerimisest ja defineerimisest:** // Char tüüpi muutuja deklareerimine char c; // Char defineerimine numbriga 65, mis vastab ascii tabeli järgi tähemärgile A c = 65; // Char defineerimine tähemärgiga A // Tähemärkide kasutamisel programmis tuleb need ümbritseda ülakomade vahele c = 'A'; /* String objekti loomine ja teksti omistamine. Rohkem kui ühe tähemärgilise teksti kasutamisel programmis tuleb see ümbritseda jutumärkide vahele. */ String tervitus = "Hello World"; // Konstandi deklareerimine ja väärtuse omistamine const int kalibratsiooniKonstant = 187; // Mitu ühte tüüpi muutujat saab deklareerida ühel real unsigned long x, kahvel, test_systeem, toiteLED; ===== Operaatorid ja tehted ===== === Aritmeetilised === Arduino programmeerimiskeeles toetatud aritmeetilised tehted on liitmine (+), lahutamine (-), korrutamine (*), jagamine (/) ja mooduli võtmine (%). Keerukamate tehete koostamisel tuleb järgida tehete järjekorda. Tehted sooritatakse suunaga vasakult paremale. Esmalt tehakse * / % ja seejärel + -. Kui on vaja mingeid tehteid eelisjärjekorras teha, siis selleks kasutada sulge. **Näited aritmeetiliste tehete kasutamisest:** /* Esimesena tehakse liitmine kuna see on sulgudes, järgmisena korrutamine ning siis jagamine, x saab väärtuse 16. */ int x = 8 * (1 + 7) / 4; // Liitev-omistav operaator, x väärtuseks saab 21, lahti kirjutatud: x=x+5 x += 5; // Ühe lahutamise kiirmeetod, x väärtuseks saab 20, lahti kirjutatud: x=x-1 x--; === Loogilised tehted === Loogilised tehted on eitus (!), loogiline korrutamine (&&) ja loogiline liitmine (||). Kui kasutada koos erinevaid loogikatehteid siis täidetakse esmalt eitus ja seejärel vasakult paremale järjekorras loogiline liitmine ja korrutamine. Samuti võib kindla tehte eelistamiseks kasutada sulge. [{{ :et:arduino:logic_all_3.png?550 |Eitus, loogiline korrutamine ja loogiline liitmine}}] **Näited tehete kasutamisest:** // Toome näite kahe toa kliima parameetri kasutamisest toa tuulutuse juhtimiseks // Kui muutuja 'tuulutus' on tõene, siis lülitatakse ventilaator sisse boolean niiske, palav, tuulutus; // Algväärtustame kliima parameetrid niiske = true; palav = true; /* Eitus Muutuja palav saab eituse tulemusena vääraks ja see väärtus omistatakse samale muutujale. */ palav = !palav; /* Loogiline korrutamine Ventilaator lülitatakse sisse ainult siis, kui toas on niiske ja palav parameetrite hetkeväärtuste puhul ventilaatorit sisse ei lülitata, kuna toas ei ole palav (eelneva tehtega eitasime muutuja 'palav'). */ tuulutus = niiske && palav; // Loogiline liitmine // Ventilaator lülitatakse sisse, kui toas on niiske, palav või mõlemad korraga. tuulutus = niiske || palav; /* Esmalt teostatakse eitus, siis loogiline liitmine ning loogiline korrutamine. Ventilaator lülitatakse sisse ainult siis, kui üks parameetritest on tõene ja ventilaator veel ei tööta. */ tuulutus = niiske || palav && !tuulutus === Võrdlused === 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äited võrdluste 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 // Tehte tulemus on väär, sest esimene loogilise korrutise operand on väär b = (x + 4 > 15) && (y < 4); === Tingimuslaused === Tingimuslause võimaldab vastavalt sulgudes oleva loogikaavaldise tõesusele täita või mitte täita tingimusele järgnevat lauset või programmilõiku. Tingimuslause võtmesõna on //if//. 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. Tingimuslauseid võib moodustada lühemaid ja pikemaid: * **if**(loogikaavaldis)\\ Tõese avaldise korral täidab määratud tegevuse. * **if**(loogikaavaldis)...**else**\\ Kui avaldis ei ole tõene siis täidetakse //else// ehk muu juhu tegevus. * **if**(loogikaavaldis).. **else if**(loogikaavaldis)...**else**\\ Kui esimene avaldis ei kehtinud, siis kontrollib järgnevaid ning kui ükski ei olnud tõene, siis täidab muu juhu tegevuse. **Näide tingimuslause ülesehitusest:** // Kõigi kolme elemendiga if lause struktuur if(andur1 == 1 && andur2 == 1){ // Tee midagi } else if(andur1 == 1 || andur2 == 1){ // Tee midagi muud } else if(andur3 != 0){ // Tee midagi muud } else{ // Kui ükski eelnev lause ei olnud tõene, siis tee seda osa } === Tsüklid === Tsüklid võimaldavad ühte tegevust või programmilõiku täita mitu korda järjest. Peamised tsüklite tüübid on //for// ja //while//. * **for**(muutuja algväärtustamine; võrdlus; tehe)\\ Tsüklit korratakse, kuni võrdlus annab tulemuseks tõene.\\ for(int i=0; i<10; i++){ x++; } * **while**(loogikaavaldis)\\ Tsüklit korratakse, kuni avaldis on tõene.\\ // While tsüklit täidetakse, kuni i väärtus on suurem kui 9 int i = 0; while(i < 10){ i++; } // While tsüklit täidetakse, kuni muutuja 'lipp' on võrdne nulliga int i = 0; int lipp = 0; while(lipp == 0){ i++; if(i > 10) lipp = 1; } **Tsüklis liikumine**\\ Tsüklites on võimalik käimasoleva tsükli mõjutamiseks kasutada käske //break// ja //continue//. \\ /* Tsüklis suurendatakse muutujat loendur. Osadel juhtudel kasutatakse käsku continue, mis sunnib programmi alustama uue tsükliga. Seega loenduri suurendamine jääb kolmel juhul vahele. */ int loendur = 0; for(int i=10; i>=0; i--){ if(i==2 || i==4 || i==8) continue; loendur++; } // Lõputus tsüklis suurendatakse i väärtust. // Kui i väärtus on võrdne 10-ga, siis väljutakse tsüklist. int i = 0; while(1){ i++; if(i == 10) break; } ===== Funktsioonid ===== 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//. Funktsioon peab olema deklareeritud väljaspool teisi funktsioone ehk enne või pärast //loop// funktsiooni. **Näited funktsioonidest:** int x; int y = 3; void setup() {} void loop() { // Liitmisfunktsioon, kus parameetriteks on muutuja ja konstandi väärtus x = sum(y, 5); // Väljalülitamise funktsiooni väljakutsumine, parameetrid puuduvad power_off(); } // Kahe int tüüpi parameetriga funktsioon, mis 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) {} ===== Viikude juhtimise funktsioonid ===== Arduino programmeerimiseks on juba defineeritud hulk erinevaid funktsioone. Need ei ole standard C keele käsud vaid spetsiaalselt Arduino riistvara jaoks loodud funktsioonid. Kõige olulisemad ja vältimatult mikrokontrollerite programmide jaoks vajalikud on viikude juhtimise funktsioonid. Enne viikude kasutamist tuleb määrata nende töörežiim. Esmalt on vaja määrata, kas viik hakkab tööle sisendina või väljundina. Kui viik peaks töötama sisendina on vaja otsustada, kas aktiveerida sisemine //pull-up// takisti. **Viigu seadistamine:** * pinMode(viigu_nr, režiim) - viigu algseadistamine sisendiks või väljundiks. * INPUT - sisend * OUTPUT - väljund * INPUT_PULLUP - sisend, millel on aktiveeritud sisemine //pull-up// takisti \\ **Viigu oleku lugemine:** * digitalRead(viigu_nr) - viigu oleku lugemine digitaalsel kujul ehk 0 või 1. * analogRead(viigu_nr) - viigu oleku lugemine analoogväärtusena ehk 0 - 1023. Funktsioon töötab ainult analoogviikudel, mis on tähistatud tähega A. **Viigu oleku muutmine:** * digitalWrite(viigu_nr, väärtus) - väärtus võib olla number või makro: "HIGH" ehk 1 või "LOW" ehk 0. * analogWrite(viigu_nr, väärtus) - väärtus võib olla number vahemikus 0 kuni 255. Funktsioon töötab ainult kindlatel Arduino viikudel. Arduino UNO-l on need digitaalsed viigud 3, 5, 6, 9, 10 ja 11. **Näited:** // Tavalise lüliti väärtuse lugemine const int nupp = 12; void setup() { pinMode(nupp, INPUT_PULLUP); } void loop(){ if(digitalRead(nupp) == 0){ // Nupu vajutusel täidetav programmi osa } } // Analoogväljundiga anduri lugemine const int andurAN = A0; void setup() { pinMode(andurAN, INPUT); } void loop(){ if(analogRead(andurAN) > 500){ // Kui anduri analoogsisendi väärtus on suurem kui 500, // siis täidetakse see programmi osa } } // Digitaalse väljundi seadistamine ja oleku muutmine const int led = 13; void setup() { pinMode(led, OUTPUT); } void loop(){ digitalWrite(led, HIGH); // LED-i viigu kõrgeks seadistamine } // Analoogväljundi (PWM signaali) seadistamine ja oleku muutmine const int led = 11; void setup() { pinMode(led, OUTPUT); } void loop(){ analogWrite(led, 180); // LED-i heleduse seadmine vahemikus 0-255 } ===== Ajastusfunktsioonid ===== Programmi töös on tihti vaja teostada kindla ajastusega tegevusi. Selleks on Arduino-l olemas neli funktsiooni, millest esimesed 2 on viited ja ülejäänud 2 loendurid. Loenduritel on maksimaalne arv, mille saavutamisel ehk ületäitumisel (inglise keeles //overflow//) alustatakse lugemist taas 0-st. * **delay**(viite_pikkus) - viide, mis hoiab programmi kinni kasutaja määratud hulga millisekundeid. // Loenduri tekitamine, mis loendab sekundeid int stopper = 0; void loop() { delay(1000); // Programm on 1000 millisekundit ehk 1 sekund siin kinni stopper++; // Muutujale ühe liitmine } * **delayMicroseconds**(viite_pikkus) - viide, mis hoiab programmi kinni kasutaja määratud hulga mikrosekundeid. // Loenduri tekitamine, mis loendab millisekundeid int stopper = 0; void loop() { delayMicroseconds(1000); // Programm on 1000 mikrosekundit ehk 1 ms siin kinni stopper++; // Muutujale ühe liitmine } * **millis** - loendab millisekundeid alates mikrokontrolleri programmi tööle hakkamise hetkest. // Loenduri tekitamine, mis loendab sekundeid unsigned long aeg = millis(); int stopper = 0; void loop() { // Pidev millisekundite arvu võrdlemine eelneva millisekundite arvuga // Kui kahe arvu vahe on suurem kui 1000,siis suurendame muutujat stopper ühe võrra if((long)(millis() - aeg) > 1000){ stopper++; // Muutujale ühe liitmine aeg = millis(); // Millisekundite arvu salvestamine muutujasse } // Programm saab muul ajal vabalt joosta } * **micros** - loendab mikrosekundeid alates mikrokontrolleri programmi tööle hakkamise hetkest. // Loenduri tekitamine, mis loendab millisekundeid unsigned long aeg = micros(); int stopper = 0; void loop() { // Pidev mikrosekundite arvu võrdlemine eelneva mikrosekundite arvuga // Kui kahe arvu vahe on suurem kui 1000, siis suurendame muutujat stopper 1 võrra if((long)(micros() - aeg) > 1000){ stopper++; // Liidame muutujale ühe aeg = micros(); // Millisekundite arvu salvestamine muutujasse } // Programm saab muul ajal vabalt joosta } ===== Teegid ===== Kontrolleri programmeerimise lihtsustamiseks on riistvara tootjad ja/või vabatahtlikud loonud tarkvarateegid erinevate seadmete kasutamise. Tarkvarateegid on funktsioonide kogumid, mis on loodud riistvara lihtsamaks kasutamiseks ja haldamiseks. Nii on võimalik sisuliselt ühe käsureaga teha operatsioone, mis riistvara tasemel võivad nõuda lehekülgedepikkust koodi. Üldiselt on teegid ka paindlikud, mis tähendab, et üks teek võib toetada tervet tooteseeriat. **Mõned Arduino IDE-s vaikimisi olevad teegid:** * Wire - I2C andmeliides * EEPROM - püsimälu kasutamine * Servo - hobi servomootori juhtimine * GSM - mobiilivõrgu kaudu kommunikatsioon * SPI - sünkroonne jadaliides * Ethernet - kaabliga võrgu kaudu kommunikatsioon * Wifi - juhtmevaba võrgu kaudu kommunikatsioon * Liquid Crystal - tähemärgiliste LCD ekraanide juhtimine \\ Teeke võib ka ise koostada ja seda on mõttekas teha, kui on mingid funktsioonid, mida on soov läbi projektide korduvkasutada või on loodud mõni spetsiifiline riistvara, mille lihtsamaks kasutamiseks on mõistlik oma teek teha. Uue teegi loomiseks võib alustada tavalisest Arduino programmist, kus on loodud soovitud funktsioonid. Teegiks vormistamise jaoks on vaja koostada vähemalt kaks faili: päisfail (.h laiendiga) ja koodi fail (.cpp laiendiga). Päisfailis on teegi definitsioonid, sisuliselt info, mis kirjeldab teegi koodis olevaid funktsioone ja koodifail, mis sisaldab reaalset funktsiooni sisu ja tegevusi. Päisfailis koondatakse funktsioonide kirjeldused koos parameetritega klassidesse. Funktsioonid võivad olla kas //Public// või //Private// tüüpi. //Public// tüüpi funktsioonid on mõeldud teegi kasutajale, //Private// tüüpi klassi saab kasutada aga ainult klassi siseselt. Iga klass sisaldab spetsiaalset //construct// tüüpi funktsiooni, mis loob klassi eksemplari. //Construct// tüüpi funktsioon on sama nimega, mis klass ise. Teegi loomise täpsema juhendi leiab siit:\\ https://www.arduino.cc/en/Hacking/LibraryTutorial Teegi loomise stiilinäite ja soovitused leiab siit:\\ https://www.arduino.cc/en/Reference/APIStyleGuide === Välise teegi lisamine Arduino arenduskeskkonda === Arduino IDE arenduskeskkonda on võimalik teeke lisada mitmel meetodil. - Arduino keskkonnas kasutades menüüst nuppu //Add .ZIP Library// - Arduino teekide halduse akna kaudu (avaneb nupust //Manage Libraries...//) - Kopeerides teegi lahti pakitud kujul kausta ~\Documents\Arduino\libraries (vajab Arduino IDE taaskäivitust) {{:et:arduino:lib_add.png?450|}} === Teegi näited === Arduino jaoks loodud teekidega tuleb alati kaasa mõni näide, et tutvustada teegi funktsioonide kasutamist. Need näited leiab Arduino arenduskeskkonna //File// menüü alt. {{:et:arduino:lib_examples.png?450|}}