Input / Output¶
Osaamistavoitteet: I/O-pinnien käyttäminen ohjelmallisesti eri tarkoituksiin sulautetussa laitteessa.
Input / Output, eli tuttavallisesti I/O ja suomeksi "siirräntä" (huoh..), tarkoittaa tiedon siirtämistä tietokoneen komponenttien välillä. Inputit ovat komponentin vastaanottamia signaaleja tai dataa ja outputit komponenttien lähettämiä signaaleja tai dataa. Input-signaali voi olla esim. näppäimen painallus tai viesti oheislaitteelta. Output taas vastaavasti on viesti oheislaitteelle, esimerkiksi ohjauskomennon lähettäminen laitteelle.
Sulautettuun laitteeseen (piirikortille) on usein integroituna useita erilaisia komponentteja ja oheispiirejä mm. I/O:ta tai käyttöliittymää varten Alla listattuna tyypillisimpiä, joista osaa tulemme käyttämään kurssilla.
- Painonappeja, liukukytkin, kosketusnäyttö (ts. laitteen "näppäimistö")
- LEDejä
- LCD-Näyttö
- Analogia-digitaalimuunnin (AD-muunnin, ADC)
- Ajastinpiiri (engl. Timer)
- Sarjaliikennepiirejä, kuten UART, SPI ja I2C
- USB- ja/tai Ethernet-ohjainpiiri
- PWM-piiri (Pulssinleveysmodulaatio, engl. Pulse Width Modulation)
Usein oheiskomponentit ovat analogisia, joiden antamat jännitearvot voivat olla mitä vain maatason ja käyttöjännitteen väliltä. Esimerkiksi, monet anturit ilmaisevat mittausarvonsa analogisena jännitteenä minimi- ja maksimijännitteen välillä. Tietokoneelle analogiset signaalit, kuten jännite, on ensin muunnettava digitaaliksi eli numeroarvoksi. Tätä varten mikrokontrollereissa on valmiiksi integroituna analogi-digitaalimuuntimia, jotka tuottavat analogisesti jännitteestä pyöristettyä numeroarvoa sovitussa tarkkuudessa. Koodissa otamme sitten numeroarvon talteen ohjelmamme muuttujiin ja voimme käsittellä sitä.
Nyt SensorTag:ssa anturit ovat pääasiassa digitaalisia (tästä lisää myöhemmin), mutta analogisia komponentteja ovat esimerkiksi LED:it, joiden kirkkautta voimme säätää PWM:n avulla.
Pinni¶
Okei, kerrataanpa ihan perusteita aluksi. Pinni (engl. pin) tarkoittaa komponentin fyysistä jalkaa tai liittimen piikkiä. Pinnien tarkoitus on komponentin sähköinen ja mekaaninen liittäminen piirilevylle. Piirin jokaisella pinnillä on tietty käyttötarkoitus, tosin joskus yhdellä pinnillä on useitakin eri käyttötarkoituksia. Pinnijärjestys kuvaa mikä tai mitkä ovat pinnien käyttötarkoitukset.
Alla esimerkin vuoksi Intel 4004:n (maailman ensimmäinen kaupallinen mikroprosessori vuodelta 1971) pinnijärjestys.
Alla kuvaus armaan SensorTag:n mikrokontrollerin (TI CC2560) pinneistä. Pinneille annetaan niiden toimintaan liittyvä looginen nimi, esimerkiksi DIO_16, joka on yleiskäyttöinen digitaalinen I/O-pinni (engl. General Purpose I/O, GPIO), jonka käyttötarkoituksen voi ohjelmoija vapaasti määritellä.
Alla SensorTagin I/O-pinneille annettuja vakioita (ioc.h-otsikkotiedosto). Pinnin loogista nimeä käytämme usein koodissa suoraan vakiona, jonka kääntäjät kirjastot valmiiksi on määritellyt. Nyt omassa koodissa voimme käyttää vakiota
IOID_17
osoittamaan laitteen fyysiseen pinniin DIO_17, jne. Kätevää!#define IOID_15 0x0000000F // IO Id 15
#define IOID_16 0x00000010 // IO Id 16
#define IOID_17 0x00000011 // IO Id 17
#define IOID_18 0x00000012 // IO Id 18
#define IOID_19 0x00000013 // IO Id 19
#define IOID_20 0x00000014 // IO Id 20
Pinnit ja bitit¶
Yleinen periaate on, että ohjelmakoodissa jokaista mikrokontrollerin pinniä vastaa yksi bitti. Tässä meillä nyt realisoituu siis aiemmin oppimamme bittioperaatiot.
- Asettamalla tämä bitti joko loogiseen nollaan tai ykköseen, fyysisen pinnin jännitetaso muuttuu ja näin ohjelmallisesti ohjataan pinniä ja siihen kytkettyä oheispiiriä.
- Vastaavasti lukiessa fyysisen pinnin tilaa, luetaan sen jännite ja sitä vastaava bitti asettuu vastaavaan loogiseen arvoon.
Loogista ykköstä (engl. High) yleensä vastaa käyttöjännite (tyypillisesti 3.3V tai 5V) tai jännite sovituissa rajoissa (2.0-2.7V suuremmat arvot tulkiseen ykköseksi).
Loogista nollaa (engl. Low) vastaa maataso (0V, tai yleensä 0.7V pienempi jännite).
Laitteen ohjaus- ja dataväylä¶
Kuten kurssin alkuosassa ounasteltiin, kun komponenttien ja oheislaitteiden fyysiset pinnit kytkentään piirilevyllä mikrokontrollerin I/O pinneihin, muodostetaan oheislaitteelle ikäänkuin sen oma ohjausväylä. Erona tässä on työasemaan mm. se, ettei sulautetun laitteen kaikki oheislaitteet suinkaan ole samassa ohjausväylässä, vaikka jotkin väylätoteutukset sen sallivat, vaan usein ryhmittelemme I/O-pinnit niiden käyttötarkoituksen mukaan oheislaitekohtaisesti.
- Voimme koodistamme ohjata oheislaitetta käsittelemällä vastaavia bittejä. Toiseen suuntaan, osana ohjausväylää voi myös olla keskeytyspinni, jonka lähettämä keskeytyssignaali sitten tulkitaan joko mikrokontrollerissa tai ohjelmassamme. Keskeytys siis kertoo ohjelmallemme, että oheislaitteella on asiaa.
- Vastaavasti dataväyläksi valitaan joukko I/O-pinnejä, jotka kytketään oheislaitteen datapinneihin ja näihin saadaan sille välitettyä dataa.. yllätysyllätys binäärilukuina.
Joissain mikrokontrollereissa (esim. ATmelin MCU:n perustuvat Arduinot) I/O-laitteiden kytkemiseen varatut pinnit on rytmitelty I/O-porteiksi, esimerkiksi 8 pinniä tulkitaan loogisesti yhdeksi portiksi. Tämä on kätevää, jos laite tarvitsee useita I/O-linjoja, niin niitä voidaan käsitellä loogisesti yhtenä yksikkönä. SensorTag käsittelee kuitenkin kaikkia I/O-pinnejä yksittäin, ellei ohjelmoija ole itse määritellyt portit haluamilleen pinneille.
Nyt, meidän suureksi helpostukseksi, RTOS:n kirjastot tarjoavat meille valmiita funktiokutsuja asettaa bittejä päälle / pois päältä, kts koodiesimerkit alla. Jos sitten tarkastelemme näiden funktiokutsujen koodia, sieltä konepellin alta löytyvät kyllä tutut bittioperaatiot.. ei niistä eroon pääse, uskokaa pois.
Rekisterit ja muistiinkuvattu I/O¶
Sen lisäksi, että kommunikoimme oheislaitteen kanssa I/O-pinnien kautta, voimme myös kommunikoida käyttäen mikrokontrollerin keskusmuistia. Kun oheislaitteissa kuvataan sen toiminnallisuus ohjelmille sen omien laitekohtaisten muistipaikkojen eli rekistereiden avulla, puhutaan muistiinkuvatusta I/O:sta. Tällöin, käsittelemällä ohjelmakoodissa näitä varattuja muistipaikkoja ihan sen tavallisen muuttujan tavoin, voidaan oheislaitteelle lähettää tai vastaanottaa tietoa. Laitteiden käsikirjat kertovat nämä (suunnitteluvaiheessa) määritellyt muistipaikkojen osoitteet ja (yleensä) niitä vastaavat valmiit vakiot.
(Toinen mahdollisuus olisi porttikuvattu I/O, jossa rekistereitä käsitellään erillisten in- ja out-käskyjen avulla. Mutta, tätä ei SensorTag käytä.)
Rekistereitä on kolmea tyyppiä: osoite-, ohjaus- ja datarekisterit. Oheislaite voi tarjota useita rekistereitä, mikä vain kombinaatio näistä kolmesta tyypistä laitteen toteutuksesta riippuen on mahdollinen. Ohjausrekisterin bittejä käytetään laitteen toiminnan ohjaamiseen, vaikkapa taustavalon asettamiseksi päälle LCD-näytössä. Datarekistereihin syötetään laitteelle menevä tieto, esim. LCD-näytölle tuleva teksti merkki kerrallaan. Jos samaa datarekisteriä käytetään sekä datan kirjoittamiseen ja lukemiseen, kontrollirekisterin pinni määrittää tiedonsiirron suunnan.
Jokaisesta (oheislaitteen) rekisteristä meidän täytyy siis tietää
- Yleinen tarkoitus ja toiminta
- Yksittäisten bittien tarkoitus ja toiminta
- Muistiosoitteet, joissa rekisterit ovat ja tarjoaako kääntäjäympäristö näitä vastaavat vakiot
Esimerkkinä SensorTag:n yksi rekisterikuvaus. Tämä datarekisteri pitää sisällään laitteen patterin jännitetason. Varsin hyödyllinen rekisteri siis!
Kuvasta nähdään, että rekisterin koko on 32 bittiä (
31-0
, kuvassa keltainen kenttä). Huomataan, että bitit 31-11
ovat varattuja laitteen sisäiseen käyttöön, mutta muissa biteissä on meitä kiinnostavaa tietoa. Bitit 10-8
pitävät sisällään patterijännitteen kokonaisosan ja bitit 7-0
patterijännitteen desimaaliosan koodattuna tietyllä tavalla. Nyt jos haluaisimme tietää patterin jännitteen, kysyisimme asiaa tältä datarekisterilta ja tekisimme sen arvolle muunnoksen vaikkapa liukuluvuksi. RTOS tarjoaa suoraan rekisterin arvon lukemiseenja asettamiseen
HWREG
-makron.// Lukuoperaatio: rekisterin arvo muuttujaan patteri
uint32_t patteri = HWREG(...); // Argumentiksi osoite vakion kautta
Datakirja¶
Komponentin tai mikrokontrollerien manuaali, eli datakirja, selittää yksityiskohtaisen pilkuntarkasti kaiken sen sisäisen sekä jokaisen integroidun piirin toiminnan. Datakirja on tyypillisesti englanninkielinen, vahvasti ammattisanastoon perustuva ja satoja ellei tuhansia sivuja pitkä, joten ei ole tarkoituksenmukaista opetella sitä ulkoa. Käytetään datakirjaa referenssinä laitteistoa suunniteltaessa ja ohjelmoitaessa. Monimutkaisilla laitteilla voi olla datakirjojen lisäksi manuaaleja, esimerkiksi SensorTag Technical Reference Manual. Tässä käsikirjassa on 1742 sivua!
Onneksi, sen sijaan että kahlaisimme läpi satoja sivuja datakirjoja, kehitysympäristöihin löytyy valmiiksi kirjastoja, funktioita, makroja ja vakioita, joissa on toteutettu valmiiksi oheislaitteen ohjausta korkeamman tason toimintoja varten. Tässä jos jossain EI kannata keksiä pyörää uudelleen.
I/O-pinnien käyttö¶
Seuraavaksi perehdymme I/O-pinnien käyttämiseen SensorTagissa koodiesimerkin avulla. Käytössä olevat SensorTag-spesifiset vakiot löytyvät kätevästi ohjelmistoprojektiimme automaattisesti ilmestyvästä otsikkotiedostoista Board.h ja CC2650STK.h.
Allaoleva esimerkkimme, kaikessa kauneudessaan käyttää toista SensorTagin kahdesta painonappia on/off-kytkimenä yhdelle laitteen ledeistä. Eli meidän täytyy tässä määritellä kaksi pinniä ohjelman käyttöön: painonappia vastaava pinni ja lediä vastaava pinni.
Käytämme valmista kääntäjäympäristön tarjoamaa
Pin
-kirjastoa. Koska SensorTag:ssa tietyt I/O-pinnit ovat valmiiksi kytkettynä painonappeihin ja ledeihin, saamme niiden määritykset mukaan koodiin otsikkotiedostolla PINCC26XX.h
. Painonapin käyttöönottamiseksi ohjelmassa täytyy tehdä neljä asiaa- Esitellä RTOS:n muuttujat joilla painonappia käsitellään
- Alla buttonHandle, buttonState ja taulukko buttonConfig[]
- Alustaa napin asetukset halutusti
- Alla taulukkoon buttonConfig[]
- Laatia napinpainalluksen käsittelijäfunktio
- Alla keskeytysrutiin buttonFxn
- main-funktiossa ottaa nappeja vastaavat I/O-pinnit käyttöön ohjelmassa
Hox! SensorTagissa on kaksi painonappia ja kaksi lediä. Nämä määrittelyt tulee tehdä jokaiselle pinnille erikseen. Eli jos haluamme kaikki käyttöön, kirjoitamme koodiin neljä esittelyä ja käyttöönottoa.
Tämä esimerkkiohjelma siis, joka kerta kun nappia painetaan, suorittaa funktion
buttonFxn
, jossa lediä vastaavan pinnin tila vaihtuu, joka siis ohjaa laitteen lediä päälle / pois päältä. Esimerkki on purettu osiin alla. #include <ti/drivers/PIN.h>
#include <ti/drivers/pin/PINCC26XX.h>
...
// Vaihe 1. RTOS:n muuttujat pinnien käyttöön
static PIN_Handle buttonHandle;
static PIN_State buttonState;
static PIN_Handle ledHandle;
static PIN_State ledState;
// Vaihe 2. Pinnien määrittelyt, molemmille pinneille oma konfiguraatio
// Painonappi
PIN_Config buttonConfig[] = {
Board_BUTTON0 | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_NEGEDGE, // Hox! TAI-operaatio
PIN_TERMINATE // Määritys lopetetaan aina tähän vakioon
};
// Ledipinni
PIN_Config ledConfig[] = {
Board_LED0 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
PIN_TERMINATE // Määritys lopetetaan aina tähän vakioon
};
// Vaihe 3. Napinpainalluksen keskeytyksen käsittelijäfunktio
void buttonFxn(PIN_Handle handle, PIN_Id pinId) {
// Vaihdetaan led-pinnin tilaa negaatiolla
PIN_setOutputValue( ledHandle, Board_LED0, !PIN_getOutputValue( Board_LED0 ) );
}
int main(void) {
Board_initGeneral();
// Vaihe 4. Otetaan pinnit käyttöön ohjelmassa
buttonHandle = PIN_open(&buttonState, buttonConfig);
if(!buttonHandle) {
System_abort("Error initializing button pins\n");
}
ledHandle = PIN_open(&ledState, ledConfig);
if(!ledHandle) {
System_abort("Error initializing LED pins\n");
}
// Asetetaan painonappi-pinnille keskeytyksen käsittellijä
// funktiossa buttonFxn yllä
if (PIN_registerIntCb(buttonHandle, &buttonFxn) != 0) {
System_abort("Error registering button callback function");
}
BIOS_start();
return (0);
}
Puretaanpas ohjelmaesimerkki osiin.
1. RTOS:n muuttujat pinnien käyttöön¶
Ensin esittelemme joukon muuttujia per käyttämämme pinni, joita RTOS tarvitsee. Jälleen tarvitaan kahvat pinnille, joka esitellään muuttujalla
Pin_Handle
. Toinen RTOS:n tarvitseman muuttuja on pinnin tila, joka esitellään muuttujalla Pin_State
. Tosin näitä muuttujia emme omassa koodissa tarvitse, mutta pidetään näillä RTOS tyytyväisenä. Lisäksi, jokaista käyttämäämme pinniä kohden tarvitaan sen määrittelyt, jonka ohjelmoija itse asettaa ja jota varten esitellään
Pin_Config
-tyyppinen taulukko.// Vaihe 1. RTOS:n muuttujat pinnien käyttöön
static PIN_Handle buttonHandle;
static PIN_State buttonState;
static PIN_Handle ledHandle;
static PIN_State ledState;
PIN_Config buttonConfig[] = {
Board_BUTTON0 | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_NEGEDGE, // Hox! TAI-operaatio
PIN_TERMINATE // Määritys lopetetaan aina tähän vakioon
};
PIN_Config ledConfig[] = {
Board_LED0 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
PIN_TERMINATE // Määritys lopetetaan aina tähän vakioon
};
Tässä koodissa esitellään nyt siis kaksi pinniä ohjelmaamme, nimeltään
button
ja led
. Kumpaankin pinniä varten tarvitsemme yo. kolme muuttujaa, eli button-pinnille buttonHandle
, buttonState
ja taulukko buttonConfig
. Yllä esimerkissä on myös määritelty samat muuttujat led-pinnille. Vaihe 2. Pinnien alustus¶
Seuraavaksi alustamme jokaisen pinnin joko sisääntuloksi (input) tai ulostuloksi (output) sen omaan määrittelytaulukkoon. Kaikki tässä käytetyt vakiot ja niiden tarkoitukset löytyvät Pin-kirjaston dokumentaatiosta, mutta ao. määrityksillä pärjäämme kurssilla.
PIN_Config buttonConfig[] = {
Board_BUTTON0 | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_NEGEDGE, // Pinnin asetus TAI-operaatiolla
PIN_TERMINATE // Tämä vakio lopettaa määrittelyn
};
PIN_Config ledConfig[] = {
Board_LED0 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
PIN_TERMINATE
};
Asettaminen tapahtuu C-kielen
TAI-operaatiolla |
, jossa alustamme kaikki haluamamme asetusbitit kerralla, esimerkissä meillä on neljä asetusbittiä: Board_BUTTON0 | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_NEGEDGE
. Ensimmäinen asetusbitti on itseasiassa SensorTagin painonappia vastaava id, eli joko
Board_BUTTON0
tai Board_BUTTON1
. Sensortagin kahdelle ledille on myös omat vakiot Board_LED0
ja Board_LED1
. Toinen asetusbitti on pinnin käyttötarkoitus, eli käsitelläänkö sitä sisääntulona (engl. input) vai ulostulona (engl. output) ohjelmassamme. Input-pinnistä luemme sen tilan (esimerkiksi nappia painettu / ei painettu) ja output-pinnille asetamme sen tilan (esimerkiksi ledi päälle / pois). Sisääntuloksi pinni asetetaan vakiolla
PIN_INPUT_EN
ja ulostuloksi vakiolla PIN_GPIO_OUTPUT_EN
. Kaiken tämän selityksen luettuamme asetamme siis esimerkissä painonapin sisääntuloksi ja ledi-pinnin ulostulo. Kolmas asetusbitti kertoo mihin tilaan alustamme pinnin. Vakiolla
PIN_GPIO_LOW
pinnin jännite asetetaan alas maatasoon (0V, GND), joten ledi ei ole päällä. Vakiolla PIN_GPIO_HIGH
asetettaisiin pinnin jännite käyttöjännitteeseen (3.3V, VCC) eli tässä ledi päälle. Lisäksi, RTOS:ssa voisimme määritellä muitakin pinnin sähköiseen tomintaan liittyviä asetusparametreja, mutta niitä emme kurssilla tarvitse. Huomataan sitten vielä button-pinnin määrittelyssä vakio
PIN_IRQ_NEGEDGE
, jolla asetamme pinnin tuottamaan ohjelmassa keskeytyksen aina kun sen tila muuttuu laskevalla reunalla. Ts. kun nappi painetaan alas. Vastaavasti kun painonappi vapautetaan, siitä seuraava keskeytys saataisiin kiinni vakiolla PIN_IRQ_POSEDGE
, mutta sitä harvemmin tarvitaan. Pinnikeskeytyksistä lisää alla.. Määrittelytaulukko loppuu aina vakioon
PIN_TERMINATE
. Vaihe 3. Pinnin käsittelijäfunktio¶
Sisääntuloksi merkityille pinneille tarvitsemme (yleensä) käsittelijäfunktion, eli siis sen toiminnallisuuden mikä suoritetaan kun nappia painetaan alas. Tätä varten ohjelmassamme on käsittelijäfunktio
buttonFxn
. void buttonFxn(PIN_Handle handle, PIN_Id pinId) {
// Vaihdetaan led-pinnin tilaa negaatiolla
PIN_setOutputValue( ledHandle, Board_LED0, !PIN_getOutputValue( Board_LED0 ) );
}
Funktio toimii seuraavasti. Ensin luemme ledi-pinnin tilan (päällä "1" / pois päältä "0") lukufunktiolla
PIN_getOutputValue
. Tämä on yleinen funktio tarvitsee argumentiksi pinniä vastaavan vakion Board_LED0
. Arvolle tehdään negaatio, huomaa operaattori !
, ts. jos pinni oli tilassa "0" käännetään se tilaan "1", tai päinvastoin. Mutta, pinnin uuden tilan asetus tapahtuu asetusfunktiolla PIN_setOutputValue
, joka ottaa siis kolme parametria: pinnin kahvan, sitä vastaavan vakion sekä (tässä) negaatiolla käännetyn tilan. Voimme itseasiassa asettaa saman käsittelijäfunktion useille pinneille, edellyttäen että ne on määritelty samassa Pin_config-rakenteessa. Tällöin meidän täytyy käsittelijäfunktion argumentista
pinId
selvittää kumpi painonappi onkaan kyseessä. Parempi tapa on tehdä eri pinneille omat käsittelijät.void buttonFxn(PIN_Handle handle, PIN_Id pinId) {
if(pinId == Board_BUTTON0) {
tee_jotain1();
} else if(pinId == Board_BUTTON1) {
tee_jotain2();
}
}
Vaihe 4. Pinnit mukaan ohjelmaan¶
Seuraavaksi menemme
main
-funktioon. Pinnit varataan ohjelmamme käyttöön Pin_open
-funktiolla, jonka parametreiksi tulee äsken esittelemämme RTOS:n pinnimuuttujat ja määritykset. Sitten huomataan, ettei ohjelmassamme ei olekaan taskia mitä suorittaa! Tästä emme vielä ole puhuneet, mutta RTOS käsittelee taskit ja keskeytyksien käsittelijäfunktiot toisiaan vastaavasti, eli ohjelmassa voi olla molempia toteuttamassa toiminnallisuutta. Keskeytyksistä lisää myöhemmin, mutta nyt siis korvaamme taskin painonappiin liitettävällä keskeytyksellä joka laukaisee käsittelijäfunktion.
Tämä toteutus saadaan
PIN_registerIntCb
-funktiolla, jossa siis määritellään pinnille, käyttäen sen kahvaa, keskeytyksen käsittelijäfunktio, tässä siis painonapille yo. buttonFxn
. // Molemmat pinnit käyttöön ohjelmassa
ledHandle = PIN_open( &ledState, ledConfig );
if(!ledHandle) {
System_abort("Error initializing LED pin\n");
}
buttonHandle = PIN_open(&buttonState, buttonConfig);
if(!buttonHandle) {
System_abort("Error initializing button pin\n");
}
// Asetetaan toiselle pinnille keskeytyksen käsittellijä
// Keskeytys siis tulee kun nappia painetaan!
if (PIN_registerIntCb(buttonHandle, &buttonFxn) != 0) {
System_abort("Error registering button callback function");
}
Hox! Olisimme tietenkin voineet toteuttaa saman toiminnallisuuden ohjelmaan laatimalla taskin, joka ikuisessa toistorakenteessa kyselisi painonapin pinnin tilaa ja vastaavasti muuttaisi led-pinnin tilaa. Mutta tämän ratkaisun haittana on jatkuva pinnin tilan kysely, joka vie MCU:n suoritusaikaa ja varaa muistia omiin tilamuuttujiin koodissa. Nyt keskeytyksen käsittelijärutiini suoritetaan automaattisesti vain tarvittaessa, kun fyysisen pinnin tila vaihtuu. Aikaa ja vaivaa säästävä keino.
Lopuksi¶
Tässä kappaleessa kerrottiin lyhyesti yleisestä mikrokontrollerien I/O:sta oheislaitteiden kanssa toimimiseen. Tulevissa kappaleissa palaamme uudelleen monimutkaisempiin I/O-ratkaisuihin.
Pinnien määritys voi tuntua aluksi monimutkaiselta, ja tässäkin on paljon SensorTagin kirjastojen omaa koodia. Mutta eipä tässä tarvitse kuin muistaa nämä neljä vaihetta.
Materiaalin perusteella osaat jo tehdä sulautetun ohjelman, joka vilkuttaa laitteen lediä ja reagoida käyttäjän napin painallukseen! Olisko kakkukahvien paikka?
Anna palautetta
Kommentteja materiaalista?