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.

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.

  1. Arduino keskkonnas kasutades menüüst nuppu Add .ZIP Library
  2. Arduino teekide halduse akna kaudu (avaneb nupust Manage Libraries…)
  3. Kopeerides teegi lahti pakitud kujul kausta ~\Documents\Arduino\libraries (vajab Arduino IDE taaskäivitust)

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/programming.txt · Last modified: 2020/07/20 09:00 by 127.0.0.1
CC Attribution-Share Alike 4.0 International
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0