Professional Documents
Culture Documents
5.2. C-Kielen Perusteet. 2 - 8
5.2. C-Kielen Perusteet. 2 - 8
Sisältö
Muuttuja, variable
Ohjeita muuttujan nimeämiseen:
Miksi muuttuja pitää esitellä?
Operaattorit, operators
Sijoitusoperaattorit
Sijoitus- ja matemaattisten operaattoreiden yhdistäminen
Matemaattisten operaattoreiden käyttö-harjoitus
Vertailuoperaattorit
Unaarioperaattori
Lisäys- ja vähennysoperaattorit
Varatut sanat
1
Yleistä
Siispä töihin.
Luo uusi projekti, nimi eka_2.c. Kirjoita seuraava koodi.
eka_2.c, esimerkkikoodi
/**********************************************************
Project : eka_2.c
Hardware: PV-M32 + PV-LEDIT on PORTB
Software: WinAVR 20070525
Date : 03.07.2007
Author : pva
Comments: ensimmäiset opetuskoodit
**********************************************************/
#include <avr/io.h>
#include <util/delay.h>
// prototyyppi
void wait(uint16_t time);
int main(void)
{
DDRB = 0xFF; // B-portin suunta ulos
for(i=0;i<2000;i++)
_delay_loop_2(time);
}
2
unsigned char kuvio = 0x55; // kuvio bitteinä 0101 0101
Muuttuja, variable
Tietokone tekee monenlaisia asioita ohjelman ohjaamana; esim. se lukee lämpötila-
anturin arvoja, muuttaa (laskemalla) sen arvon Celsius-asteiksi, vertaa sitä ennalta
annettuun raja-arvoon ja jos arvo ylittää sen, kytkee transistorikytkimen kautta
tuulettimen moottorin pyörimään. Näiden tehtävien suorittamiseen mikro-ohjain
tarvitsee ohjelmakoodin lisäksi tietoa, dataa eli numeroita ja merkkejä.
Osa tiedosta on asetettu pysymään muuttumattomana ohjelman ajon ajan. Ne ovat
vakioita, esim. raja-arvo, josta tuuletin käynnistetään. Toiset tiedot muuttuvat ja niitä
on voitava muuttaa milloin tahansa ohjelman aikana. Luetaan vaikkapa lämpötilatieto
kerran minuutissa. Muutettavat tiedot tallennetaan muuttujiin.
Muuttujan
arvo muuttuu, tai saattaa muuttua, ohjelman ajon aikana.
Vakion
arvo ei muutu ohjelman aikana.
Muuttuja
on RAM-muistiin nimetty muistipaikka,
jonne voi tallentaa luvun tai merkin.
3
muuttujan_tyyppi muuttujan_nimi;
int x = 0;
char merkki = 0;
float lampo;
Muuttujan nimenä kannattaa käyttää jotain sen merkitystä tai tehtävää kuvaavaa
nimeä. Jos esim. muuttujaan tallennetaan virta-arvoja, kannattaa antaa muuttujalle
nimi virta. Vältä käyttämästä muuttujan nimenä pelkkää kirjainta.
Koska globaalin (yleisen) muuttujan nimen tulee olla erityisen kuvaava, (se näkyy
kaikille funktioille ja siten käytetään monessa paikassa) se voi toisinaan muodostua
kahdesta tai useammasta sanasta.
Käytä silloin sanojen välissä alaviivaa, esimerkiksi näin:
char ovi_kytkin;
int lampo_anturi;
Hyvin valittu nimi on kuin ylimääräinen kommenttirivi, se kertoo heti lukijalle mistä
on kysymys, mitä ko. ohjelmakohteessa tapahtuu.
Aina kun kirjoitetaan ohjelmakoodia tarvitaan muuttujia. Käännin tarkistaa joka kerta
muuttujan kohdatessaan, onko muuttuja esitelty. Täten säilyy oikea kirjoitusmuoto.
Jos näin ei tehtäisi, käännin loisi aina uuden muuttujan virheellisenkin nimen
yhteydessä. Tästä seuraisi ongelmia. Isoista ohjelmista ohjelmointivirheiden
etsiminen on tosi työlästä.
4
Huom!
Muuttujalle varataan tilaa SRAM-muistista, koska sen arvoa on voitava muuttaa
ohjelman kuluessa. SRAM-muisti on rakennettu kiikuista, joilla on sähkön
kytkemisen jälkeen satunnainen arvo, siis yksi tai nolla.
Kiikku voi olla ’kiikun tai kaakun’.
Muuttujan esittely varaa vain muistista tilaa, mutta ei ota kantaa muistin sisältöön.
Siksi muuttuja on alustettava, initialisoitava eli sille on annettava arvo.
Alustamattoman muuttujan käyttö on vaarallista, koska muistipaikka saattaa sisältää
mitä tahansa satunnaista dataa.
5
Pienissä mikro-ohjaimissa ei ole laitteistotukea liukuluvuille (laskentayksikköä, saati
matematiikkaprosessoria), joten laskenta on tehtävä ohjelmallisesti. Ongelmaksi tulee
silloin suuri muistintarve. Onneksi suurille liukuluvuille on harvoin tarvetta pienissä
sulautetuissa järjestelmissä.
Liukulukutyypin käytön etuna on se, että sillä voidaan esittää paljon suurempi määrä
lukuja, kuin kokonaislukutyypillä. Haittana taas se, että liukulukuoperaatiot ovat
paljon hitaampia kuin kokonaislukulaskenta ja pikku systeemeissä laskettaessa luvun
tarkkuus vähenee.
Kokonaisluvut ovat oletuksena etumerkillisiä, ne voivat olla siis joko positiivisia tai
negatiivisia. Yleisin tapa esittää negatiivinen numero on kahden komplementti, two's
complement.
Unsigned on etumerkitön, siis vain positiivisia lukuja sisältävä muuttujatyyppi. Käytä
unsigned-tyyppiä, aina jos suinkin voit. Negatiivisten lukujen käsittelyyn liittyy
etumerkin testaus ja siihen tarvitaan koodia ja muistitilaa ja siten myös aikaa.
Etumerkki varaa yhden bitin paikan rekisteristä, joten lukualue jää pienemmäksi.
(void merkitsee tyhjä, ilman tyyppiä)
6
Ei ole järkevää käyttää liukulukuja AVR:n yhteydessä, koska AVR-ytimessä
ei ole liukulukulaskentaa suorittavaa ”rautaa”.
Liukuluvut on käsiteltävä ohjelmallisesti ja se syö valtavasti resursseja.
Huom.
Muuttujien koot vaihtelevat kääntimittäin ja varsinkin sulautettujen järjestelmien C-
kääntimet eivät välttämättä sisällä kaikki niitä tietotyyppejä, mitä ANSI-normi
edellyttää.
Käytä näitä:
ANSI C99 määrittelee muuttujien koot, esim. int16_t, int8_t, uint8_t, jne.
Numeroarvo kertoo muuttujan koon, bittimäärän.
C99 tietotyyppejä kannattaa käyttää porttaamisen (koodin siirto toiseen käännin- tai
MCU-ympäristöön) helpottamiseksi.
Siis silloin, jos tietotyypin koolla on merkitystä ohjelman toimintaan.
esim.
typedef signed char int8_t;
se ja muut määritykset löytyvät stdint.h-headerista
ja polku on C:\WinAVR-20070525\avr\include
7
Muuttujan tyypin valinta
TIETOTYYPIT
Vinkki:
Miten kokonaislukumuuttujasta liukulukumuuttuja?
int i;
double d;
d = i;
parempi tapa: d = (double)i;
8
Käyttäjän itse määrittämät tyypit
C-kielessä koodaaja voi luoda omia tyyppejä. Se tehdään typedef-määreellä ja apuna
käytetään kirjaston standardityyppejä.
Formaatti on:
typedef standardi_tyyppi omatekema_tyyppi;
9
Talletusluokka Static
Talletusluokka Extern
10
Extern esimerkki
Kirjoita seuraava koodi ja käännä se normaalisti.
/**********************************************************
Project : extern_1.c
Hardware: PV-M32 + PV-LEDIT on PORTB
Software: WinAVR-20081221
Date : 05.01.2008
Author : pva
Comments: extern-määritys, demo
**********************************************************/
#include <avr/io.h>
#include <util/delay.h>
#include "apu.h"
// kerrotaan kääntimelle, että tämä tiedosto on käytettävissä
// prototyyppi
void wait(uint16_t time);
int main(void)
{
DDRB = 0xFF;
// extern unsigned char luku, luku_2;
// esittely, ei ole määrittely, vaan käsky etsiä muuttujaa muualta
while(1)
{
PORTB = 0x00;
wait(200);
PORTB = luku;
wait(200);
PORTB = 0x00;
PORTB = luku_2;
wait(200);
}
}
for(i=0;i<2000;i++)
_delay_loop_2(time);
}
Sitten, avaa New File = valkoinen tyhjä ”sheetti” ja kirjoita siihen seuraavat rivit:
uint8_t luku = 0x01;
uint8_t luku_2 = 0x80;
// määrittelyt, muistia on varattu muuttujia varten
11
Analysointi
1.) Käännä koodi ensin siten, että luku-muuttujat ovat esitelty ilman asetettua arvoa.
Ohjelma kääntyy (pari varoitusta) ja kun ajat sen, niin tulostus on ”mitä sattuu” =
LEDit ovat pimeitä, koska muuttujat ovat määrittämättömiä (0).
Tämä on vain ehdotus kääntimelle, sillä se saattaa tehdä sen itsekin. Käännin joko
huomioi ohjeen eli register-määreen, tai jättää sen huomiotta. Riippuu tilanteesta.
Sulautetuissa järjestelmissä on toisinaan tärkeää, että käännin ei käytä CPU:n
rekisteriä muuttujan tallentamiseen, vaan käyttää siihen SRAM-muistipaikkaa, mutta
siitä tarkemmin rekisteritason ohjelmoinnin yhteydessä.
Huomaa!
register-esittelyä voidaan käyttää vain automaattisiin
muuttujiin ja funktioiden muodollisiin parametreihin.
Huom!
Älä käytä register-määrittelyä c-koodin yhteydessä!!!
avr-gcc-käännin osaa itse käyttää yleisrekistereitä parhaiten.
Ainoastaan jos opiskelet assembly-koodin käyttöä, silloin voit itse
määrätä mitä yleisrekistereitä käytät.
12
Volatile
Jos sulautetun systeemin koodin toiminta muuttuu oudoksi kun kytket kääntimen
optimoinnin päälle tai otat keskeytyksen käyttöön, on syytä opetella tuntemaan
volatile.
Käyttö:
Muuttuja on määritettävä volatileksi, jos sen arvo voi muuttua koodista huolimatta.
- kun muuttujan arvo voi muuttua asynkronisesti, siis esim. kun globaalia
muuttujaa muokataan keskeytysfunktiossa ja jota arvoa testataan pääkoodissa
- samoin jos käytät muistiavaruudessa olevaa oheislaitteen rekisteriä jonka arvo
voi muuttua koodista huolimatta
- odotat loopissa jossa luetaan I/O-pinnin muuttumista
- tai luet timeria
- jos yleensä odotat, että jotain tapahtuu, kuten while(!jotain);
Syntaksi:
volatile int arvo;
int volatile arvo;
Ihan miten päin vaan. Tutki tarkemmin mallikoodia.
13
#include <avr/io.h>
#include <avr/interrupt.h>
int main(void)
{
DDRB = 0xFF;
TCCR1B |= 1<<CS11; // kellon jakoluku; clk/8, muuta tätä
TIMSK |= 1<<TOIE1; // T/C1 Overflow interrupt enable
sei(); // globaali keskeytysten sallinta
Muuttuja voi olla myös ns. yleinen eli globaali. Globaalit muuttujat määritetään
lähdekoodin alussa ennen funktioita, siis kaikkien funktioiden ulkopuolella. Huomaa,
myös main-funktion ulkopuolella. Siksi globaalit muuttujat ovat voimassa (näkyviä)
kaikkialla ohjelmassa. Siis käytettävissä koko koodin alueella.
Jos globaalin muuttujan arvoa muutetaan, niin sen uusi arvo on siitä lähtien voimassa
kaikissa ohjelman funktioissa. Ellet alusta globaalia muuttujaa, käännin tekee sen itse
ja asettaa arvoksi nollan.
Isoissa ohjelmissa globaalit muuttujat määritetään yhdessä erityisessä header-
tiedostossa ja esitellään siellä missä niitä käytetään määreellä extern.
extern int jannite;
Kun määre on extern, sillä kerrotaan kääntimelle, että muuttuja on määritetty jossain
muussa moduulissa.
14
Lisää ’fundeeraamista’!
Globaali muuttuja asetetaan datamuistiin pysyvästi. Se siis varaa muistia koko
ohjelman ajan. Tämä on tärkeää tietää, koska mikro-ohjaimissa on pieni SRAM-
muistitila.
Yleensä on syytä välttää globaalien muuttujien käyttöä.
Iso ongelma saattaa syntyä siitä, että muuttujan arvoa voidaan muuttaa monesta
paikkaa. Isoissa ohjelmissa ne saattavat aiheuttaa hyvinkin vaikeasti selvitettäviä
virheitä. Paha kauneusvirhe on se, että funktiot eivät tällöin enää ole itsenäisiä,
riippumattomia. Pienissä sovelluksissa, kuten meidän 8-bittisen mikro-ohjaimen
yhteydessä, pieni SRAM-muistitila rajoittaa globaalien muuttujien käyttöä. Siksi
kannattaa opetella heti alkuun oikea ohjelmointityyli ja välttää globaaleja. Jos se
suinkin on mahdollista.
Globaali muuttuja
- on voimassa koko ohjelman ajan ja siten se varaa
muistia kaikenaikaa
- sen arvoa voi mikä tahansa funktio muuttaa,
milloin tahansa.
Muuttujan ominaisuuksia
Elinikä
- aika minkä aikana muuttujan tilanvaraus on voimassa, eli muuttuja on
käytettävissä. Funktion (aliohjelma) sisällä määritelty muuttuja ”elää” vain sen
ajan kuin funktion käsittely kestää. Lohkojen ulkopuolella määritetty muuttuja
on globaali ja se on pysyvä (varaa muistia koko ohjelman ajan).
näkyvyys
- koodialue mistä muuttujaan voidaan viitata. Funktion sisällä määritetty
muuttuja näkyy vain ko. funktion sisällä. Se on paikallinen, lokaali.
- Funktioiden ulkopuolella määritetty muuttuja on käytettävissä kaikkialla, se
näkyy jokaiselle funktiolle. Se on globaali muuttuja.
- kukin funktio eli aliohjelma muodostaa oman näkyvyysalueensa. Kun
kutsutaan funktiota, hypätään tämän aliohjelman näkyvyysalueelle.
tallennuspaikka
- datasegmentti SRAM-muistissa
- pinomuisti (SRAM-muistissa)
- rekisteri
tyyppi
- C-kielessä valmiina primitiivisiä tyyppejä, kuten int, char, float
- joista voi rakentaa uusia tyyppejä, kuten taulukko, tietue
15
Määrite Tarkoitus
auto(matic) muuttujat ovat oletusarvoisesti tällaisia
määritys on voimassa vain siinä funktiossa missä se on määritelty,
se on siis paikallinen - local
const muuttujan arvo on vakio
register määrittelee muuttujan paikalliseksi ja määritys kehottaa käännintä
pitämään muuttujan rekisterissä.
Tämä on lähinnä isojen koneitten ominaisuus,
pienissä sulautetuissa järjestelmissä tätä ei tarvita, (rekisterien käyttö
on oletuksena). Älä käytä sulautetuissa.
extern muuttuja tai funktio on määritelty toisessa tiedostossa
static muuttuja on olemassa ohjelman suorituksen ajan
muuttuja alustetaan funktiossa kerran ja sen arvo säilyy vaikka
funktiosta välillä poistutaankin
käyttö: laskurit yms.
typedef tyyppimäärittely
volatile arvo voi muuttua ulkoisista syistä
Vakio, constant
Vakio on myös ohjelman käyttämä muistipaikka, mutta sen sisältöä ei voi muuttaa
ohjelman ajon aikana. Vakion sisältö on, kuten nimikin sanoo, muuttumaton,
staattinen. Se täytyy alustaa esittelyn yhteydessä.
16
1. Numeeriset vakiot
Numeerinen vakio on arvo, joka kirjoitetaan suoraan lähdekoodiin aina tarvittaessa.
Se voidaan tarpeen mukaan kirjoittaa eri muodossa. Kokonaislukuvakiot voidaan
kirjoittaa:
desimaaliluku, ilman etuliitettä esim. 1234
heksaluku, etuliite on 0x esim. 0xF0
oktaaliluku, etuliite on 0 esim. 0567
2. Merkkivakiot
Merkkivakio voi olla tulostettava (kuten aakkoset), tai ei-tulostettava (kuten rivin
vaihto new line, tabulaattori tab). Tulostettavat merkkivakiot kirjoitetaan
ympäröimällä merkki heittomerkeillä, esim. ’A’, joka on heksamuodossa 0x41. Ei-
tulostettavat merkkivakiot ovat ns. ohjausmerkkejä, kuten ’\n’, new line, ’\x0a’
heksalukuna, jolla siirretään kursori seuraavalle riville, tai tabulointimerkki ’\t’,
heksana ’\x09’.
3. Symboliset vakiot
on vakioita, joita ohjelmassa esittää nimi, symboli. Sitä ei voi ohjelman ajon aikana
muuttaa. Käytön etuna on koodin selkeys. Ne otetaan esikääntimen käsittelyyn
samoin kuin header-tiedostot, eli risuaitamerkillä #.
#define JANNITE 10
- esikäännin suorittaa yksinkertaisen tekstikorvauksen, aina kun se näkee sanan
JANNITE, se korvaa sen luvulla 10. Itse käännin ei näe koskaan JANNITE nimeä,
vaan ainoastaan arvon 10.
17
4. Varattu sana const
Varattu sana const on muunnin, jolla muuttuja määritellään const-tyyppiseksi
vakioksi, sitä ei voi enää sen jälkeen ohjelmassa muuttaa. Vakiolla on myös tyyppi ja
käännin tarkistaa, että sitä käytetään oikein.
Const
ei talleta oliota flash-muistiin vaan SRAMmiin. Se on oikeasti muuttuja jonka arvoa
ei voi ohjelmassa muuttaa. Se on eräänlainen suojamekanismi.
Const
on hyödyllinen määre funktioiden parametrien määrityksessä, se estää funktiota
muuttamasta arvoa.
vakio.c esimerkki
/**********************************************************
Project : vakio.c
HW: PV-M32 + PV-LEDIT
SW: WinAVR-20070525
Date : 02.12.2007
Author : pva
Comments: vakion käyttö-demo
**********************************************************/
#include <avr/io.h>
#include <util/delay.h>
#define VAKIO 0x81 // vakion määritys
for(i=0;i<2000;i++)
_delay_loop_2(time);
}
18
int main(void)
{
uint8_t kuvio;
const uint8_t LUKU = 3; // vakion määritys
Jos määritetään muuttuja pelkästään tyypiksi char kuvio, niin merkkitavun eniten
merkitsevä bitti, vasemmanpuoleisin, on tällöin ns. merkkibitti. Se kertoo, onko luku
positiivinen tai negatiivinen. Silloin varsinaista merkkiä varten jää vain 7 bittiä, siis
128 eri dataa, jotka voivat olla negatiivisia tai positiivisia.
Rivillä
const unsigned int LUKU = 3;
määritetään vakio LUKU ja sille arvoksi sijoitetaan 3.
19
Sitten luku-vakion arvo, joka on 3, kerrotaan luvulla 2 ja tulo sijoitetaan kuvio-
muuttujan uudeksi arvoksi. Välittömästi tämän jälkeen kuvio sijoitetaan B-porttiin.
VAKIOT
Arvoa ei voi muuttaa.
Kirjoitusasu määrittää vakioiden tyypin:
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.
Operaattorit, operators
Mikro-ohjaimessa tietoa voidaan käsitellä monella eri tavalla. Ensin data pitää
sijoittaa SRAM-muistiin muuttujan arvoksi ja siirtää sitten itse prosessorin tiedon
käsittely-yksikköön, akkuun, tms. rekisteriin. Se tehdään sijoitusoperaattorilla.
20
Sijoitusoperaattorit, Assignment Operators
Sijoitusoperaattorilla annetaan muuttujalle arvo. C-kielen sijoitusoperaattori on
matematiikan yhtäsuuruusmerkki (=)-merkki. C-kielen yhtäsuuruus on kaksi on-
merkkiä yhdessä eli ( ==).
Sijoitusoperaattorin formaatti:
tunniste = arvo;
HUOM!
Yllä oleva lauseke ei tarkoita sitä, että tunniste ja arvo olisivat yhtä suuria, vaan,
että arvo sijoitetaan tunniste-muuttujan arvoksi.
Sijoitusoperaattorin oikealla puolella oleva arvo, (rvalue, right value) sijoitetaan sen
vasemmalla puolella olevan muuttujan arvoksi (lvalue, left value).
21
Modulus- eli jakojäännösoperaattori.
Jakojäännös jää, kun kokonaisluku jaetaan toisella kokonaisluvulla.
Modulusoperaattori palauttaa kokonaislukujakolaskun jakojäännöksen.
22
Matemaattisten operaattoreiden käyttö
Harjoituksia
1. Anna muuttujille uusia, pieniä arvoja (jotta voit seurata koodia) ja totea
ohjelman eteneminen ja aritmeettisten operaattorien toiminta. Viive
suuremmaksi?
2. Lisää kaksi laskutoimitusta peräkkäin samalle käskyriville.
- esim. luku = luku + 3 – 2;
esim.
x<y on tosi, true, jos x on pienempi kuin y, muuten se on epätosi, false.
5<6 on tosi.
6>8 on epätosi.
23
Unaarioperaattori, Single Operand
C-kieleen kuuluu ns. unaarioperaattori, se operoi vain yhtä arvoa. Niitä ovat jo edellä
opittu tilde (invertoi bitit) ja tässä esiteltävät lisäys- ja vähennysoperaattorit.
Esim.
unsigned int i = 2;
i++; // tarkoittaa: i = i + 1; eli i saa arvon 2 + 1 eli on 3
toinen tapa esittää sama toiminto: i += 1;
i--; // tarkoittaa: i = i - 1; eli jos i on 3, niin nyt saa arvon 3-1 eli 2
toinen tapa esittää sama toiminto: i -= 1;
Etuoperaattori
Jos operaattori on ennen operandia, siis kuten ++i, puhutaan etuoperaattorista. Käsky
toimii niin, että ensin i-muuttujaan lisätään yksi ja vasta sitten sitä käytetään.
int a, b, x = 5;
a = ++x;
- ensin x inkrementoidaan eli x on yhtä kuin 5+1 eli 6 ja sitten tämä 6 sijoitetaan a:n
arvoksi.
toinen esimerkki:
kierrosluku = 2* ++i;
- ensin i = i + 1
- sitten i = i * 2
- ja sitten kierrosluku = i
24
Jälkioperaattori
Jos operaattori on operandin jälkeen, siis kuten i++, puhutaan jälkioperaattorista.
Käsky toimii niin, että ensin operandia käytetään ja sitten vasta kasvatetaan sitä.
int b = 5, x = 6;
b = x++;
- ensin arvo x sijoitetaan b:n arvoksi eli b on 6 ja sitten x inkrementoidaan eli x on 7.
toinen esimerkki:
kierrosluku = 2 * i++;
- ensin kierrosluku = 2 * i
- sitten i = i + 1
int main(void)
{
DDRB = 0xFF;
uint8_t luku = 0;
while (1)
{
luku++;
PORTB = luku;
wait(50);
}
}
Analyysi:
1. Mitä tapahtuu kun muuttuja saa arvon 0xFF?
25
Otetaan seuraavaksi siirto-operaattori, koska sillä saadaan edelliseen liittyviä
opettavaisia pikku harjoituksia. Ja toisaalta, ’pienuudestaan’ huolimatta, siirto-
operaattorit tekevät sulautetuissa järjestelmissä useasti hyvinkin tarpeellisia
toimintoja.
Bittikohtaiset siirto-operaattorit
Siirto-operaattorikäskyt siirtävät rekisterin bittejä vasemmalle tai oikealle, niin monta
askelta kuin ohjausnumero edellyttää. Jos esim. siirretään bittejä yhden askeleen
vasemmalle, niin äärimmäisenä vasemmalla oleva bitti 'putoaa roskakoriin' ja
oikeanpuolimaiseksi bitiksi nousee 'hatusta’ nolla.
x << 1;
Rekisterin bitit siirtyvät yhden askeleen vasemmalle.
x << 2;
Rekisterin bitit siirtyvät kahden askeleen verran vasemmalle.
x = x << 1;
Muuttujan x bitit siirtyvät yhden pykälän vasemmalle, oikeanpuolimaiseksi bitiksi
tulee 0.
Tämä on käytännössä sama kuin kertominen kahdella.
Huom!
siirto-operaatio ei muuta muuttujan arvoa, ellet käytä sijoitusoperaatiota
x = x >> 3;
26
Bittikohtainen siirto oikealle
x >> 1;
Rekisterin bitit siirtyvät yhden askeleen oikealle.
x >> 3;
Rekisterin bitit siirtyvät kolme askelta oikealle.
x = x >> 1;
Muuttujan x bitit siirtyvät yhden pykälän oikealle, vasemmanpuolimaiseksi bitiksi
tulee 0. Tämä on käytännössä sama kuin jakaminen kahdella.
int main(void)
{
DDRB = 0xFF;
uint8_t bitti = 0x80; // 1000 0000 bin
PORTB = bitti;
WAIT(1000);
while (1)
{
bitti = bitti >> 1; // siirretään bittejä 1 askel oikealle
// tulos asetetaan bitti-muuttujan uudeksi arvoksi
PORTB = bitti;
WAIT(300);
}
}
Analysointi
27
Operaattoreiden suoritusjärjestys
Operaattoreilla on evaluointijärjestys, precedence, joka määrää operaattoreiden
kutsujärjestyksen lausekkeessa.
Jos lausekkeessa on useita samanarvoisia operaattoreita, käytetään ns.
assosioituvuutta, associativity:
- yksioperandiset ja sijoitusoperaattorit evaluoidaan oikealta vasemmalle
- muut vasemmalta oikealle
- järjestystä voidaan muuttaa käyttämällä sulkeita
28
Sulautettujen systeemien operaattorit, yhteenveto
Sijoitus
= PORTB = 0x55;
käytetään lauseissa, joissa muuttujaan sijoitetaan lukuarvo taikka suoritetaan muu lauseke
Aritmetiikka
summa + Rtot = R1 + R1;
erotus - Rtot = R1 – R2;
tulo * Rtot = 2*R1;
osamäärä / Rtot = R1/2;
jakojäännös % taajuus_ero = f%50;
* operaatiota käytetään tavallisimmissa matemaattisissa lauseissa
Vertailu
yhtäsuuri ==
pienempi < if (jann < vert)
Lisäys ja vähennys
lisäys, inkrementointi ++ tavu++;
vähennys, dekrementointi -- teho--;
askeltaa yhdellä ylös- tai alaspäin esim. rekisterin sisältöä tai muuttujan sisältöä
Loogiset operaatiot
JA, AND &
TAI, OR |
ehdoton tai, XOR ^
invertointi ~
siirto vasemmalle <<
siirto oikealle >>
Esim. 8 bit tavujen , rekisterien tai muuttujien sisällön muokkaaminen tavallisilla digitaalitekniikan
operaatioilla. Näitä operaatioita käytetään sulautettujen järjestelmien ohjelmoinnissa.
Loogiset
JA-operaatio &&
TAI-operaatio ||
EI, NOT !
operaatioita käytetään yhdistämään vertailuoperaatioita. Älä sekoita näitä edellisiin operaattoreihin.
29
Varatut sanat
Varattuja sanoja C-kielessä on 32 kpl. Joku niistä määrää CPU:n tekemään jotain
erikoista, toisia yhdessä muiden kanssa kertomaan ohjelmalle mitä tehdä, joitakin et
tule käyttämään milloinkaan. Varatut sanat kirjoitetaan pienellä. Niitä ei saa käyttää
muuhun kuin varattuun tarkoitukseen. Vältä varattuja sanoja muistuttavia
muuttujanimiä.
30