Edellisessä osassa käytiin läpi taulukoita ja sitä aiemmin muuttujien käsittelyä erilaisin menetelmin on myös kahlattu lävitse. Bittejäkin on naksuteltu ledin vilkutuksen muodossa ja kytkimen lukua myös harjoitettu. Tässä vaiheessa mielestäni taitaa olla tämän oppaan kokonaisuuden kannalta järkevintä käydä lävitse hieman tarkemmin MSP430G2231 mikrokontrollerin rekistereitä ja niiden merkityksiä, vaikka näistä on ollut puhetta aiemminkin. Tämä sen vuoksi, että vaikka tarkoitus on oppia c-kieltä ja ohjelmoinnin perusteita, niin on aivan yhtä tärkeää tietää ja ymmärtää mikrokontrollerien maailmaa myös rekisterien osalta.
Rekisterit
Tämä kappale olisi hyvä ollut selvittää aluksi, ennen ensimmäistäkään ledin vilkuttelua, mutta koska opas on muodoltaan tehdään ensin ja mietitään sitten, niin käydään nämä asiat vasta nyt läpi.
Joten mennäänpäs rekistereihin. Rekisterit, mitä ne ovat ja mihin niitä käytetään? No... yleisesti voidaan sanoa, että rekisteri tallentaa jonkinlaisen tiedon tai pitää sisällään useampia tietoja. Esimerkiksi verovirastolla on tieto verovelvollisista ja väestörekisterissä on tieto, ketkä kaikki Suomen väestörekisteriin on rekisteröity. Rekisteristä voidaan poistaa tietoja ja sinne voidaan lisätä tietoja, toisin sanoen rekisterien arvoja voidaan muuttaa.
Mikrokontrollerien maailmassa asia ei siis ole tämän ihmeellisempi. Kuten varmaan huomasitkin, niin esimerkiksi aiemmin käyttämämme P1OUT on rekisteri. Kyseinen rekisteri pitää sisällään tiedon porttipinnien ulospäin näkyvistä tiloista, olettaen että kyseinen porttipinni on asetettu lähdöksi.
Mikrokontrollerien maailmassa ohjelmoijan ei itse tarvitse varsinaisesti rekisteröidä mikrokontrollerin rekistereihin mitään, sillä se on tehty valmiiksi valmistajan toimesta silloin kun piiriä on suunniteltu. Ainoa asia, minkä ohjelmoijan tarvitsee tietää on se, miten rekisteriä käytetään ja mitä tietoja voidaan muuttaa. Rekistereihin tehtyjen muutosten avulla mikrokontrolleri saadaan tekemään erilaisia asioita juuri kuten ohjelmoija haluaa.
MSP430 mikrokontrollereilla on olemassa kahdentyyppisiä rekistereitä: CPU rekisterit ja moduulirekisterit. Moduulirekistereillä ohjataan mikrokontrollerin eri laitteita (I2C/SPI/UART/ADC/DAC jne) ja porttipinnejä. CPU:n rekistereitä muokkaamalla voidaan vaikuttaa mikrokontrollerin toimintatilaan ja se voidaan asettaa esimerkiksi vähävirtaiseen 'sleep'-tilaan.
Seuraavassa käydään läpi muutama olennainen bittien naksutteluun liittyvä rekisteri, tai no itse asiassa kaikki ne rekisterit, jotka MSP430G2231 on syönyt porttipinnien osalta (eri MSP430 mikrokontrollereilla porttipinnien rekistereitä voi olla enemmän, mutta yleisimmät on tässä ja samat asiat pätee jokaiseen niistä). Samat tiedot löytyvät muuten MSP430x2xx mikrokontrollerien käyttöohjeesta, jonka voi ladata PDF-tiedostona Texas Instrumentsin sivuilta. Jos sinulla ei vielä ole kyseistä käyttöohjetta, kannattaa ladata ja tallentaa se NYT. Tarvitset sitä kun luet eteenpäin.
HUOM. Alla olevat kappaleiden numerot ja nimet ovat voineet käyttöohjeen päivityksen takia muuttua. Tässä ohjeessa käytetään manuaalia, jonka kansisivulla lukee pienellä präntillä "December 2004 - Revised April 2011". Todennäköisesti voit käyttää muutakin versiota dokumentista, kunhan dokumentin nimenä on MSP430x2xx Family User's Guide (SLAU144H).
Porttipinnien rekisterit ja käyttöohjeen lukeminen
Kun yllä oleva linkitetty manuaali on ladattu ja olet avannut sen, otetaan sieltä kappale 8, Digital I/O. Introduction kappaleessa (8.1) kerrotaankin mitä kaikkea mikrokontrollerin digitaalisella I/O:lla voidaan tehdä. Ei kuitenkaan suomenneta kaikkea tähän, vaan keskitytään suoraan rekistereihin, joten hypätään suoraan kappaleeseen 8.3, eli Digital I/O Registers. Kyseisen kappaleen alusta on otettu portin P1 tiedot alla olevaan taulukkoon.
Port | Register | Short Form | Address | Register Type | Initial State |
P1 | Input | P1IN | 020h | Read Only | - |
Output | P1OUT | 021h | Read/Write | Unchanged | |
Direction | P1DIR | 022h | Read/Write | Reset with PUC | |
Interrupt Flag | P1IFG | 023h | Read/Write | Reset with PUC | |
Interrupt Edge Select | P1IES | 024h | Read/Write | Unchanged | |
Interrupt Enable | P1IE | 025h | Read/Write | Reset with PUC | |
Port Select | P1SEL | 026h | Read/Write | Reset with PUC | |
Port Select 2 | P1SEL2 | 041h | Read/Write | Reset with PUC | |
Resistor Enable | P1REN | 027h | Read/Write | Reset with PUC |
Yllä olevasta taulukosta nähdään paljon olennaista tietoa portin P1 rekistereistä. Lyhyesti läpikäytynä taulukosta löytyy portin P1 jokaiselle toiminnolle oma rekisteri alkuarvoineen ja osoitteineen. Launchpadin ohjelmoijan kannalta (ja noin yleensäkin) osoitteista (Address) ei tarvitse välittää, sillä kääntäjä tietää kyllä osoitteet kun rekistereitä käsitellään. Ainoat asiat jotka ohjelmoijan tulee ymmärtää on rekisterien toiminta ja niiden käyttö - ja rekistereitä olemme jo käyttäneetkin.
Jos et ole vielä tähän mennessä hoksannut, kuinka voidaan tietää mikä mikrokontrollerin pinni vastaa mitäkin porttia, niin vastaus tulee tässä: mikrokontrollerin datalehdestä! Kun datalehdestä etsii vaikkapa sanaa 'pinout' niin pitäisi löytyä tietoa siitä, mitä portteja mikrokontrollerilla on käytössä. Alla oleva kuva on otettu Launchpadillä kiinni olevan MSP430G2231 mikrokontrollerin datasivulta, mistä käytettävissä olevat nastat ovat näkyvissä.
Mutta takaisin rekistereihin. Alla käydään läpi kunkin rekisterin ominaisuudet ja käyttötarkoitus sekä lyhyet esimerkit.
PxIN
Tämä rekisteri voidaan vain lukea. Ja kuten arvata saattaa, niin tämän rekisterin avulla voidaan tutkia missä tilassa mikrokontrollerin portit ovat. Jos haluat tutkia vain yhden porttipinnin tilaa (esimerkiksi Launchpadin kytkimen S2, P1.3), voit lukea sen kuten edelläkin on tehty, eli näin:
Ja kuten jälleen huomasit, niin x-kirjaimen tilalle laitetaan sen portin numero, jota halutaan tutkia. Helppoa eikö? Mutta, entäpä jos haluttaisiin lukea napin painallus muuttujaan? No se kävisi vaikkapa näin:
{
painettu = 1;
}
PxOUT
PxOUT-rekisterin avulla määritetään porttipinnin lähtötila. Launchpadissä porttipinniin P1.0 on kytketty punainen LED1 ja porttipinniin P1.6 vihreä LED2. Niiden päälle laittaminen (samoin kuin minkä muun logiikka-ohjauksen päälle laittaminen) tapahtuisi siis näin:
P1OUT = BIT0 + BIT6; // laitetaan päälle vain LED1 ja LED2 ja
// sammutetaan muut lähdöt
P1OUT = 0xFF; // laitetaan päälle kaikki
P1OUT &= ~(BIT0 + BIT6); // sammutetaan vain LED1 ja LED2
P1OUT = 0x00; // sammutetaan kaikki
Yllä onkin jo muutama eri vaihtoehto erilaisten ohjausten tekemiseksi. Kyseiset rivit ja kommentit lienevät itsensä selittäviä.
PxOUT-rekisterin merkitys kuitenkin muuttuu, jos pinneihin kytketään ohjelmallisesti sisäiset ylös- tai alasvetovastukset (PxREN-rekisteri). Tässä tapauksessa vastukset kytketään päälle ja pois seuraavasti:
P1OUT &= ~BIT0; // P1.0 vastus on alasvetovastus (maa)
Pelkästään ylläolevat koodirivit eivät siis kytke vastuksia päälle, vaan niiden kytkemiseksi tarvitaan vielä muokata PxREN-rekisterin arvoja kyseisen BITx:n kohdalta.
PxDIR
Porttipinnien määrittelyssä olennainen rekisteri on myös PxDIR eli suuntarekisteri. Tällä rekisterillä määritetään onko portti tulo vai lähtö, eli input vai output. Lähtö ja tulo voidaan asettaa seuraavasti:
P1DIR &= ~BIT1; // P1.1 on tulo (input)
P1DIR |= 0x02; // P1.2 on lähtö (output)
Lähtö tai tulo voidaan määrittää vaikka kesken ohjelman suorituksen, mutta jos porttipinniä käyttää jokin mikrokontrollerin lisälaite (peripheral), niin sen asetukset "voittavat" nämä rekisteriasetukset yleensä. Tavallisia I/O-pinnejä voidaan kuitenkin konfiguroida milloin halutaan.
PxIFG
Jokainen MSP430G2231 mikrokontrollerin porttipinni (P1/P2) on niin sanotusti keskeyttävä. Tämä tarkoittaa sitä, että jos porttipinnin tilassa tapahtuu muutos, niin keskeytyskäsittelijä voi hoitaa kyseisen tilanteen. PxIFG-rekisteri kertoo sen, missä porttipinnissä keskeytys sattui. Tällöin voidaan sanoa, että keskeytyslippu on "päällä". Alla on esimerkki kuinka esimerkiksi Launchpadin kytkimen painalluksen keskeytys voitaisiin tutkia:
Mikäli PxIFG-rekisterin jokin bitti on asettunut "1"-tilaan, on porttipinnissä tapahtunut keskeytys eli lippu asettunut. Keskeytyksiä ei kuitenkaan tutkita yllä olevalla tavalla (yleensä) vaan niitä varten on erilliset keskeytyskäsittelijät. Keskeytyksistä kuitenkin tarkemmin lisää seuraavissa kappaleissa.
PxIES
Olennaisesti keskeytyksiin liittyvä asia on se, tapahtuuko keskeytys signaalimuutoksen nousevalla vai laskevalla reunalla. Nouseva reuna tapahtuu luonnollisesti silloin, kun jännitetaso keskeyttävässä pinnissä nousee. Laskevassa reunassa asia on luonnollisesti päinvastoin. Alla on esimerkki kuinka reunaherkkyys asetetaan Launchpadin kytkimelle S2:
P1IES &= ~BIT3; // P1.3 (kytkin) keskeytys tapahtuu nousevalla reunalla ___/¨¨¨¨
Keskeytyksistä lisää seuraavissa kappaleissa.
PxIE
PxIE-rekisterillä määrätään se, huomioidaanko porttipinnin BITx:ssä tapahtuvaa keskeytystä vai ei. Mikäli keskeytyspinniä vastaava PxIE:n rekisteribitti ei ole "1"-tilassa eli sallitussa tilassa, niin keskeytystä ei tapahdu eikä mikrokontrolleri näin ollen sitä huomioi. Tämä on helppo unohtaa varsinkin alussa. Alla olevassa esimerkissä sallitaan Launchpadin kytkimen S2 keskeytys:
P1IE &= ~BIT3; // P1.3 (kytkin) keskeytys kielletty
PxSEL ja PxSEL2
Mikrokontrollereiden porttipinnit ovat usein monikäyttöisiä. Eli niitä voidaan käyttää joko perus-I/O:na tai sitten jonkin lisälaitteen pinninä. PxSEL ja PxSEL2 -rekistereillä määritetään mihin mikrokontrollerin ominaisuuteen porttipinni kytkeytyy sisäisesti. PxSEL -rekistereiden asetus ei kuitenkaan aina välttämättä ohjaa pinniä toimimaan juuri oikealla tavalla, vaan esimerkiksi UART-moduulin (sarjaportti) konfigurointi voi pakottaa porttipinnin "omakseen". Näistäkin tulee tarkemmin lisää tietoa myöhemmin.
PxREN
Viimeisenä muttei vähäisimpänä on vielä PxREN-rekisteri, jolla kuten aiemmin mainittiin, voidaan määrittää käytetäänkö porttipinnissä ylös- tai alasvetovastusta. Alla esimerkki ohjelmallisesta alas- ja ylösvetovastuksesta.
P1REN |= BIT0; // aktivoidaan vastus
P1OUT &= ~BIT0; // asetetaan vastus alasvetovastukseksi
// YLÖSVETOVASTUS P1.0 (LED1, pun.)
P1REN |= BIT0; // aktivoidaan vastus
P1OUT |= BIT0; // asetetaan vastus ylösvetovastukseksi
Ylösvetovastuksen toimimisen voit testata Launchpadilla. Sen huomaa siitä, että kun ylösvetovastus on LED1:lle aktivoitu, niin punainen LED loistaa himmeästi.
Huom! Launchpadin kytkimellä S2 ei ole ylösvetovastusta ulkoisesti (siksi että linjaan voidaan kytkeä mitä halutaan ilman häiriöitä) vaan ylösveto täytyy tällekin napille ohjelmoida sisäisesti käyttöön.
Seuraavassa osassa jatketaan Launchpadin kanssa ohjelmoimista ja tutustutaan mikrokontrollerin keskeytyksiin. Myös yllä mainittujen rekistereiden käyttöä on luvassa lisää.