5.4. Sulautetun järjestelmän C-kielen perusteet. 4/8. Ohjausrakenteet 7.1.2008 pva



Samankaltaiset tiedostot
Koottu lause; { ja } -merkkien väliin kirjoitetut lauseet muodostavat lohkon, jonka sisällä lauseet suoritetaan peräkkäin.

12. Javan toistorakenteet 12.1

5.6. C-kielen perusteet, osa 6/8, Taulukko , pva, kuvat jma

12. Javan toistorakenteet 12.1

11. Javan toistorakenteet 11.1

Sisällys. 11. Javan toistorakenteet. Laskurimuuttujat. Yleistä

Ehto- ja toistolauseet

Sisällys. 12. Javan toistorakenteet. Yleistä. Laskurimuuttujat

Osa. Toimintojen toteuttaminen ohjelmissa vaatii usein haarautumisia ja silmukoita. Tässä luvussa tutustummekin seuraaviin asioihin:

Ohjausrakenteet. Valinta:

Java-kielen perusteita

Java-kielen perusteita

Perusteet. Pasi Sarolahti Aalto University School of Electrical Engineering. C-ohjelmointi Kevät Pasi Sarolahti

11. Javan valintarakenteet 11.1

Sisällys. 3. Pseudokoodi. Johdanto. Johdanto. Johdanto ja esimerkki. Pseudokoodi lauseina. Kommentointi ja sisentäminen.

Perusteet. Pasi Sarolahti Aalto University School of Electrical Engineering. C-ohjelmointi Kevät Pasi Sarolahti

Johdanto ja esimerkki. Pseudokoodi lauseina. Kommentointi ja sisentäminen. Ohjausrakenteet:

Alkuarvot ja tyyppimuunnokset (1/5) Alkuarvot ja tyyppimuunnokset (2/5) Alkuarvot ja tyyppimuunnokset (3/5)

TAITAJA 2007 ELEKTRONIIKKAFINAALI KILPAILIJAN TEHTÄVÄT. Kilpailijan nimi / Nro:

OPPITUNTI 5 Ohjelman kulku

11. Javan valintarakenteet 11.1

Zeon PDF Driver Trial

13. Loogiset operaatiot 13.1

Python-ohjelmointi Harjoitus 5

Ohjelmoinnin perusteet Y Python

5/20: Algoritmirakenteita III

Lauseet. Ehdollinen lause. Tämän osan sisältö. Ehdollinen lause. Esimerkkejä. Yksinkertainen ehto. Lohkosulut ja sisennys. Ehdollinen lause if

IDL - proseduurit. ATK tähtitieteessä. IDL - proseduurit

ATK tähtitieteessä. Osa 3 - IDL proseduurit ja rakenteet. 18. syyskuuta 2014

Taitaja2005/Elektroniikka. 1) Resistanssien sarjakytkentä kuormittaa a) enemmän b) vähemmän c) yhtä paljon sähkölähdettä kuin niiden rinnankytkentä

13. Loogiset operaatiot 13.1

Sisällys. 16. Ohjelmoinnin tekniikkaa. Aritmetiikkaa toisin merkiten. Aritmetiikkaa toisin merkiten

16. Ohjelmoinnin tekniikkaa 16.1

Perinteiset tietokoneohjelmat alkavat pääohjelmasta, c:ssä main(), jossa edetään rivi riviltä ja käsky käskyltä.

Ohjelmointiharjoituksia Arduino-ympäristössä

Muistutus aikatauluista

Harjoitus 3 -- Ratkaisut

Luento 5. Timo Savola. 28. huhtikuuta 2006

Ohjelmoinnin peruskurssi Y1

Sisällys. 17. Ohjelmoinnin tekniikkaa. Aritmetiikkaa toisin merkiten. for-lause lyhemmin

Lohkot. if (ehto1) { if (ehto2) { lause 1;... lause n; } } else { lause 1;... lause m; } 16.3

Ohjelmointitaito (ict1td002, 12 op) Kevät Java-ohjelmoinnin alkeita. Tietokoneohjelma. Raine Kauppinen

16. Ohjelmoinnin tekniikkaa 16.1

6.3. AVR_rauta. EEPROM-muisti pva

13. Hyvä ohjelmointitapa (osa 1) 13.1

811120P Diskreetit rakenteet

14. Hyvä ohjelmointitapa 14.1

Lohkot. if (ehto1) { if (ehto2) { lause 1;... lause n; } } else { lause 1;... lause m; } 15.3

Ohjelmoinnin peruskurssi Y1

811120P Diskreetit rakenteet

Sisällys. 15. Lohkot. Lohkot. Lohkot

Muuttujien roolit Kiintoarvo cin >> r;

C-ohjelma. C-ohjelma. C-ohjelma. C-ohjelma. C-ohjelma. C-ohjelma. Operaatioiden suoritusjärjestys

Algoritmit. Ohjelman tekemisen hahmottamisessa käytetään

Vertailulauseet. Ehtolausekkeet. Vertailulauseet. Vertailulauseet. if-lauseke. if-lauseke. Javan perusteet 2004

Tietotyypit ja operaattorit

Ohjelmoinnin perusteet Y Python

Sulautettujen järjestelmien kilpailutehtävä

Java kahdessa tunnissa. Jyry Suvilehto

Sisällys. 16. Lohkot. Lohkot. Lohkot

Python-ohjelmointi Harjoitus 2

Ohjelmoinnin perusteet Y Python

Ehto- ja toistolauseet

ELEC-A4010 Sähköpaja Arduinon ohjelmointi. Jukka Helle

6.2. AVR_rauta. Analogia-komparaattori-ohjelmointia , pva

Ongelma(t): Miten tietokoneen komponentteja voi ohjata siten, että ne tekevät yhdessä jotakin järkevää? Voiko tietokonetta ohjata (ohjelmoida) siten,

Java-kielen perusteet

Ohjelmoinnin peruskurssi Y1

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin perusteet Y Python

if-lauseen yksinkertaisin muoto on sellainen, missä tietyt lauseet joko suoritetaan tai jätetään suorittamatta.

Algoritmit 1. Demot Timo Männikkö

Taitaja2007/Elektroniikka

7.3. Oheisrautaa. DS

4. oppitunti. Ilmaukset ja ohjelmalauseet. Osa

Java-kielen perusteet

Taitaja semifinaali 2010, Iisalmi Jääkaapin ovihälytin

TIEP114 Tietokoneen rakenne ja arkkitehtuuri, 3 op. Assembly ja konekieli

Ohjelmointitaito (ict1td002, 12 op) Kevät Java-ohjelmoinnin alkeita. Tietokoneohjelma. Raine Kauppinen

Tähtitieteen käytännön menetelmiä Kevät 2009 Luento 5: Python

Ohjelmoinnin perusteet Y Python

ITKP102 Ohjelmointi 1 (6 op)

5.2. Sulautetun järjestelmän C-kielen perusteet 2/8, käsitteet pva

C-kielessä taulukko on joukko peräkkäisiä muistipaikkoja, jotka kaikki pystyvät tallettamaan samaa tyyppiä olevaa tietoa.

Osoitin ja viittaus C++:ssa

815338A Ohjelmointikielten periaatteet Harjoitus 2 vastaukset

Sisällys JAVA-OHJELMOINTI Osa 3: Laskennan ohjaus. Lohkolause (block) Peräkkäinen laskenta. Lohkon käyttö. Esimerkki

Taitaja2008, Elektroniikkalajin semifinaali

Ohjelmassa henkilön etunimi ja sukunimi luetaan kahteen muuttujaan seuraavasti:

Valinnat ja päätökset

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin perusteet Y Python

Tutoriaaliläsnäoloista

Ohjelmiston testaus ja laatu. Testausmenetelmiä

TT00AA Ohjelmoinnin jatko (TT10S1ECD)

2. Lisää Java-ohjelmoinnin alkeita. Muuttuja ja viittausmuuttuja (1/4) Muuttuja ja viittausmuuttuja (2/4)

UML -mallinnus TILAKAAVIO

Ohjelmoinnin peruskurssi Y1

Muuttujat ja kontrolli. Ville Sundberg

Ohjelmoinnin peruskurssi Y1

Transkriptio:

5.4. Sulautetun järjestelmän C-kielen perusteet. 4/8. Ohjausrakenteet 7.1.2008 pva Superohjelmoija on insinörttitaiteilija ja ryhtyessään koodaamaan, hän keskittyy kunnolla, leijuu jonnekin sfääreihin ja maailma katoaa ympäriltä. - Richi Jennings Tässä osiossa tärkeää: sulautetun järjestelmän ohjelman etenemiseen käytetyt käskyt Sisältö Peräkkäisrakenne Valintarakenne if-lause, if else lause, else-if lause if-esimerkki 1, if ja input, esimerkki 2, if-else-esimerkki 3, if ja else-lause, esimerkki 4 Inkrementointi ja if-lause Switch-lause switch-lause esimerkki 1, Switch-lause esimerkki 2 Toistorakenne for-silmukkalause, for-loop, For-silmukan kolme vaihetta, For-lause esimerkki 1 For-lause ja ikuinen silmukka, Sisäkkäiset silmukat, Sisäkkäiset silmukat esimerkki Break ja for-silmukka, Silmukan keskeyttäminen break-käskyllä, Break-lause esimerkki continue-lause, Silmukan keskeyttäminen continue-lauseella, Continue esimerkki While-toistolause, while-loop, While-lause esimerkki 1 Sisäkkäiset while-lauseet, Ikuinen while-silmukka, while-silmukka ja odotus Do-while-toistolause. Miksi käytetään do-silmukkaa? 1

Yleistä Kuten olet tähänastisista harjoituksista huomannut, niin C-kielinen ohjelma koostuu lauseista, joita ovat - lausekkeet - kootut lauseet eli lohkot - sekä erilaiset esittelyt Nämä riittävät yksinkertaisiin ohjelmiin, silloin kun ollaan aivan opiskelun alussa. Jos käsitellään hiemankin monimutkaisempia tehtäviä, myös ohjelmasta tulee monimutkainen ja laaja. Tarvitaan uusia rakenteita ja lauseita ohjelman toiminnan organisointiin ja hallintaan. C-kieli on ohjelmointikieli, jolla tehdään ns. rakenteista eli strukturoitua ohjelmakoodia. Rakenteinen tarkoittaa tässä sitä, että ohjelma jaetaan pieniin rakenneosiin eli lohkoihin ja funktioihin. Pieni on kaunista ja pieniä funktioita on helpompi hallita kuin suuria, jakamattomia kokonaisuuksia. Ryhmittelemällä sopivasti kaikkia opittavia rakenteita saadaan aikaan toimiva ohjelma. Näitten rakenteiden suoritusjärjestyksen muuttaminen on olennainen osa ohjelmointia. Seuraavaksi opitaan miten lisätään ohjelmaan erilaisia ohjausrakenteita. Ohjausrakenteilla ohjataan ja muutetaan ohjelman käskyjen suoritusjärjestystä. Useimmat suorituksen ohjauskäskyt perustuvat jonkin ehdon testaamiseen. Ehto joko täyttyy, eli on tosi - true, tai ei täyty, eli on epätosi- false. C-kielessä tosi-arvo on mikä tahansa nollasta poikkeava kokonaisluku ja epätosi on aina nolla. Ohjelman eteneminen Ohjelma etenee (käskyjen suoritusjärjestys) kolmella eri tavalla: 1. Peräkkäinen 2. Valinta 3. Toisto 5.4.1. Peräkkäisrakenne Ohjelman käskyt suoritetaan peräkkäin eli siinä järjestyksessä, johon ohjelmoija on ne kirjoittanut, ylhäältä alas, vasemmalta oikealle. Lauseiden ryhmitys selkeyttää koodin ymmärtämistä. Tähänastiset ohjelmaesimerkit ovat käyttäneet (pääasiassa) vain tätä rakennetta. 5.4.2.Valintarakenne Valinta- eli ehtorakenne mahdollistaa tehtävien vaihtoehtoisen suorittamisen. Toimenpide valitaan kahdesta tai useammasta vaihtoehdosta jonkin ehdon perusteella. Ohjelma tekee päätöksiä. Näin saadaan pienestäkin ohjelmasta älykäs, mikä on eduksi etenkin sulautetuissa järjestelmissä. Valintarakenteita ovat: - päätöksen tekeminen, if, if-else - yhden valitseminen useasta vaihtoehdosta, switch 2

5.4.2.1. if-lause Kaikkien ohjauskäskyjen perusrakenne on ehto- eli if-lause. Sen avulla voi ohjelman suorituksen jakaa kahteen eri haaraan, joista vain toinen suoritetaan halutun ehdon perusteella. If-lause näyttää C-kielessä tällaiselta: Kuva 5.4.1. if-rakenne. if-lauseen yleinen muoto, formaatti: if(ehto) lause; esim. if(lampo_1 > lampo_2) // jos ehto on tosi eli lampo_1 on suurempi kuin lampo_2, PORTB = 0x01; // B-porttiin sijoitetaan hex-luku 0x01 Sulkujen sisällä oleva ehto voi olla mikä tahansa lauseke, tavallisimmin se on vertailulauseke. Siinä verrataan kahden arvon suuruutta keskenään, esim. onko y suurempi kuin x; y > x? Jos ehto on tosi, eli sulkujen sisällä olevan ehto-lauseen arvo on nollasta poikkeava, suoritetaan lause. Muuten ei. Jos ehdon perusteella suoritettavia lauseita on useita, lauseet kootaan yhteen käyttäen aaltosulkuja. if(ehto) lause_1; lause_2; lause_3; Huomaa, että kaarisulkujen jälkeen ei tule puolipistettä. if-käskyyn liittyy - joko yksittäinen käsky - tai monta käskyä. Jos if-lauseeseen liittyy monta käskyä, ne on sijoitettava omaan lohkoonsa ja siis erotettava muusta ohjelmasta lohkoerottimilla 3

5.4.2.2. if else lause If-lauseessa voi olla myös valinnainen else-osa: if(ehto) lause_1; else lause_2; Kuva 5.4.2. If-else-rakenne. Jos ehto on tosi, suoritetaan lause_1. Jos ehto ei ole totta, eli sulkujen sisällä olevan lausekkeen arvo on nolla, suoritetaan lause_2. If-lausetta voi jatkaa niin pitkälle kuin tarpeellista lisäämällä uusia if-lauseita else-osan perään. Ehto laitetaan aina sulkeiden sisään. Lause voi olla joko yksittäinen käskylause tai aaltosulkeissa oleva koottu lause (eli monta lausetta). else-if lause if(ehto_1) lause_1; else if(ehto_2) lause_2; else lause_3; Huom! if-lauseen jälkeen puolipiste (;) puuttuu. Muista kirjoittaa ehdon ympärille kaarisulkeet. Jos if-lauseita on kaksi tai useampia, niin se toteutetaan, joka on tosi. 4

if-esimerkki 1 Kirjoita seuraava lähdekoodi, käännä ja aja se. /********************************************************** Project : if_1.c Hardware: PV-M32 + PV-LEDIT on PORTB Software: WinAVR 20070525 Date : 12.07.2007 Comments: if-lauseen demo **********************************************************/ #include <util/delay.h> // prototyyppi void wait(uint16_t time); int main(void) DDRB = 0xFF; uint8_t luku = 0; while(1) PORTB = luku; wait(500); luku = luku + 1; if(luku > 8) // testi, jos luku on suurempi kuin 8 luku = 0; // luku nollataan Analysointi Ohjelma laskee nollasta ylöspäin ja joka kierroksella testataan, joko ollaan yli kahdeksan. Kun luku on suurempi kuin 8, luku-muuttuja nollataan ja laskenta alkaa uudestaan. Harjoituksia 1. Muuta esimerkkiohjelman testiehtoa. 2. Muuta testiehtoa ja askellusta. (esim. luku = luku + 2;). 3. Muuta testiehto toisinpäin, siis pienempi kuin, <., ja samalla myös koodia, niin että toimii. Aloittelijan virhe! Tyypillinen aloittelijan virhe on panna puolipiste if-lauseen loppuun. Se aiheuttaa yleensä paljon hämminkiä. if(virta == 10); // jos virta on yhtä suuri kuin 10 lause_1; - tässä lause_1 suoritetaan aina, koska kukin rivi suoritetaan erillisenä lauseena, ei yhdessä, kuten oli tarkoitus - kun otat puolipisteen pois sulkumerkin jälkeen, ohjelma toimii oikein. 5

Nyt voidaan jatkaa if-lauseen tutkimista. if ja input, esimerkki 2 /********************************************************** Project : if_in.c HW: PV-M32 + PV-TINT + PV-LEDIT SW: WinAVR-20070525 Date : 23.11.2007 Comments: lukee D-portin tilan ja tulostaa muuttujan, jos S1=INT0 on painettu ***********************************************************/ int main(void) unsigned char inpu; unsigned char luku = 0x18; DDRB = 0xFF; // B-portti output DDRD = 0xF0; // D-portti input PORTD = 0xFF; while(1) PORTB = 0x01; inpu = PIND; // luetaan portti D muuttujan arvoksi if(inpu == 0xBB) // jos S1=INT0 painettu PORTB = luku; // katso PV-TINT-kortin kaaviota, // siitä selviää miksi vertoarvo on 0xBB Analysointi Ohjelman alussa kaikki D-portin bitit asetetaan ykköseksi: PORTD = 0xFF; Jos S1 on painettu, se merkitsee sitä, että bitti 3 menee nollaksi, ja johtuen kortin kytkennästä myös 6- bitti menee nollaksi, jolloin portista luettava ei ole 0xFB, vaan 0xBB. if-lauseessa testataan, onko inpu-muuttujaan luettu arvo yhtä kuin 0xBB. Jos S1=INT0 on painettu alas, kun porttia luetaan muuttujaan, niin silloinhan se on. Ehto on selvästikin tosi ja B-porttiin kirjoitetaan luku-muuttujan arvo. Harjoituksia 1. Lisää testiehto, jossa testataan onko kytkintä S2=INT1 painettu. 2. Lisää testiehto, jossa testataan onko kytkimet S1 ja S2 painettu alas yhtaikaa.. 6

if-else-esimerkki 3 jossa mukana esikääntimen direktiivi #define /********************************************************** Project : if_else.c HW : PV-M32 + PV-EMO + PV-LEDIT SW : WinAVR-20070525 Date : 23.11.2007 Comments: lukee D-portin tilan ja tulostaa muuttujan, jos S1 & S2 on painettu **********************************************************/ #define S2 bit_is_clear(pind, 2) // jos S2 painettu #define S3 bit_is_clear(pind, 3) // jos S3 painettu int main(void) DDRB = 0xFF; DDRD = 0x00; PORTD = 0xFF; // B-portti output // D-portti input while(1) if(s2) // jos S2 painettu PORTB = 0x0F; else if(s3) // jos S3 painettu PORTB = 0xF0; else PORTB = 0x81; // ellei mitään painettu Analysointi Uutta koodissa on kaksi symbolisen merkkivakion määritystä, #define S2 bit_is_clear(pind, 2) // jos S2 painettu #define S3 bit_is_clear(pind, 3) // jos S3 painettu Määritys toimii siten, että esikäännin korvaa koodissa missä tahansa kohtaa esiintyvän S2-merkinnän makrolla joka testaa onko D-portin 2-bitti nolla vai ei. Siinähän on nolla, jos S2-nappia on painettu. Ellei kumpaakaan nappia ole painettu niin else // ellei mitään painettu PORTB = 0x81; LED-kuvio loistaa vain niin kauan kuin painat jotain kytkintä, sillä koodissa ei käytetä viivettä. Harjoituksia 1. Muuta testiehtoja ja tulostettavia LED-kuvioita. 2. Lisää testiehto, jossa S1 ja S2 painettu alas yhtaikaa. If-else-lausetta kehittyneempi valintakomento on switch. Tarvitsemme sen käytössä break-komentoa, joten tutkitaan se ensin. 7

5.4.2.3. Silmukan keskeyttäminen break-käskyllä Switch-lauseesta joudutaan poistumaan, kun jokin sen ehto toteutuu. Poistuminen voidaan toteuttaa break-komennolla. Se aiheuttaa hyppäämisen ulos silmukasta välittömästi. Break-komennon käyttö ei liity pelkästään switch-lauseeseen, vaan sitä voidaan käyttää myös ohjelmasilmukoiden kanssa. Jos ollaan ohjelmasilmukassa, break-komennolla hypätään sieltä ulos. Käsky toimii siis myös while, for ja do - while lauseiden yhteydessä. Break-lause, esimerkki /********************************************************* Project : break.c HW: PV-M32 SW: WinAVR-20070525 Date : 03.01.2007 Comments: break-lauseen demo *********************************************************/ #include <util/delay.h> // *** Primitive wait() *** void wait(uint16_t time) volatile uint16_t i; for(i=0;i<2000;i++) _delay_loop_2(time); int main(void) DDRB = 0xFF; unsigned char laskuri=0; while(1) while(1) if(laskuri > 33) break; // hypätään ulos, kun ehto on tosi ++laskuri; // laskuri = laskuri + 1; PORTB = laskuri; wait(50); laskuri = 0; Analysointi Ohjelma laskee ja tulostaa laskuri-muuttujaa, kunnes ehto on tosi. Silloin poistutaan sisemmästä whilesilmukasta, ja jatketaan. Uloimman while-silmukan ensimmäinen toimenpide on nollata laskuri, palataan takaisin sisempään silmukkaan ja if-testiin. Laskenta jatkuu ikuisesti. 8

5.4.2.4. Silmukan keskeyttäminen continue-lauseella Muuten toiminnaltaan samankaltainen kuin break, mutta kun break-lauseen kohdatessaan ohjelma hyppää ulos silmukasta, niin continue ohittaa kaikki silmukan loput käskyt ja aloittaa saman silmukan alusta. Käyttö while, do-while ja for-loopeissa. Ei toimi switch-lauseessa. Joissakin tapauksissa ohjelmassa joudutaan palaamaan while-silmukan alkuun ennen kaikkien silmukan runkolauseiden suoritusta. Continue-komento sijoitetaan silmukan runkoon haluttuun kohtaan. Kun continue-komento suoritetaan, alkaa seuraava silmukan kierros välittömästi. Silmukan loput lauseet ohitetaan. Do-while-silmukassa testataan lopetusehdot ja tarvittaessa aloitetaan seuraava silmukkakierros. Käytä continue ja break-lauseita varoen. Ohjelmaa, joka äkkiä muuttaa suuntaansa, on vaikea ymmärtää. Continue esimerkki /********************************************* Project : continue.c HW: PV-M32 SW: WinAVR-20070525 Date : 03.01.2007 Comments: continue-lauseen demo *********************************************/ #include <util/delay.h> int main(void) DDRB = 0xFF; unsigned char laskuri; while(1) laskuri = 0; while(1) if(laskuri > 62) continue; // stop, kun ehto on tosi, // koska ei hypätä ulos silmukasta, vaan silmukan alkuun ++laskuri; // laskuri = laskuri + 1; PORTB = laskuri; wait(50); laskuri = 0; Analysointi Koodin pohjana on edellinen esimerkki, jotta komentojen toimintaero selviää. Kun if-lauseen ehto on tosi, ohjelma pysähtyy, koska ei poistuta silmukasta, vaan continuella hypätään saman silmukan alkuun ja laskurihan on edelleen suurempi kuin 62. 9

5.4.2.5. Switch-lause Jos testattavia asioita on monta, pannaan if- ja else-lauseita yhtä monta peräjälkeen. Muutama vielä menettelee, mutta äkkiä tulee tilanne, että koodista tulee sekava ja se on vaikeasti ymmärrettävä. Otetaan apuun switch-lause. Switch-lauseen sisällä suoritus haarautuu yhteen useasta mahdollisesta haarasta. Sitä käytetään tavallisesti erilaisissa valikkorakenteissa, joissa käyttäjän valintojen perusteella jatketaan ohjelmaa. Tai esimerkiksi sulautetuissa järjestelmissä luetaan jonkin portin tila (vaikkapa varasvalvonnan ovi- ja ikkunakytkimet) tietyin väliajoin ja sen perusteella suoritetaan valinta, miten ohjelma jatkuu (käynnistetään kameranauhuri, kutsutaan yövahti, soitetaan poliisi, hälytetään palokunta, pannaan summeri soimaan, jne.). Kuva 5.4.3. switch-lause. switch-lauseen formaatti: switch (ehto) case luku1: lause1; break; case luku2: lause2; break; case luku3: lause3; break; case luku4: lause4; break; default: lause5 Switch-lauseen otsikossa on ehto-lauseke, joka määrää mikä case-sanalla merkityistä tapauksista valitaan. Lausekkeen arvon on oltava kokonaisluku, mutta sen paikalla voi käyttää myös erimerkiksi merkkivakiota. Jokaisella tapauksella on oma case-osansa. Lohkossa hypätään siihen kohtaan, joka vastaa muuttujan arvoa. Jokaisen vaihtoehdon käsittelyn jälkeen pitää laittaa break-käsky. Sillä poistutaan switch-lauseesta sitä seuraavaan komentolauseeseen. Jos vastaava arvoa ei löydy, hypätään 10

default-arvoon ja suoritetaan sen käskyt. Default-osassa voi olla esimerkiksi virhetilanteiden käsittelyyn liittyvää ohjelmakoodia, vaikka vikailmoitus. Se voi myös puuttua. Switch-lause on kuin vaihtokytkin, jonka avulla haaraudutaan oikeaan case-osaan, jos switchin jälkeen suluissa oleva lauseke saa jonkin caselauseen jälkeisen arvon. Jos mikään ei matsaa, suoritetaan default-lause. Switch-lause vaikuttaa monimutkaiselta, mutta siitä tulee selkeä parin harjoituksen jälkeen. switch-lause, esimerkki 1 /********************************************************** Project : switch_1. HW : PV-M32 + PV-TINT + PV-LEDIT on B-port SW : WinAVR-20070525 Date : 01.12.2007 Comments: switch-ehtorakenne case-ehdot "outoja", ne johtuvat PV-TINT-kortin rakenteesta **********************************************************/ #include <util/delay.h> // *** Primitive wait() *** void wait(uint16_t time) volatile uint16_t i; for(i=0;i<2000;i++) _delay_loop_2(time); int main(void) uint8_t inpu; DDRB = 0xFF; DDRD = 0x00; PORTD = 0xFF; // B-portin suunta lähtö, output // D-portin suunta tulo, input // D-portin pinnit ylös while(1) inpu = PIND; // luetaan D-portin tila switch(inpu) case 0x8B: PORTB = 0x0F; wait(1000); break; case 0xC7: PORTB = 0xF0; // jos INT0 painettu // jos INT1 painettu 11

wait(1000); break; default: PORTB = 0x81; // jos mitään ei painettu Analysointi Ensin luetaan D-portin tila. Jos mitään painokytkintä ei ole painettu, resetin jälkeen kaikki portin pinnit ovat tilassa looginen ykkönen, lukuunottamatta 5- ja 6-bittejä (johtuu kortin kytkennästä). Eli kun D- portin tila luetaan inpu-muuttujan arvoksi, on tulos 0xCF. Jos jompikumpi D-portin kahdesta kytkimestä on painettu alas, se maadoittaa ko. pinnin eli sen tila on nolla, joten inpu-muuttujan arvo muuttuu vastaavasti. Tätä testataan switch-lauseessa ja tämän jälkeen suoritetaan sen case-osan lause, jonka lausekkeen arvo on sama kuin ehto-osan lausekkeen arvo. Mikäli switch-lauseessa ei ole sellaista case-osaa, jonka lausekkeen arvo vastaa ehto-osan lausekkeen arvoa, (eli mitään kytkintä ei ole painettu) suoritetaan default-osan lause. Switch-lause, esimerkki 2 /********************************************************** Project : switch_2.c Hardware: PV-M32 + PV-EMO + PV-LEDIT on PORTB Software: WinAVR 20070525 Date : 03.07.2007 Comments: switch-ehtorakenne **********************************************************/ #include <util/delay.h> int main(void) unsigned char arvo, laskuri = 0; DDRB = 0xFF; // B-portin suunta lähtö, output while(1) if(laskuri < 5) PORTB = 0x01; laskuri++; arvo = laskuri; if(laskuri > 20) laskuri = 0; switch(arvo) case 5: PORTB = 0x04; // jos arvo on 5, LED 4 loistaa break; 12

case 10: PORTB = 0x10; break; case 15: PORTB = 0x40; break; default: wait(200); Analysointi Koodi ei kommenttia enempää kaipaa, kunhan teet tähän liittyvän harjoitukset. No goto! Basicilla ohjelmoineet muistanevat goto-lauseen. Se on myös C-kielessä. Goto-lause sallii hypyn koodissa mihin tahansa, eteen- tai taaksepäin. Siitä seuraa vaikeasti tulkittavaa koodia, spagetti-koodia. Ilman goto-lausetta voi C-ohjelman aivan hyvin tehdä, joten on parempi olla käyttämättä sitä. 13

5.4.2. Toistorakenne Toisto- eli silmukkarakenne on ohjelmarakenne, joka suorittaa saman asian useita kertoja peräkkäin. Jos on laskettava joku tietty arvo, vaikkapa viive, jos pitää säännöllisesti tietyn ajan kuluttua käydä lukemassa joukko portteja tai vaikkapa taulukon käsittely (opitaan myöhemmin), tarvitaan ohjelmoinnissa silmukkarakennetta. Koska sulautetuissa järjestelmissä ei (yleensä) ole käyttöjärjestelmää, tarvitaan jokaisessa ohjelmassa erityinen toistorakenne, ikuinen silmukka. Silmukkarakenteita on kolme erilaista; - for - while - do-while 5.4.2.1. for-silmukkalause, for-loop Jos tiedetään etukäteen, montako kertaa ohjelmasilmukka tulee tehdä, käytetään for-lausetta. Kuva 5.4.4. for-silmukka. for-silmukan formaatti: for(silmukkalaskurin_alkuarvo; ehto; päivitys) ohjelmalause; Jos useita lauseita liittyy for-silmukkaan, on käytettävä lausesulkeita. 14

For-silmukan kolme vaihetta 1. Laskurimuuttujan alkuarvon asetus, initialization Alkuarvon asetus voi olla mikä tahansa C-kielen lause. Yleensä se kuitenkin on sijoituslause, jolla asetetaan muuttujan alkuarvo. 2. Testi eli ehdon tarkistus, test-expression Sillä tarkistetaan jatketaanko silmukkaa vai ei. Testiehtolause on usein vertailulause. Toistoehto tutkitaan aina ennen mahdollista silmukan suoritusta. Jos ehto on tosi eli nollasta poikkeava, forlauseen komennot suoritetaan. Jos tulos taas on epätosi (nolla), silmukka pysäytetään ja siirrytään forlauseen jälkeiseen lauseeseen. Jos ehto on epätosi jo ensimmäisessä tarkistuksessa, ei ohjelmalausetta suoriteta kertaakaan. 3. Laskurimuuttujan arvon päivitys, increment/decrement Laskurin päivtys voi olla mikä tahansa C-kielen lauseke. Yleensä se on lause, joka kasvattaa alkuarvoa (yhdellä tai suuremmalla luvulla). Voi olla myös toisin päin eli vähennyslause. Silmukassa olevaa ohjelmalausetta toistetaan niin kauan, kunnes laskuri on kasvanut alarajalta ylärajalle tai päinvastoin. Silmukkalaskuri on muuttuja, joka tulee määritellä aivan kuten muutkin muuttujat. Laskurin alku- ja loppuarvot voivat olla mitä tahansa kokonaislukuja, tai jonkun muun numerotyypin alkioita. Vanhassa C:ssä for-silmukan alkulausekkeessa ei voinut alustaa muuttujia. Vuoden 1999 standardiin tuo ominaisuus lisättiin. Gcc:n uusimmatkaan versiot eivät tue koko C99-standardia kunnolla, mutta tuo ominaisuus kyllä löytyy ainakin gcc 3.0:sta. Tutkitaan muutama esimerkki ja tehdään harjoituksia, jotka selvittävät asiaa. For-lause, esimerkki 1 /********************************************************** Project : for_1.c HW: PV-M32 + PV-LEDIT SW: WinAVR-20070525 Date : 01.12.2007 Comments: for-lauseen demo **********************************************************/ #include <util/delay.h> // *** Primitive wait() *** void wait(uint16_t time) volatile uint16_t i; for(i=0;i<2000;i++) _delay_loop_2(time); 15

int main(void) uint8_t i; // silmukkalaskurin muuttuja DDRB = 0xFF; for(i = 0; i < 65; i++) // alkuarvo, testi, päivitys PORTB = i; wait(50); PORTB = 0x81; Analysointi Ensin for-silmukassa alustetaan laskurimuuttuja eli i:n arvoksi laitetaan 0. Sen jälkeen tutkitaan, onko laskurin tarkistamiseen annettu ehto tosi, vai epätosi. Ensimmäisellä kierroksella se on selvästi tosi, joten siirrytään suorittamaan for-lauseen runkoa, eli suoritetaan aaltosulkujen välissä olevat lauseet, järjestyksessä. Kun for-lauseen runko on suoritettu, kasvatetaan laskuria i, siis i++ eli i = i + 1; Nyt yksi for-lauseen kierros on suoritettu, ja i:n arvona on 1. Alustusta ei enää suoriteta, ainoastaan ehdon tarkistus, runko ja kasvatus. Seuraava kierros alkaa jälleen ehdon tarkistuksella, eli onko i < 65?, kyllä. Näin jatketaan kunnes ehto on epätosi eli 65 < 65. For lause päättyy. 5.4.2.2. For-lause ja ikuinen silmukka Tähän asti me olemme tehneet sulautetuissa järjestelmissä yleisen ikuisen silmukan while-lauseella. Sama voidaan tehdä myös for-lauseella. /********************************************* Project : for_ikuinen.c Date : 01.12.2007 Comments: ikuinen silmukka for-lauseella *********************************************/ #include <util/delay.h> // *** Primitive wait() *** void wait(uint16_t time) volatile uint16_t i; for(i=0;i<2000;i++) _delay_loop_2(time); 16

int main(void) uint8_t i = 0; // silmukkalaskurin muuttuja DDRB = 0xFF; for(;;) // ikuinen silmukka i++; // i = i + 1; PORTB = i; wait(100); if(i > 100) // jos yli 100, aloita alusta i = 0; Analysointia tuskin kaipaa. 5.4.2.3. Sisäkkäiset silmukat Silmukat voidaan laittaa sisäkkäin, yksi silmukka toisen sisälle. Sisällä oleva silmukka tulee suorittaa kokonaan jokaisen ulomman silmukan kierroksen aikana. Sisäkkäiset silmukat, esimerkki /********************************************************** Project : for_sisaiset.c HW: PV-M32 + PV-LEDIT on B-port SW: WinAVR-20070525 Date : 01.12.2007 Comments: for-lauseen demo **********************************************************/ int main(void) volatile uint8_t i; // ulompi silmukkalaskuri volatile uint32_t k; // sisempi silmukkalaskuri DDRB = 0xFF; for(i = 0; i < 65; i++) PORTB = i; for(k = 0; k < 30000; k++); // kulutetaan aikaa PORTB = 0x81; // for-lauseet läpikäyty 17

Analysointi Tärkeää on huomata, että tässä on käytettävä muuttujan volatile-määritystä. Muuten käännin optimoi koodin ja hypätään suoraan silmukasta ulos. Käy tutustumassa volatile-määrityksestä C-kielen käsitteet-osiosta. volatile uint8_t i; // ulompi silmukkalaskuri volatile uint32_t k; // sisempi silmukkalaskuri Käytämme for-silmukassa sisäistä for-silmukkaa, jossa ei tehdä mitään, kulutetaan vain aikaa laskemalla 300000:een. Luku on oltava suuri, jotta viive näkyisi. Kuten muistanet, AVR on RISCtyyppinen, joten yhdellä kellopulssilla tehdään koko konekäsky. Jos silmukkamuuttuja on saanut arvon ennen silmukkaan tuloa, sitä ei tarvitse initialisoida itse silmukassa. Toisaalta silmukkamuuttujan päivitys voi olla muutakin kuin +1. esim. laskuri = 4; for(; laskuri < 14; laskuri + 2) lauseita; Laskuri-muuttuja on asetettu jo ennen for-silmukkaa. 5.4.2.4. Break ja for-silmukka Break-käskyn suoritus aiheuttaa poistumisen ohjelman siitä (sisimmästä) ohjausrakenteesta, missä se sijaitsee. Ts. jos break kohdataan sisäisessä silmukassa, ohjelma hyppää ulospäin silmukan jälkeiselle komentoriville, tai seuraavaan silmukkaan. esim. for(laskuri = 0; laskuri < 9; laskuri++) PORTB = laskuri; if (laskuri == 5) //jos laskurin arvo yhtä kuin 5, hypätään ulos for-silmukasta break; 18

5.4.3. While-toistolause, while-loop Kun ei tiedetä tarkkaan, montako kertaa käskysarjaa pitää toistaa, käytetään while-lausetta. Siinä toistetaan käskysarjaa niin kauan kuin annettu ehto on tosi. While-lauseen tarve testataan ennen silmukkaan menoa. Siksi on mahdollista, että silmukkaa ei koskaan käydä läpi, eikä sen käskyjä suoriteta. Kuva 5.4.3.1. while-silmukka. while-silmukan formaatti: while (ehto) lause; esim. while (luku < 5) // niin kauan kuin luku on pienempi kuin 5, suoritetaan silmukassa käskyjä PORTB = 0xAA; Sulkujen sisällä on testi- eli jatkamisehto. Mikäli lausekkeen arvo on tosi, suoritetaan lause ja palataan uudelleen lausekkeen arvon testaamiseen. Esimerkkilauseessa niin kauan kuin luku-muuttuja on pienempi kuin 5, ehto on tosi ja silmukka jatkuu. Silmukassa ollaan, kunnes ehto on epätosi. Lopetusehto tarkistetaan aina ennen ensimmäistä toimenpidettä ja aina, kun ollaan silmukan käskyrivien lopussa. Ehto voi olla mikä tahansa C-lauseke, useimmiten vertailulauseke. Lause, joka while-silmukassa suoritetaan, voi olla * yksi lause, joka päättyy puolipisteeseen, tai * se voi olla useita lauseita, yhdistelmälause, jolloin se ympäröidään lausesulkeisiin. Itse ohjelmalauseet voivat olla mitä tahansa C-kielen lauseita. 19

While-lause, esimerkki 1 /********************************************************** Project : while_1.c HW: PV-M32 + PV-LEDIT on B-port SW: WinAVR-20070525 Date : 01.12.2007 Comments: while-lauseen demo **********************************************************/ #include <util/delay.h> // *** Primitive wait() *** void wait(uint16_t time) volatile uint16_t i; for(i=0;i<2000;i++) _delay_loop_2(time); int main(void) uint8_t testi = 33; DDRB = 0xFF; while(testi) testi--; // testi = testi - 1; PORTB = testi; wait(100); PORTB = 0x81; // while-lause läpikäyty Analysointi Äkkiä ajatellen yllä olevassa koodissa ei loppua tule koskaan. Mutta tutkitaan asiaa tarkemmin, opitaan samalla tärkeä seikka, jota tarvitaan, kunhan päästään ohjelmoinnissa mikro-ohjaimen sisäisiin laskureihin. Niin kauan kuin testi on erisuuri kuin nolla, ohjelma pyörii while-silmukassa vilkutellen LED-diodeja. Miksi ja milloin ohjelma viimein pysähtyy? Kun ehto on nolla, epätosi, sehän on selvä. Kun laskennassa muuttujan arvo on päätynyt arvoon 0x00, se on binäärisenä 0000 0000. Silloin whiletestiehto on selvästikin epätosi ja tullaan ulos silmukasta. Muista! C-kielessä kaikki nollasta poikkeavat luvut ovat tosi-true. Nolla on epätosi-false. 20

Sisäkkäiset while-lauseet while-silmukka voi olla toisen while-lauseen sisällä. Tällöin on pidettävä huolta, että sisäinen silmukka on kokonaisuudessaan ulomman sisällä. Ikuinen while-silmukka while(1) koodia Tässä ehto on aina tosi, joten ohjelma pyörii silmukassa 'ikuisesti'. Tämä on tyypillinen ja hyvin usein tarvittava sulautetun järjestelmän ohjelmasilmukka. while-silmukka ja odotus While-silmukkaa voidaan käyttää odotettaessa jotain tiettyä tapahtumaa, kuten ovikytkimen aiheuttamaa bitin kääntymistä. Kun ovi on sulkeutunut, ohjelma jatkuu while-silmukan jälkeisestä seuraavasta käskystä. while(ovi==1); Kun ovi sulkeutuu, ovi-muuttuja saa arvon 0 ja ohjelman eteneminen jatkuu. 5.4.4. Do-while-toistolause Do-while lause muodostaa silmukan, jota toistetaan kunnes testilausekkeesta tulee epätosi eli nolla. Dowhile lause on lopetusehtoinen silmukka. Päätös silmukan uudesta kierroksesta tehdään silmukan läpikäynnin jälkeen, joten silmukan kaikki käskyt suoritetaan ainakin kerran. Kuva 5.4.4.1. do-while-lause. 21

do-while-lauseen formaatti: do ohjelmalause(et); while (ehto); Ehto voi olla mikä tahansa C-lauseke, usein se on vertaileva lauseke. Jos lauseosassa on useita käskyjä, on käytettävä lausesulkeita. Lauseosaa toistetaan, kunnes testistä tulee epätosi eli nolla. Ehdon testi tehdään vasta käskyjen suorittamisen jälkeen. Miksi käytetään do-silmukkaa? do-silmukka on harvemmin käytetty kuin while. Erona on se, että while-lauseessa ehto testataan ennen käskysarjan suoritusta ja do-lauseessa vasta sen jälkeen. Mitä tämä käytännössä merkitsee? Jos silmukan lauseet on tehtävä ainakin yhden kerran, käytetään Do-lausetta. While-lauseen runkoa ei suoriteta kertaakaan, jos ehto on epätosi jo ensimmäisellä testauskerralla. Yleensä do.. while -rakennetta ei suositella käytettäväksi sen hankalan logiikan kannalta. Do-while esimerkki /********************************************************** Project : do_while.c HW: PV-M32 + PV-LEDIT SW: WinAVR-20070525 Date : 01.12.2007 Comments: for-lauseen demo **********************************************************/ #include <util/delay.h> // *** Primitive wait() *** void wait(uint16_t time) volatile uint16_t i; for(i=0;i<2000;i++) _delay_loop_2(time); 22

int main(void) uint8_t testi = 0x00; DDRB = 0xFF; do testi++; // testi = testi + 1; PORTB = testi; wait(50); while(testi < 9); // ehdon testaus PORTB = 0x81; // while-lause läpikäyty Analysointi Niin kauan kuin testi on pienempi kuin 9, suoritetaan silmukan koodit. Kun ehto ei ole tosi, hypätään ulos. while(testi < 9); // ehdon testaus 23