5.1. c-kielen perusteet. 1_8

17
1 5.1. Sulautetun järjestelmän C-kielen perusteet 1/8, Start 5.1.2008 pva ”Pienen maan armeija on samaa tarkoitusta varten kuin on päivystävän upseerin pistooli. Omia varten.” - Arvo Salo Osion sisältö Ohjelmoimaan oppii vain itse tekemällä Ensimmäinen ohjelma eka.c ja sen lähdekoodin listaus Miksi main-funktion tyyppi on int? viive C-ohjelman osat, Kommentit, Comments, Esikäsittelysäännöt, direktiivit, directives Mitä WinAVR- eli avr-gcc-kääntimen #include <avr/io.h -määritys sisältää Esikääntäjä - C Preprocessor Kirjastot, libraries, Perusdirektiivit main()-funktio Ikuinen silmukka Lähdekoodin kääntäminen Konekoodin lataus ohjelmamuistiin ja ohjelman ajaminen Bittikohtaiset siirto-operaattorit Bittikohtainen siirto vasemmalle Bittikohtainen siirto oikealle. Bittien siirto oikealle esimerkki Yhteenveto, Tavallisimmat sulautettujen operaattorit Portin ja rekisterin yksittäisen bitin asetus tai nollaus Portable esim. 1 OR-operaatio. AND-operaatio Bit Value BitValue_m32.c, harjoitus bittien_asetus_1.c esimerkki Kertausta Ohjelmoimaan oppii vain itse tekemällä Nyt alamme perehtyä C-kielen perusteisiin siten, että pääset mahdollisimman nopeasti kirjoittamaan omia ohjelmia. Se on tehokkain ja mielenkiintoisin tapa oppia. Kirja keskittyy vain kielen perusasioihin, erikoisesti laiteläheisiin perusasioihin. Kielen hienoudet ja ominaisuudet, jotka on tarkoitettu isojen koneiden ohjelmien kirjoittamiseen ja joita ei oikeastaan sulautettujen kääntimissä edes ole, jätetään pois. Mutta malta vielä hetki. Jotta ymmärtäisit miksi ensimmäinen laiteläheinen ohjelmakoodi on juuri sellainen kuin se (jäljempänä) on, Sinun on vielä perehdyttävä siihen, mikä ja millainen on AVR-mikro-ohjaimen portti ja sen rekisterit. Etsi esille kirjasta porttejä käsittelevä dokumentti: ”AVR portit ja niiden rekisterit.pdf” ja tutki se tarkkaan.

Upload: digindom

Post on 08-Apr-2015

365 views

Category:

Documents


2 download

TRANSCRIPT

Page 1: 5.1. C-kielen perusteet. 1_8

1

5.1. Sulautetun järjestelmän C-kielen perusteet 1/8, Start 5.1.2008 pva

”Pienen maan armeija on samaa tarkoitusta varten kuin on päivystävän upseerin pistooli. Omia varten.” - Arvo Salo Osion sisältö Ohjelmoimaan oppii vain itse tekemällä Ensimmäinen ohjelma eka.c ja sen lähdekoodin listaus Miksi main-funktion tyyppi on int? viive C-ohjelman osat, Kommentit, Comments, Esikäsittelysäännöt, direktiivit, directives Mitä WinAVR- eli avr-gcc-kääntimen #include <avr/io.h -määritys sisältää Esikääntäjä - C Preprocessor Kirjastot, libraries, Perusdirektiivit main()-funktio Ikuinen silmukka Lähdekoodin kääntäminen Konekoodin lataus ohjelmamuistiin ja ohjelman ajaminen Bittikohtaiset siirto-operaattorit Bittikohtainen siirto vasemmalle Bittikohtainen siirto oikealle. Bittien siirto oikealle esimerkki Yhteenveto, Tavallisimmat sulautettujen operaattorit Portin ja rekisterin yksittäisen bitin asetus tai nollaus Portable esim. 1 OR-operaatio. AND-operaatio Bit Value BitValue_m32.c, harjoitus bittien_asetus_1.c esimerkki Kertausta Ohjelmoimaan oppii vain itse tekemällä Nyt alamme perehtyä C-kielen perusteisiin siten, että pääset mahdollisimman nopeasti kirjoittamaan omia ohjelmia. Se on tehokkain ja mielenkiintoisin tapa oppia. Kirja keskittyy vain kielen perusasioihin, erikoisesti laiteläheisiin perusasioihin. Kielen hienoudet ja ominaisuudet, jotka on tarkoitettu isojen koneiden ohjelmien kirjoittamiseen ja joita ei oikeastaan sulautettujen kääntimissä edes ole, jätetään pois. Mutta malta vielä hetki.

Jotta ymmärtäisit miksi ensimmäinen laiteläheinen ohjelmakoodi on juuri sellainen kuin se (jäljempänä) on, Sinun on vielä perehdyttävä siihen, mikä ja millainen on AVR-mikro-ohjaimen portti ja sen rekisterit. Etsi esille kirjasta porttejä käsittelevä dokumentti: ”AVR portit ja niiden rekisterit.pdf” ja tutki se tarkkaan.

Page 2: 5.1. C-kielen perusteet. 1_8

2

Vihdoinkin pääset koodin tekoon Oletan, että olet tutustunut AVRStudioon, sen editoriin, WinAVR- eli avr-gcc-C-kääntimeen jo luvussa 4, kun asensit IDEn, Integrated Development Environment, integroidun ohjelmien kehitysympäristön. Siis tarvittavien ohjelmien asennukset, integrointi (yhteen liittäminen) ja konfigurointi (asetukset) on tehtynä. Joten opiskeluympäristö on alustavasti tuttu ja muutaman harjoituksen jälkeen osaat käyttää sitä rutiinilla.

Wilma 7v. haluaa myös oppia koodaamaan! 5.1. Ensimmäinen ohjelma eka.c Ennen kuin ryhdymme analysoimaan ensimmäisen esimerkkiohjelman koodia, tutustutaan mahdollisimman yksinkertaiseen C-kieliseen ohjelmaan. main() { }

C-kielen peruskäsitteitä ovat funktio ja muuttuja. Muuttujiin tallennetaan käsiteltäviä tietoja. Funktio sisältää komentolauseita, jotka ovat ohjeita tietokoneelle. Tietokone toimii näiden ohjeiden, käskyjen mukaan. Funktioita tulee olla vähintään yksi, nimittäin pääfunktio main(). Kääntäjäohjelma tunnistaa nimen funktioksi nimeä välittömästi seuraavista kaarisulkeista (). Aaltosulkeet {} rajoittavat itse funktion rungon. { on funktion alkumerkki ja } on loppumerkki. Kaikki käskyt, tiedot, määritykset, yms. kirjoitetaan aaltosulkeiden väliin. Tässä esimerkissä ei tehdä vielä mitään, koska ohjelmarunko on tyhjä.

Page 3: 5.1. C-kielen perusteet. 1_8

3

Seuraava vaihe: void main() { PORTB = 0xF0; }

Lisätään vielä funktion tyyppi ja itse runkoon yksi käskyrivi. Main-funktion tyyppi on tavallisesti kaikissa (ilman käyttöjärjestelmää olevissa) esimerkeissä void. Käskyrivillä sijoitetaan B-porttiin heksaluku F0 (binäärisenä 1111 0000). Se tehdään sijoitusoperaattorilla (=). Se ei siis ole C-kielen yhtäsuuruusmerkki, vaan komento sijoittaa merkin oikealla puolella oleva arvo sen vasemmalla puolella olevaan muuttujaan tai tässä tapauksessa porttirekisteriin. Oikeastaan sijoitus on tiedon kopiointia paikasta toiseen. Tästä ja muista operaattoreista myöhemmin lisää. Mikroprosessori hakee ohjelmamuistista käskyn, tulkitsee sen ja käskyn perusteella kirjoittaa mikro-ohjaimen B-porttiin heksaluvun 0xF0. Portti on ikään kuin ovi mikro-ohjaimen ja ulkomaailman välillä. Se on bittien 'sisään- ja uloskäynti'.

WinAVR-kääntimen tapa kirjoittaa dataa porttiin: PORTB = 0xF0; B-porttiin kirjoitetaan heksaluku 0xF0, eli 111 0000 binäärisenä. Oikealla on vähiten merkitsevä bitti, LSB Least Significant Bit.

Jos heksaluvut eivät ole tuttuja, nyt olisi aika perehtyä niihin. Perusteetkin eli idean ymmärtäminen riittää, tosiosaaminen tulee koodia tehdessä. Vielä tarvitaan jotain #include <avr/io.h> void main(void) { PORTB = 0xF0; }

Lisäämällä #include-rivi, kerrotaan (esi)kääntimelle mikä ohjetiedosto liitetään ohjelmaan mukaan. Tämä tiedosto, io.h, sisältää käytössämme olevan mikro-ohjaimen ”käyttöohjeet”, eli miten käsitellään main-funktiossa olevaa komentoriviä ja mistä osoitteesta kyseinen portti, B-portti, löytyy. Näin koodista tulee yksinkertaista, B-portti ja totta kai kaikki muutkin rekisterit löytyvät ilman monimutkaisia osoitemäärityksiä, sillä ne on tehty valmiiksi kääntimen kirjastoissa (jonka käytön ja sisällön tulet myöhemmin tässä kirjassa oppimaan). *.h header-file Header-tiedoston tarkoitus on koota yhteen paikkaan muuttujat ja niiden funktioiden esittelyt jotka ovat muidenkin ohjelmamoduulien käytössä. Kun ohjelma on pieni, niitä ei tarvita, siis kirjastotiedostoja lukuunottamatta. Kun ohjelmasi kasvavat monia moduuleita käsittäviksi, silloin niitten merkitys tulee tärkeäksi. Matkan varrella headereista lisää.

Page 4: 5.1. C-kielen perusteet. 1_8

4

*.h, oikeaoppisessa header-tiedostossa ei ole ajokelpoista koodia. C-kielen ohjelmissa headereissa - määritetään vakioita - määritetään makroja - esitellään ohjelmassa käytettävät funktiot, c-tiedostot, yms.

Katso tarkemmin io.h-tiedoston sisällöstä kaaviokuvassa joka löytyy liitteestä. Funktion nimirivillä olevien kaarisulkeiden väliin kirjoitetaan funktion parametrit (tässä void, tyhjä, eli ei parametreja). Ne selvitetään myöhemmin. Nyt meillä on riittävästi tietoa, jotta voimme analysoida ensimmäistä C-ohjelmaa.

Bitti ja tavu Pienin tiedon yksikkö on bitti. Se arvo voi olla nolla tai yksi, 0 tai 1. Tavu on kahdeksan bittiä. Jokainen tavun bitti voi olla 0 tai 1, joten erilaisia tavuja voi olla kaikkiaan 2 potenssin 8 eli 256 kappaletta.

eka.c, jatkuu Ohjelman tekeminen alkaa lähdekoodista, source code. Se kirjoitetaan C-kielen kielioppisääntöjä noudattaen ja tallennetaan tavallisena ASCII-tekstinä tiedostoon. Lähdekoodista käännin-ohjelma tekee objektitiedoston, object code, ja linkkeri-ohjelma, linker, yhdistää objektikoodin ja tarvittavat kirjastotiedostot ajettavaksi ohjelmatiedostoksi. Tutustu (edes alustavasti, myöhemmin perusteellisemmin) WinAVR-käännösprosessiin dokumentissa ”C-lähdekoodin kääntäminen.pdf”. ASCII-koodi (American Standard Code for Information Interchange ) on Yhdysvalloissa kehitetty ja yhteisesti maailmanlaajuiseen käyttöön sovittu tapa merkitä kirjaimet ja numerot 7- (standardi ASCII) tai 8-bitin (laajennettu ASCII) paketteina. PC-ympäristössä C-kielen opiskelun aloittavan ensimmäinen suuri haaste on ollut saada ohjelma tulostamaan kuvaruudulle teksti "Hello, World". Siitä on muodostunut kaikissa oppikirjoissa esiintyvä perinne. Sulautetuissa järjestelmissä ei ole käytössä monitoria, joten on tyydyttävä vilkuttelemaan PV-M32-MOOkitin (mikro-ohjain-opiskelukortti/kit) ledejä.Tästä syntynee samanlainen perinne. (Kyllä se ”Hello World”-kin vielä koodataan ja tulostetaan LCD-näyttöön ja monitoriinkin.) Käynnistä AVRStudio. Ensin pitää luoda projekti ja kirjoittaa sekä tallettaa ensim-mäinen C-kielinen ohjelma Omat_koodit-kansioon. Annetaan sille nimeksi eka.c

Page 5: 5.1. C-kielen perusteet. 1_8

5

eka.c lähdekoodin listaus /************************************************** ******** Project : eka.c Hardware: PV-M32-MOOkit (4 MHz) + PV-LEDIT B-portis sa Software: WinAVR-20071221 Date : 01.01.2008 Author : pva Comments: vilkuttaa B-portin LEDejä *************************************************** *******/ #include <avr/io.h> #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; // suunta ulos while(1) { PORTB = 0xF0; // B-porttiin 1111 0000 wait(500); // kulutetaan aikaa PORTB = 0x0F; // B-porttiin 0000 1111 wait(500); } } Talleta. File, Save, tai paina disketin kuvaketta. Rivi- ja sarakenumero näkyy AVRStudion editorissa, status-barin alhaalla oikealla.

Miksi main-funktion tyyppi on int? Funktion tyyppi kertoo sen palauttaman arvon tyypin, kuten opit myöhemmin. Tavallisesti sellaisen funktion tyypiksi, joka ei palauta arvoa, laitetaan void, tyhjä. WinAVR-käännin olettaa main-funktion tyypin olevan int, mikä periytyy gcc:n historiasta (se palauttaa tietoa käyttöjärjestelmälle). Jos se ei sitä ole, käännin antaa käännöksen yhteydessä varoituksen. Tämä ei ole vaarallista. Jotta turhilta varoituksilta vältytään, olen ottanut käytännön, että main-funktion tyyppi on aina int. Kun käytetään käyttöjärjestelmää, se kutsuu aina main()-funktiota, josta ohjelma alkaa/käynnistyy. Main-funktio palauttaa aina int-tyyppisen datan, muut funktiot voivat palauttaa kaikkea muutakin.

Page 6: 5.1. C-kielen perusteet. 1_8

6

Kuva 5.1.1. eka.c ja AVRStudio. AVRStudion eräs hyvä puoli on se, että se tuo kaikki projektiin kuuluvat tiedostot (hakemistopuussa) mukavasti esille. Kun header-nimeä klikkaa hiirellä, ko. tiedosto aukeaa editori-ikkunaan. Aluksi kannattaa opetella ainakin C-kääntimen ja ohjelmointi- eli lataajan kutsunapit. IDE-ikkunan ulkoasua voi muutella halutuksi. Jos virheilmoituksia on paljon, niin niiden korjaamisen ajaksi kannattaa alimmalla oleva info-fikkuna suurentaa. Tai jos koodia kirjoitellaan, silloin saattaa olla mukavaa, jos editori-ikkuna on iso. Debuggaus-ikkuna (oikealla) on leikattu kuvasta pois. Sen käytöstä on oma dokumentti.

Page 7: 5.1. C-kielen perusteet. 1_8

7

viive, delay Viive-funktio ei kuulu normin mukaiseen ANSI C-kirjastoon. Tarvitsemme kuitenkin melkein jokaisessa ohjelmaesimerkissä viivettä, jotta ehdimme nähdä ja tajuta mitä ohjelma tekee. Nykyisessä kääntimen libc-kirjastossa on kyllä useitakin viive-funktioita (niiden viiveet ovat hyvin lyhyitä), mutta tyydytään tässä vaiheessa käyttämään ”omatekemää”. // *** Primitive wait() *** void wait(uint16_t time) { volatile uint16_t i; for(i=0;i<2000;i++) _delay_loop_2(time); }

wait-ohjelman tarkoitus on siis vain kuluttaa aikaa, ts. pysäyttää ohjelman eteneminen, mutta vain hetkeksi. Sen toiminta selviää myöhemmin.

Huom! Tällaisia viiveitä ei normaalissa sulautettujen koodissa ole kuin aivan poikkeustapauksissa ja silloinkin ne tehdään tarkasti mikro-ohjaimen omilla ajastimilla eli timereillä. Tämä käyttö on vain opiskelutarkoitukseen.

Tarkkojen viiveiden käyttö edellyttää timer/counter-järjestelmän käyttöönottoa, joten ne on opittava ensin. Siksi erilaisista viive-funktioista ja niiden käytöstä on oma lukunsa. Toinen tapa tehdä viive Kirjoitetaan sama wait-funktio makroksi. #define WAIT(time) for(uint16_t i=0;i<2000;i++)_del ay_loop_2(time);

Jos tutkii tarkkaan yläolevaa koodiriviä, huomaa, että kyseessä on sama asia kuin primitive wait-funktiossa. Vain kirjoitustyyli on erilainen. Siispä se toimii aivan samalla tavalla. Olet tarkkana, WAIT(time) ja lopun välissä on tyhjä merkki, siis väli, loppuosa pitää kirjoittaa yhteen pötköön. Käytännössä on parasta käyttää kummassakin tapauksessa ”kopipastaa”-menetelmää, silloin koodi tulee varmasti kirjoitettua oikein. Käytän tämän viiveen kutsuna isoja kirjaimia, erotuksena wait-funktiosta. Intentional change in the library. Too many people have stumbled across that, so I decided it's worth a warning. If you don't want the "convenience" functions (_delay_us, _delay_ms) but only the basic delay functions _delay_loop_1 and _delay_loop_2 (which are independant of the optimization level), you can use <avr/delay_basic.h> instead of <avr/delay.h>, and won't get the warnings then (neither the one about F_CPU). _________________ Jörg Wunsch

Page 8: 5.1. C-kielen perusteet. 1_8

8

Sitten päästään töihin eli aloitetaan analysoimalla eka.c-lähdekoodia ja samalla opitaan, mitkä ovat C-ohjelman osat Jokaisessa C-kielisessä ohjelmassa esiintyvät samat peruselementit, olipa ohjelma PC:ssa ajettava iso koodi tai sulautetun järjestelmän pienen pieni koodi. Siis ohjelman rakenne on aina samanlainen, koko vain muuttuu. Tavallisesti ainakin seuraavat osat löytyvät: - kommentit - esikäsittelysäännöt - pääfunktio main() - muuttujat - ohjelmalauseet

Kuva 5.1.2. C-kielisen ohjelman rakenne.

Page 9: 5.1. C-kielen perusteet. 1_8

9

Kommentit, Comments /************************************************** ******** Project : eka.c Hardware: PV-M32-MOOkit (4 MHz) + PV-LEDIT B-portis sa Software: WinAVR-20071221 Date : 01.01.2008 Author : pva Comments: vilkuttaa B-portin LEDejä *************************************************** *******/

Ensimmäiset rivit ohjelmassamme sisältävät huomautuksia, kommentteja. Kommentti sijoitetaan merkkiparien /* ja */ väliin, tai // kommenttirivin alkuun. Huomautukset ovat vain Sinulle itselle, jotta ymmärtäisit vielä huomennakin mitä ohjelma tekee. Niin, ja tietysti toisille ohjelmoijille, heidänkin tulee kyetä tulkitsemaan koodia oikein ja sitä kautta ymmärtämään ohjelman toiminta. Kommentteja kannattaa käyttää sopivassa määrin, ainakin alussa mieluummin liikaa kuin liian vähän. Itsestäänselvyyksiä ei tietenkään kirjata. Kommentit tulee kirjoittaa samaan aikaan kuin itse ohjelmakoodi, jotta kaikki oleellinen tulisi kerrottua silloin kun se vielä on muistissa (oman pääsi muistissa).

Käännin-ohjelma ei huomioi kommentteja, se ohittaa ne. Siksi ne eivät kuluta ohjelmamuistia.

Kommentteja voidaan määrittää kahdella eri tavalla: // kommentti - kaksi kauttaviivaa kertoo c-kääntimelle, että koko rivi tulee ohittaa, siis ei huomioida. Tämä tapa tulee C++-ohjelmasta, mutta se toimii myös C-käännin-ympäristössä (C99). Käytä tätä yhden rivin kommentteihin. /* kommentti */ - on C-kielen alkuperäinen (ISO C90 = ANSI C 89) merkintä. Käytä tätä tapaa, jos kommentti on pidempi kuin yksi rivi. Huom! Heti opiskelun alussa on tärkeää oppia oikeat työmenetelmät. Siispä sovitaan, että toimit näin: Jokainen ohjelmasi sisältää aluksi kommenttirivejä, joissa on vähintään seuraavat tiedot ohjelmasta:

- tiedoston (siis ohjelman) nimi, - mille ”raudalle” (AVR-ohjain) koodi on kirjoitettu - mille C-kääntäjälle koodi on kirjoitettu - päiväys, milloin ohjelma tallennettu/muutettu, - tekijän nimi tai nimilyhenne - lyhyt kuvaus mitä ohjelma tekee

Näin omaksut heti oikean tyylin tehdä ohjelmia ja tulet - muut ohjelmoijat etenkin - arvostamaan sitä myöhemmin, kun harrastuksesi, toivon mukaan, muuttuu ammatiksi.

Page 10: 5.1. C-kielen perusteet. 1_8

10

Esikäsittelysäännöt, direktiivit, directives #include <avr/io.h> // kirjastotiedosto #include <util/delay.h>

Seuraavat kaksi riviä sisältävät ns. direktiivit, #include <avr/io.h>, ja

#include <util/delay.h>. Ne ovat ohjeita (esi)kääntimelle sisällyttää, include, omaan koodiimme kulmasulkujen välissä olevat kirjastotiedostot. io.h on WinAVR-kääntimen kirjoittajien AVR-mikro-ohjaimille kirjoittama kirjastotiedosto, otsikko-tiedosto eli header-file (header, koska se sijoitetaan tiedoston huipulle, head). io.h:n alussa sijoitetaan avr/sfr_defs.h-tiedosto sekä määritellään kaikille prosessoreille yhteiset määrittelyt kuten pino-osoitin, tilarekisteri, pointterit. Lisäksi suurimmalle osalle määritetään EEPROM-rekisterit. Lopuksi haetaan prosessorikohtaiset määrittelyt sijoittamalla avr/iom32.h tiedosto (tai mikä ohjain on käytössä). Tässä tiedostossa on esim. porttien osoittimet toteuttavat makrokutsut.

io.h on ohjeisto joka sisältää komennon joka sisällyttää mukaan mm. header-tiedoston iom32.h, - jossa puolestaan on ohjeet, miten käsitellään ATmega32 mikro-ohjainta - ja lisäksi se sisältää kaikkien muidenkin AVR-ohjaimien vastaavat tiedostot.

Kirjastotiedosto on ”koodivarasto”, joka helpottaa meidän työtämme ja jota ilman ohjelma ei toimi. Näitä ’hiidereitä’ kuuluu ANSI-C-normin kirjastoon kymmenittäin ja lisäksi ovat kääntimen valmistajat kirjoittaneet eri tarkoituksiin lisää. Ne löytyvät C:\WinAVR-20071221\avr\include-hakemistosta ja osa sen avr-alihakemistosta, ja \lib-hakemistossa on vielä muutama lisää. Käy katsomassa. Toinen direktiivi on <util/delay.h>. Se siltää funktion _delay_loop_2(time);

jota tarvitaan varsinaisen viive-funktion tekemiseen. // *** Primitive wait() *** void wait(uint16_t time) { volatile uint16_t i; for(i=0;i<2000;i++) _delay_loop_2(time); }

Page 11: 5.1. C-kielen perusteet. 1_8

11

WinAVR-kääntimen #include <avr/io.h -määritys sisältö:

Kaikki muut headerit ovat ”yhteisiä”, siis samoja kaikille mikro-ohjaimille, mutta mikro-ohjaimen header (tässä iom32.h) valitaan makefile-tiedoston perusteella. Käytä aina pelkästään io.h-tiedostoa, ohjaimen header valitaan makefilen perusteella. Katso C:\WinAVR-20071221\avr\include\avr

Page 12: 5.1. C-kielen perusteet. 1_8

12

Kun olet pidemmällä avr-gcc-kääntimen opinnoissa, voit käydä tutkimassa asiaan tarkemmin dokumentissa ”C-lähdekoodin kääntäminen.pdf”.

Hieman yksinkertaistaen: #include on ’leikkaa ja liimaa’ -toiminto. Se hakee tiedoston sisällön ja upottaa sen siihen kohtaan, jossa #include-rivi koodissa on.

Huom! ”Risuaita” #-käskyt eivät ole mukana kääntimelle menevässä koodissa, sillä en eivät ole ohjelmakoodia, vaan ohjetekstiä esikääntimelle. Esikäännin - C Preprocessor on ohjelma, joka käsittelee lähdekoodia ennen kuin varsinainen käännin ottaa sen käsittelyynsä. Esikäsittelysäännöt alkavat aina ”risuaitamerkillä” # ja ne ovat siis ohjeita esikääntimelle. Esikäännin työstää ohjelmoijan työtä helpottavia vakiomäärittelyjä, makroja ja ehdollisen kääntämisen komentoja. Rivin loppuun ei kirjoiteta puolipistettä, kuten yleensä C-kielen lauseiden loppuun.

Makrot ovat osa C-esikäännintä Kun esikäännin kohtaa makron, se korvaa makron nimen koodilla, joka suorittaa varsinaisen toiminnon. Lisää makroista edempänä.

Esikääntimen ohjekomennot ovat aina ohjelman alussa ja se ikään kuin vaihtaa ohjeet eli direktiivit header-tiedoston sisältöön. (Poikkeuksen tekevät mm. ehdollisen kääntämisen lauseet #if ja #ifdef tms. määritykset, joita on pitkin koodia. Niistä myöhemmin lisää). Tuloksena syntyy tiedosto, jonka varsinainen käännin kääntää yhdessä muun lähdekoodin kanssa ensin assembly-koodiksi, jonka assembler edelleen kääntää AVR-ohjaimen ymmärtämäksi konekoodiksi. Kirjastot, libraries ANSI-C määrittää standardikirjaston, jossa esitellään ne valmiit perusfunktiot, jotka ovat käytettävissä eri prosessoriympäristöissä ja josta voi poimia useaan eri tilanteeseen ja ongelmaan sopivan ohjelmamoduulin. Normi esittää yksityiskohtaisesti kunkin funktion toiminnan. Kirjastoon voi kukin kääntimen valmistaja, tai vaikka yksityinen ohjelmoija, lisätä standardiin kuulumattomia funktioita, jos oma järjes-telmä edellyttää erityistarpeita tai vaan antamaan lisämukavuuksia koodaamiseen. ANSI-C:n standarditiedostot ovat aivan liian massiivisia 8-bittisiin mikro-ohjaimiin. Sulautetuissa järjestelmissä header-tiedostot sisältävätkin pääasiassa erilaisia mikro-ohjaimen rautaan (so. rekistereitä ja niiden osoitteita jne.) liittyviä määrityksiä. Oikeita standarditiedostoja löytyy vain nimeksi ja nekin yleensä enemmän tai vähemmän vajaina. Tämä tietenkin riippuu kääntimen valmistajan ahkeruudesta. AVRLibC on AVR-mikro-ohjaimien standardikirjasto.

Page 13: 5.1. C-kielen perusteet. 1_8

13

avr-gcc-käännin on sovitettu versio ’oikeasta’ C-kääntimestä (GCC) ja sen tekijät ovat pyrkineet pitäytymään mahdollisimman pitkälle normissa. Luonnollisesti kirjastosta löytyy myös prosessoreihin liittyviä ’bitin nypläykseen tarkoitettuja osioita’. Kääntimen mukana tuleva kirjasto, siis include-tiedostojen määrä ja laatu määrittävät kääntimen käytettävyyden. Nopeudella ei yleensä näin pienissä järjestelmissä ole merkitystä, mutta sillä on, millaisiin ongelmiin ne tuovat apua ja kuinka hyvää koodia ne kääntävät. Hyvä tarkoittaa tässä yhteydessä; kuinka ’tiivistä’ koodia (mahtuu pieneen muistitilaan) ja kuinka virheetöntä käännöstulos on. Kääntämisen jälkeen automaattisesti toimiva linker-ohjelma ottaa kirjastoista käyttöön vain sen, mitä se koodiin tarvitsee ja lisää sen em. käännökseen.. Perusdirektiivit #include <tiedostonimi.h> - esikäännin ei hae tiedostoa siitä hakemistosta, missä varsinainen C-ohjelma on, vaan yleisessä käytössä olevasta standardihakemistosta, tässä tapauksessa C:\WinAVR\avr\include\avr-hakemistosta. #include "tiedostonimi.h" - esikäännin etsii tiedostoa ensisijaisesti siitä hakemistosta, jossa ohjelman lähdekoodi sijaitsee (työhakemisto) ja vasta sen jälkeen yleiskäyttöisistä hakemistoista. Tähän kategoriaan kuuluu ohjelmoijan omatekemiä (tai ’lainattuja’) tiedostoja, joko C- tai assembly-kielisiä. Tiedostonimi kirjoitetaan lainausmerkkien ” ” väliin. Sitten palataan takaisin esimerkkikoodin pariin. main()-funktio int main(void) { koodia }

Funktiot ovat C-kielisen ohjelman moduuleita, aliohjelmia, jotka tekevät tietyn osakokonaisuuden. Ne ovat ikään kuin lego-palikoita, joita kutsutaan käyttöön tarvittaessa. Funktion tunnistaa nimestä ja kaarisulkeista (). Kaarisulkeiden väliin kirjoitetaan parametrit. Ellei niitä ole, älä jätä tilaa tyhjäksi, vaan kirjoita paikalle void, sillä void-sanalla ilmaistaan tässä yhteydessä ettei parametreja käytetä. (Argumenteista, parametreista, kuten myös itse funktioista, myöhemmin lisää). Funktion alkumerkkinä on aaltosulku auki { ja loppumerkkinä on aaltosulku kiinni }. Näiden väliin kirjoitetaan varsinainen ohjelmakoodi tiettyjen muotosääntöjen, syntaksin, mukaisesti. Koodi koostuu C-kielisistä lauseista, joista jokainen edustaa yhtä operaatiota, toimintoa. Yksi C-kielen lause puolestaan edustaa useita (jopa kymmeniä) konekielen käskyjä.

Page 14: 5.1. C-kielen perusteet. 1_8

14

Funktiolla on oltava - nimi, tunnus, jolla sitä kutsutaan ja - tyyppi, joka kertoo ns. paluuarvon tyypin.

Funktioita voi olla ohjelmassa miten monta tahansa, mutta main-funktio on poikkeustapaus. Jokaisessa C-kielisessä ohjelmassa on oltava yksi ja vain yksi main-funktio. Siitä alkaa aina ohjelman suoritus. Nimen edessä kerrotaan paluuarvon tyyppi, joka tässä on int, integer, kokonaislukutyyppi (GCC:n oletustyyppi).

Huom! Joissakin vanhoissa koodeissa (ja kirjoissa) käytetään merkintää int main() Se ei ole suositeltavaa, vaan käytä int main(void)

Ikuinen silmukka Pienissä sulautetuissa järjestelmissä ei ole käyttöjärjestelmää. Siksi ohjelman ”hengissä pitäminen” on tehtävä muilla konsteilla. while(1) { PORTB = 0xF0; // B-porttiin 1111 000 wait(500); // kulutetaan aikaa PORTB = 0x0F; // B-porttiin 0000 1111 wait(500); }

Tyypillinen sulautetun järjestelmän ohjelman elementti on ikuinen silmukka. Tässä se on ns. while-silmukka. While-komento kuuluu ohjelman ohjausrakenteisiin, joihin perehdymme tarkemmin sen omissa harjoituksissa. While-silmukan sisällä olevaa koodia suoritetaan alusta loppuun rivi kerrallaan yhä uudelleen ja uudelleen, niin kauan, kun kaarisulkujen () välissä oleva ehto on tosi.

Kuva 5.1.3. Ikuinen silmukka - endless loop: while(1) {};

Page 15: 5.1. C-kielen perusteet. 1_8

15

C-kielessä - nolla on epätosi, false, ja - kaikki nollasta poikkeavat arvot ovat tosia, true.

Joten, koska ykkönen on aina tosi, while-silmukan ehto on aina tosi ja silmukka jatkuu ’ikuisesti’. Tai ainakin niin kauan kuin sähköä riittää.

Miksi käytetään ikuista silmukkaa? - se on yksinkertainen ja helppo käyttää (ja koodata), helppo testata ja

tarvittaessa muuttaa - ei tarvita erityistä ”rautaa” - koodi on portable, siirrettävää

Mitallin toinen puoli:

- ikuinen silmukka ei takaa signaaleille tarkkaa ajoitusta - MCU toimii koko ajan ”täysillä” = kuluttaa sähköä - siksi sähkön säästämiseksi ohjain kannattaa laittaa ”nukkumaan” aina

kuin mahdollista (siitä myöhemmin lisää)

Ohjelma toiminta: While-silmukan sisällä on ensin lause PORTB = 0xF0; // B-porttiin 1111 0000

Tällä lauseella kirjoitetaan B-porttiin heksaluku 0xF0, se on binäärisenä 1111 0000. Portin neljä eniten merkitsevää bittiä (vasemmanpuoleiset) asetetaan ykköseksi (+5 V) ja portin neljä vähiten merkitsevää bittiä (oikeanpuoleiset) asetetaan nollaksi (0 V). 0x-etuliite kertoo C-kääntimelle, että sitä seuraavat kaksi merkkiä ovat heksa-lukuja. Lause päättyy puolipisteeseen (;). (Melkein) kaikki C-kielen lauseet päättyvät puolipisteeseen. Looginen yksi (1) lähtöportissa merkitsee sitä, että portin pinneihin kytketyt LEDit saavat +5 Voltin jännitteen ja riittävästi virtaa, jolloin ne loistavat valoa ja looginen nolla (0 V) merkitsee sitä, että portin lähtöihin kytketyt LED-diodit eivät saa ohjausjännitettä ja ne ovat pimeitä, eivät siis loista valoa. Elleivät heksa-luvut ole vielä tuttuja, vilkaise kappaletta ”Lukujärjestelmät”.

Page 16: 5.1. C-kielen perusteet. 1_8

16

Sitten kutsutaan ’omatekemää’ wait- eli delay- eli viive-funktiota wait(500); // kulutetaan aikaa

Funktion tunnistaa nimen perässä olevasta kaarisulkuparista. Funktiota kutsutaan C-kielessä nimellä. Kutsu tarkoittaa sitä, että nyt main-funktiosta hypätään kutsuttavaan wait()-funktioon ja ohjelma jatkuu sieltä. wait()-funktiossa kulutetaan vain aikaa kaarisulkujen välissä olevan lukuarvon verran (millisekunteja). Arvo ei ole tarkka, se on noin ’suurin piirtein’. Seuraavat kaksi riviä ovatkin helppo selvittää edellisen perusteella. PORTB = 0x0F; // B-porttiin 0000 1111 wait(500);

Nyt B-porttiin kirjoitetaan uusi luku 0x0F, eli portin kahdeksaan pinniin tulee päinvastaiset loogiset tilat kuin edellisessä lauseessa oli. Jännite +5 V saa LED-diodin loistamaan. Viive on sama kuten edellä. Silmukan suoritus alkaa jälleen alusta, koska kyseessä on ikuinen silmukka. Lähdekoodin kääntäminen Ensimmäisen ohjelman lähdekoodi on nyt valmis ja analysoitu. Seuraavaksi se on käännettävä mikro-ohjaimen ymmärtämään muotoon. Kutsutaan C-käännintä klikkaamalla AVRStudion työkalurivin Built-painonappia, tai valitsemalla sen alasvetovalikosta. Jos koodi on kirjoitettu oikein, noudattaen C-kielen kielioppisääntöjä ja olet konfiguroinut ohjelmat huolellisesti, AVRStudion alaosaan avautuu kääntämisen onnistumisesta kertova viestit, messages. Jos käytät editorina ConTEXTia (tai jotain muuta), paina kääntimen ”kutsupoikaa”. Editorin ala-ikkuna kertoo käännöksen eri vaiheet ja lopputuloksen. Tärkeintä on ilmoitus ’Errors: none’, ei käännösvirheitä. Jos virheitä ilmenee, tarkista lähdekoodin kirjoitusasu. Jos yksikin merkki on väärin, liikaa, puuttuu, tai on väärässä paikassa, niin käännin ei ymmärrä koodia ja käännösprosessi keskeytyy.

Huom! Tulo- ja lähtökäskyt, eli Input/Output eivät kuulu varsinaiseen C-kieleen. C-kielen kääntimistä löytyy kyllä input- ja output-funktioita, joita voi käyttää. Mikro-ohjaimen I/O-liitäntä tapahtuu porttien avulla. Portti on oikeasti CPU:n rekisteri, jolle on ulkoista liitäntää varten rakennettu puskurivahvistin. Siten se pystyy käsittelemään suurempia virtoja kuin tavallinen rekisteri. Yleensä portti pystyy ’nielemään’ noin 20 mA virran, mutta antaa ulos huomattavasti vähemmän. Esim. AVR:n portit ’nielevät’ 20 mA per portin pinni, ja ’antavat’ ulospäin 5 mA. Uudet mega-piirit toimivat symmetrisesti, molempiin suuntiin maksimivirta on 20 mA. Portin kokonaisvirta, siis kaikkien pinnien summavirta, voi olla maksimissaan 80 mA. Kannattaa tutkia piirin datalehteä doc2503.pdf, jonka saa Atmelilta.

Page 17: 5.1. C-kielen perusteet. 1_8

17

Konekoodin lataus ohjelmamuistiin Kun käännös on ok, ladataan, ’loudataan’, konekielelle käännetty koodi eka.hex mikro-ohjaimen ohjelmamuistiin. Suoritetaan mikro-ohjaimen ohjelmointi. Latausohjelman käyttöönotto tapahtuu klikkaamalla AVRStudion Tools-valikosta Programmer-nappia (tai ConTEXTin vastaavaa ”kutsupoikaa”). Jos olet konfiguroinut kaiken oikein, se käynnistää lataajaohjelman ja lähdekoodin konekielikäännös, eka.hex, siirtyy bittijonona PC:n muistista AVR-ohjaimen ohjelmamuistiin (flash). Jos kaikki onnistui oikein, ohjelma käynnistyy saman tien. LED-diodit alkavat vilkkua neljän ryhmissä noin 0,5 sekunnin tahtiin. Jos haluat palauttaa tarkemmin mieleen mitä kääntämisessä ja ’flässäyksessä’ eli ohjelman siirtämisessä muistiin oikein tapahtuu, tutki niistä kertovia dokumentteja kirjassa toisaalla.