Sami-Petteri Pukkila sami-petteri.pukkila@aalto.fi 26. syyskuuta 2016
Arduino-ohjelman rakenne int ledpin = 13; void setup () pinmode ( ledpin, OUTPUT ); void loop () digitalwrite ( ledpin, HIGH ); delay (1000) ; digitalwrite ( ledpin, LOW ); delay (1000) ; 2
Muuttujat https://www.arduino.cc/en/tutorial/variables int omenamaara tyyppi nimi = 5 arvo ; Tyyppi (kokonaisluku, kirjain,...) Jokainen muuttuja on jonkin tyyppinen. Vrt. esim Python missä muuttujalla on vain nimi ja arvo Arvo Mikäli muuttujalle ei luomishetkellä anneta arvoa, se voi olla mitä tahansa Muuttujan arvo ei siis oletuksena ole nolla! 3
Tärkeimmät muuttujatyypit https://learn.sparkfun.com/tutorials/data-types-in-arduino Kokonaisluku (int, long) int muuttuja = -4; Liukuluku (float, double) float muuttuja = 4.0; Merkki (char) char muuttuja = a ; Vain ASCII-järjestelmän merkit Aakkoset ja numerot löytyvät, ääkköset eivät Totuusarvo (boolean) boolean muuttuja = true; Tosi (true) tai epätosi (false) 4
Muuttujatyypit Kieli on vahvasti tyypitetty Jokaisen muuttujan tyyppi on siis määritelty luomisvaiheessa Tyyppi määrää: Millaisia arvoja muuttuja voi sisältää Mitä muuttujalla voi tehdä Paljonko muuttuja vie tilaa ohjelman muistissa 5
Muuttujatyypit laskutoimituksissa Arduino ei automaattisesti muunna muuttujatyyppejä ihmisen mieleen sopiviksi. int kokonaisluku = 2; float muuttuja1 = 3/ kokonaisluku ; // 1 float muuttuja2 = 3.0/2.0; // 1. 5 float muuttuja3 = 3.0/( float ) kokonaisluku ; // 1. 5 (tyyppi)muuttuja-notaatio muuntaa muuttujan tyypin Muunnos isommasta tyypistä pienempään aiheuttaa ongelmia jos muunnettava arvo on liian iso. (long int) 6
Lukutyypit Laskutoimituksissa ja sijoituksissa voi merkitä lukuja eri lukujärjestelmissä 0123 (oktaali) 0b10100011 (binääri) 0xA3 (heksadesimaali) 3.4e3 (3.4 10 3 ) Myös muuttujatyypin voi erikseen määrätä. Hyödyllistä esimerkiksi laskutoimituksissa. 7U (unsigned) 11L (long) 15UL (unsigned long) 12.3f (liukuluku) 7
Tärkeimpiä operaattoreita summa 1+2 = 3 erotus 1-2 = -1 tulo 1*2 = 2 osamäärä 1.0/2.0 = 0.5 jakojäännös 5%3 = 2 8
Muutama oikotie summa a += 2 a = a+2 erotus a -= 2 a = a-2 tulo a *= 2 a = a*2 osamäärä a /= 2.0 a = a/2 kasvata yhdellä a++ a = a+1 vähennä yhdellä a a = a-1 9
Under-/overflow Mikäli muuttujan arvo menee muuttujatyypin alueen yli, "pyörähtää muuttuja yli" byte c = 0; // c = 0 --c; // c = 2 5 5 c = c + 1; // c = 0 10
Taulukot Hyvä väline esimerkiksi useamman ledin nastanumeroiden säilömiseen. int led_ pin [3] = 3, 5, 6; // l e d _ p i n [ 0 ] on n y t 3 // l e d _ p i n [ 1 ] v a s t a a v a s t i 5 Taulukon jäseniä kutsutaan alkioksi. Alkioon pääsee käsiksi syntaksilla nimi[alkio] Indeksointi alkaa nollasta led_ pin [1] = 2; // l e d _ p i n v a s t a a n y t määritelmää 3, 2, 6 11
Teksti https://www.arduino.cc/en/reference/string C-kielessä ei ole erillistä muuttujatyyppiä tekstille, vain merkeille (char) Merkkijonot esitetään char-taulukkona char materiaali [] = " puu "; // materiaali-muuttuja vastaa nyt // määritelmää p, u, u, \0 Merkkijonon lopussa ns. nollatavu Työkalut pystyvät päättelemään mihin merkkijono loppuu. Kolmen merkin merkkijonon tallentamiseen tarvitaan siis neljä merkkiä! 12
Merkkijonojen käsittely Merkkijonojen käsittelyyn on C-kielessä olemassa apufunktioita. Esimerkkejä strcpy Kopioi osa merkkijonosta toiseen merkkijonoon strcat Yhdistä kaksi merkkijonoa toisiinsa strcmp Vertaile kahta merkkijonoa toisiinsa itoa ja atoi Muunna kokonaisluku merkkijonoksi tai toisin päin 13
Vaikeaa? https://www.arduino.cc/en/reference/stringobject Merkkijonojen käsittely C-kielen työkaluilla voi olla hieman haastavaa. Arduino sisältää String-nimisen olennon joka tekee tekstin käsittelystä hieman helpompaa. Merkkijonoja voi helposti yhdistää ja muokata. S t r i n g merkkijono = " e l a i m i a on " + S t r i n g ( 3 ) + " k p l " ; / / merkkijono on nyt muotoa " elaimia on 3 kpl " 14
String-objektin muuntaminen Jotkut funktiot palauttavat tai vaativat c-tyylisiä char-taulukoita. Muuntaminen onnistuu kuitenkin helposti. String nimi = " EsimErkki "; nimi. c_ str () // vastaa c-tyylistä char-taulukkoa. // Tätä pystyy vain lukemaan, // ei muokkaamaan. char merkkijono [] = " testausteksti "; String muunnettu = String ( merkkijono ); 15
Muuttujien näkyvyys int koira = 1; void setup () int kissa = koira + 2; // T o i m i i void loop () kissa = koira + 2; // Ei toimi, kissa näkyy // vain setup-funktiossa 16
Globaali vs lokaali muuttuja Globaali (esimerkissä koira) Voidaan käyttää kaikkialla ohjelmassa Hyviä kun samaa muuttujaa käytetään kaikkialla ohjelmassa. Esim. Arduinoon kytketyn ledin pinninumero Vältä mikäli mahdollista. Hankala tutkia mitkä kaikki ohjelman osat vaikuttavat muuttujaan. Lokaali (esimerkissä kissa) Voi käyttää vain niiden aaltosulkeiden välissä jossa määritetty Laitteen tarvitsee säilöä tieto ainoastaan pienessä osassa ohjelmaa tehokkaampaa Vaikeampi tehdä mokia 17
Funktiot paluutyyppi funktionimi(parametri) return paluuarvo ; Funktio ottaa sisäänsä parametreja, tekee niillä jotakin ja antaa jonkinlaisen paluuarvon. Paluutyyppi Muuttujan palauttaman arvon tyyppi. Funktionimi Pitää alkaa kirjaimella. Parametri Parametrit joita funktio ottaa vastaan. Voi olla useampia ja jokaisella pitää olla tyyppi. Pilkulla voi erottaa useampia parametreja. 18
Funktioesimerkki int laskeyhteen(int numero1, int numero2) return numero1 + numero2 ; int a = laskeyhteen (1, 2); // a:n arvo on nyt 3 19
Ehtolauseet if ( false ) // Mikäli ehto on true, hypätään koodissa tänne. // Näin ei kuitenkaan ole, eli täällä ei käydä. else // If-lauseen ehto oli epätosi. // Hypätään siis tänne, eli else-lohkoon. Else-lohkon voi myös jättää pois. Tällöin ei tehdä mitään jos lauseen ehto on epätosi. 20
Else if mutta entä jos? if (5 > 10) // Ei ole, eli tänne ei päädytä else if (6 > 10) // Ei ole sekään, eli tännekään ei päädytä else // Päädytään siis tänne 21
Mielekkäitä totuuksia Vertailu a == b a yhtä suuri kuin b a!= b a eri suuruinen kuin b a < b a pienempi kuin b a > b a suurempi kuin b a <= b a pienempi tai yhtäsuuri kuin b a >= b a suurempi tai yhtäsuuri kuin b Kaikki yllä olevat vertailut muuttuvat suorituksen jälkeen jompaan kumpaan kahdesta: true jos ehto täyttyy false jos ehto ei täyty 22
Boolen operaattorit a && b tosi jos a ja b ovat molemmat tosia (and) a b tosi jos jompikumpi, a tai b ovat tosia (or)!a tosi jos a on epätosi (not) Kaikki yllä olevat ehdot muuttuvat suorituksen jälkeen jompaan kumpaan kahdesta: true jos ehto täyttyy false jos ehto ei täyty 23
Boolen logiikka int a = 15; if ( (a > 10) && (a < 20) ) Serial. println ("a on 10: n ja 20: n valissa "); 24
Boolen logiikka if ( true && true ) Serial. println ("a on 10: n ja 20: n valissa "); 25
Boolen logiikka if ( true ) Serial. println ("a on 10: n ja 20: n valissa "); 26
Helpot asiat mokata! Varoitus! a=b ja a==b ovat eri asioita! a = b; sijoita b:n arvo a:han a == b; tarkista ovatko a ja b saman arvoiset C-tyylisiä merkkijonoja ei voi vertailla ==-operaattorilla. Arduinon String-olioita voi! 27
Silmukat, eli toistorakenteet Silmukoita käytetään kun samankaltaisia asioita pitää tehdä useita kertoja peräkkäin. Silmukoita käytetään kun samankaltaisia asioita pitää tehdä useita kertoja peräkkäin. Silmukoita käytetään kun samankaltaisia asioita pitää tehdä useita kertoja peräkkäin. 28
While ja for int i =0; while ( i <= 5) Serial. println (i); i ++; for ( int i =0; i <= 5; i ++) Serial. println (i); 0 1 2 3 4 5 29
For Käyttökohteita esimerkiksi taulukoiden läpikäynti. for (alkuarvo; ehto; askel) // Todo: mitä tähän voisi laittaa Alkuarvo (int i = 0;) Luodaan loopin sisällä käytettävä muuttuja ja annetaan sille alkuarvo. Ehto (i <= 5;) Ennen jokaista loopin suorituskertaa tarkistetaan että ehto toteutuu. Mikäli ei, koko looppi ohitetaan. Askel (i++) Jokaisen loopin suorituskerran viimeiseksi suoritetaan tämä käsky. Tässä tapauksessa kasvatetaan luotua i-muuttujaa yhdellä. 30
For esimerkki int ledpin [3] = 3, 5, 6; void setup () for ( int i =0; i <3; i ++) //i=0, 1, 2 pinmode ( ledpin [i], OUTPUT ); 31
While Hieman geneerisempi toistorakenne kuin for. while (ehto) // Todo: mitä tähän voisi laittaa Ehto (i <= 5) Ennen jokaista loopin suorituskertaa tarkistetaan että ehto toteutuu. Mikäli ei, koko looppi ohitetaan. Huom! Mikäli ehto toteutuu joka kerta, looppi ei lopu koskaan. 32
While esimerkki Odotetaan minuutti ja joka sekunti tulostetaan kauanko aikaa on vielä jäljellä. millis() kertoo montako millisekuntia sitten Arduino käynnistettiin. long nowplusminute = millis () + 60000; while ( millis () < nowplusminute ) Serial. println ( nowplusminute - millis ()); delay (1000) ; 33
For vs while Oikeastaan for-silmukan voi ajatella "hienompana"versiona while-silmukasta alkuarvo on vain lause joka ajetaan ennen while-silmukkaan siirtymistä ehto on while-silmukan ehto askel on lause joka sijoitetaan viimeiseksi while-silmukan sisälle. 34
Break ja continue Silmukoiden kulkuun voidaan vaikuttaa kahdella komennolla: break Lopeta silmukan suoritus heti ja siirry siitä ulos continue Hyppää välittömästi takaisin silmukan alkuun. For-silmukassa suoritetaan lisäksi askel-vaihe. 35
Break ja continue -esimerkki int i =0; while ( true ) Serial. println (i); i ++; if (i < 3) continue ; break ; 0 1 2 3 36
Arduino 37
Arduino UNO:n pääpiirteet Flash-muistia 32 kilotavua, josta 0,5 KB varattu Arduinon bootloaderille Tähän tilaan ohjelman pitää siis mahtua 2 kilotavua SRAM-muistia Käyttömuisti. Esim muuttujat asuvat täällä Tieto häviää kun virrat katkeavat 1 kilotavu EEPROM-muistia Muisti joka ei häviä virtojen katketessa Esimerkiksi laitteen asetusten säilöminen Vrt. tietokoneen kovalevy 38
Arduino UNO vs teensy 2.0 Arduino UNO perustuu ATmega328P-piiriin Teensy ATmega32U4-piiriin. Piirissä on tuki USB:lle. Teensy voi esimerkiksi esittää USB-näppäimistöä Flash-muistia 32 kilotavua Teensyssä n. 32kB 2 kilotavua SRAM-muistia Teensyssä n. 2,5kB 1 kilotavu EEPROM-muistia Teensyssä 1kB Käytännössä eroja siis on, mutta kumpikin ovat "tyhmiä"mikrokontrolloreita 39
digitalwrite https://www.arduino.cc/en/tutorial/digitalpins Asettaa pinnin arvon LOW tai HIGH. LOW, "pois päältä" HIGH, "päällä" Esimerkiksi ledin vilkutus void setup () pinmode (13, OUTPUT); void loop () digitalwrite (13, HIGH ); // LED päällä delay (1000) ; //Odota sekunti digitalwrite (13, LOW ); // LED pois päältä delay (1000) ; //Odota sekunti 40
digitalread Lukee pinnin tilan LOW, pinni kytketty maahan (GND) HIGH, pinni kytketty jännitteeseen. (3-5 volttia) void setup () pinmode (3, INPUT); void loop () int arvo = digitalread (3) ; 41
Ylös-/Alasvetovastukset https://learn.sparkfun.com/tutorials/pull-up-resistors Mikäli pinniä ei ole kytketty mihinkään, sanotaan että se kelluu digitalread palauttaa satunnaisesti HIGH tai LOW Ratkaisuna alasvetovastus Kytketään pinni vastuksella (n. 10KΩ) GND:hen Pinnin arvo on nyt LOW kunnes se kytketään myös +5V:iin Ylösvetovastus lähes sama asia: Kytketään pinni vastuksella (n. 10KΩ) +5V:iin Pinnin arvo on nyt HIGH kunnes se kytketään myös GND:iin 42
INPUT_PULLUP Arduinosta löytyy sisäänrakennettuna ylösvetovastus Aktivoidaan määrittämällä pinnin modeksi INPUT_PULLUP Yksinkertainen nappula voidaan nyt kytkeä suoraan GND:in ja halutun pinnin välille. Mitään ylimääräistä vastusta ei tarvita kytkennässä! void setup () pinmode (3, INPUT_PULLUP ); void loop () int nappula = digitalread (3) ; 43
analogread analogreadilla voidaan lukea pinnin jännite Onnistuu vain pinneistä jotka on nimetty A0, A1... Kyseisten pinnien takana on 10-bittinen analogidigitaalimuuntaja (AD) Arvo 0-5V väliltä saadaan lukuna väliltä 0-1023. (2,5V siis vastaisi lukua 512) Kyseisiä pinnejä voi käyttää myös digitaaliseen I/O:hon void setup () pinmode (A1, INPUT); void loop () int arvo = analogread ( A1); 44
analogwrite Arduinossa ei ole DA-muunninta analoginen ulostulo pitää tehdä "keinotekoisesti" PWM, eli Arduino kytkee pinniä nopeasti 0V ja 5V välillä. (kanttiaalto) "Teho"määräytyy kauanko pinniä pidetään HIGH- ja kauanko LOW-tilassa Esimerkiksi LEDien himmentämisessä ja normaalien moottorien tehon säädössä riittävä Vain tildellä ( ) merkittyjä pinnejä voi käyttää void setup () pinmode (3, OUTPUT ); void loop () // Ledi palaa "puolella teholla" analogwrite (3, 127) ; 45
Esimerkki: Monen ledin vilkutus Blinkkiesim.ino Ongelma: Halutaan saada useampi kuin yksi ledi vilkkumaan tietyllä taajuudella. Arduinon tutussa Blink-esimerkissä vilkutetaan yhtä lediä kytkemällä sitä päälle sekä pois, välissä odottaen sopiva aika. Odottelun aikana ei voida tehdä mitään muuta, eikä kahden ledin vilkuttaminen eri taajuuksilla ole tällä tavalla mielekästä. 46
Esimerkki: Monen ledin vilkutus Esimerkkiä varteen tarvitaan Arduino tai teensy jossa Pinniin 9 on kytketty etuvastuksen kanssa sarjaan ledi Pinniin 10 on kytketty etuvastuksen kanssa sarjaan ledi 47
Esimerkki: Monen ledin vilkutus BlinkLed led1 (10, 1000) ; BlinkLed led2 (9, 500) ; void setup () void loop () led1. update (); led2. update (); BlinkLed on luokka josta luodaan oliot led1 ja led2. led1 ja led2 sisältävät.update()-metodin jonka kutsuminen pitää huolen että ledi on oikeassa tilassa 48
Luokka ja olio? Luokka kuvaa miten asia toimii. Sillä on omia sisäisiä muuttujia. Sillä on omia funktioita jotka vaikuttavat sen muuttujiin. Esim. servo, näyttö, ihminen. Olio on luokan pohjalta luotu itsenäinen eliö. Esimerkissämme on siis kaksi BlinkLed-tyyppistä oliota. led1 on pinniin 10 kytketty ledi joka vilkkuu 1s sykleissä. led2 on pinniin 9 kytketty ledi joka vilkkuu 0,5s sykleissä. 49
Esimerkki: Monen ledin vilkutus class BlinkLed public : BlinkLed ( int pin, int blink_time ); void setdelay ( int blink_time ); void update (); private : int _pin ; //Pin johon led on kytketty bool _state ; //Onko ledi nyt päällä vai ei ; int _blink_time ; //Kauanko pidetään lediä päällä/pois long _last_cycle ; //Milloin viimeksi tehtiin ledille jotakin 50
Public- ja private-lohkot https://fi.wikipedia.org/wiki/luokka_(ohjelmointi) Public-lohkon alla olevat asiat näkyvät ulkomaailmaan. Tämän vuoksi esimerkin led1:n update()-funktiota voidaan kutsua ohjelman pääloopissa. Private-lohkon asioita voi käyttää luokan sisällä olevissa funktioissa, mutta niitä ei voi käyttää ulkopuolella. Esimerkiksi led1:n pinniä ei voi selvittää lukemalla muuttujaa led1._pin. Tapana on erottaa private muuttujat alaviivalla alkavalla nimellä, mutta tämä ei ole pakollista. 51
Esimerkki: Monen ledin vilkutus BlinkLed ( int pin, int blink_ time ) _pin = pin ; _ blink_ time = blink_ time ; _ state = LOW ; pinmode (_pin, OUTPUT ); _ last_ cycle = millis (); Ns. konstruktori. Suoritetaan silloin kun luodaan uusi olio. BlinkLed led1(10, 1000); käyttää tätä osaa luokasta. 52
Esimerkki: Monen ledin vilkutus void setdelay ( int blink_ time ) _ blink_ time = blink_ time ; Public-blokissa oleva funktio joka muokkaa private-muuttujaa. 53
Esimerkki: Monen ledin vilkutus https://www.arduino.cc/en/reference/millis void update () if ( millis () - _last_cycle >= _blink_time ) _state =! _state ; _ last_ cycle = millis (); digitalwrite (_pin, _state ); millis() aika Arduinon käynnistymisestä millisekunteina. Funktio tarvittaessa kääntää ledin päälle tai pois. Tämän jälkeen voidaan odottamisen sijaan tehdä jotakin muuta. 54
Ohjelma laitteelle 55
Esimerkki: Monen ledin vilkutus Jatketaan esimerkkiä hieman lisää. Uusi ongelma ledin vilkkumisnopeutta halutaan muuttaa lennosta. 56
Esimerkki: Monen ledin vilkutus void setup () Serial. begin (9600) ; void loop () led1. update (); led2. update (); update_ speeds (); setup-funktiossa alustetaan sarjaporttiyhteys. pääloopissa kutsutaan yhtä uutta funktiota. 57
Esimerkki: Monen ledin vilkutus void update_ speeds () if ( Serial. available ()) long new_ delay = Serial. parseint (); led2. setdelay ( new_delay ); Serial. println (" Set new delay for led2 : "+ String ( new_delay )); Nyt Arduinosta voi avata Serial monitorin ja lähettää Arduinolle halutun viiveen numerona. 58
Serial monitorin avaaminen Varmista että tools port on valittu oikein. 59
Serial monitor 60
Sarjaportti https://www.arduino.cc/en/reference/serial Arduino osaa USB:n kautta esittää sarjaporttia Helpoin tapa tietää mitä Arduinossa tapahtuu Kun ohjelma ei toimi kuten sen pitäisi, kannattaa sarjaporttiin tulostaa eri muuttujien arvoja ja tutkia niiden järkevyyttä Tekstin tulostaminen ennen ja jälkeen jonkin ohjelman osan auttaa selvittämään, jääkö ohjelma jumiin johonkin kohtaan. Huom! jos käytät sarjaporttia, pinnejä 0 ja 1 ei voi enää käyttää muuhun! 61
Enum enum OhjelmanTila kysyy_ nimea, sanoo_ moi ; OhjelmanTila tila = kysyy_ nimea ; void loop () String nimi ; if ( tila == kysyy_ nimea ) nimi = kysy_ nimi (); if ( tila == sanoo_ moi ) sano_moi ( nimi ); 62
Vinkit ohjelmointiin: Sisennys Sisennetty koodi on helppolukuista sillä lohkot erottuvat visuaalisesti toisistaan Koodia saa sisennettyä painamalla tab-nappulaa kursorin ollessa rivin alussa void loop () String nimi ; if ( tila == tila1 ) nimi = kysy_ nimi (); if ( tila == tila2 ) sano_moi ( nimi ); void loop () String nimi ; if ( tila == tila1 ) nimi = kysy_ nimi (); if ( tila == tila2 ) sano_moi ( nimi ); 63
Vinkit ohjelmointiin: Manuaalien lukeminen Arduinon sivuilla hyvät on ohjeet useimpien funktioiden käyttöön. Kannattaa aina lukea funktion manuaali kun käyttää sitä ensimmäistä kertaa. Tiettyjen kirjastojen käyttäminen saattaa asettaa rajoituksia esimerkiksi tiettyjen pinnien toimintaan. Myös komponenttien käyttöön löytyy hyviä ja huonoja ohjeita Googlella. 64
Vinkit ohjelmointiin: Google Lähes kaikki kääntäjän ilmoittamat virheet googlautuvat hyvin. Maailmassa on tehty paljon asioita jo ennestään: how to * with arduino/c Englannin kielellä parhaat hakutulokset Tällä pääsee yllättävän pitkälle kaikkeen ohjelmointiin liittyvässä! 65
Ohjelman debuggaus: kumiankka 66
Linkkejä Arduinon oppaat ja esimerkit https://www.arduino.cc/en/tutorial/homepage Arduinon kielen referenssi https://www.arduino.cc/en/reference/homepage Atmega328P-piirin datasheet. Kertoo kaiken mitä kyseinen piiri osaa, kannattaa lukea lähinnä mielenkiinnosta opus on todella pitkä. http://www.atmel.com/images/ atmel-8271-8-bit-avr-microcontroller-atmega48a-48pa-88a datasheet_complete.pdf 67