Vajalikud teadmised:
[HW] Kasutajaliidese moodul,
[AVR] Digitaalsed sisendid-väljundid,
[LIB] Sisend-väljundviigud,
[PRT] Valgusdiood
Lüliti on elektromehhaaniline seade elektriahela kokku- ja lahtiühendamiseks. Lüliteid on erinevaid, kuid tüüpiline mehhaaniline lüliti koosneb klemmidest, mida saab omavahel mehhaaniliselt ühendada. Klemmide ühenduse korral on elektriahel suletud ja lülitit võib läbida elektrivool. Kui klemmid on lahti, on elektriahel avatud ja elektrivool lülitit läbida ei saa.
Lülititega saab otseselt elektriahelaid pingestada, kuid neid saab kasutada ka anduritena. Lüliti anduri funktsioonis on ka selle harjutuse teema, seepärast on vaatluse alt välja jäetud spetsiifilised kõrgepinge ja suure voolu lülitid. Lülitid erinevad ka kontaktide arvu ja nende ühendamise meetodilt. On olemas kahe kontaktiga lüliteid, kuid ka duubellüliteid, kus ühendatakse kontaktide paarid. On surunupp-, klahv-, liug- ja pöiallüliteid (inglise keeles thumbler) ning lüliteid, mis vajutades ei ühenda, vaid katkestavad elektriahela.
Erinevat liiki lülititel on erinev skemaatiline tähis. Järgnevalt on toodud tüüpilisemad elektroonikaskeemides kasutatavad lülitid ja nende elektrilised tähised:
Lüliti kasutamiseks andurina mikrokontrolleri juures ühendatakse lüliti üks kontakt mikrokontrolleri viiguga, mis määratakse programmis sisendiks. Kui toimub kontakti ühendamine maa- või toitepotentsiaaliga, muutub ka mikrokontrolleri viigule vastava siini biti väärtus. Loogiline variant on kasutada pöiallülitit, mis võimaldab üht kontakti ühendada valitud kontaktiga (antud juhul siis maa või toitega), kuid see pole päris nii lihtne. Põhjus on selles, et ümberlülitamise hetkel ei ole kontaktid omavahel ühenduses. See hetk on väga lühike (millisekundites), kuid sellesama hetke jooksul pole mikrokontrolleri sisendviik kuhugi ühendatud ja sel on määramata väärtus. Elektromagnetiliste häirete tõttu (mida leidub kõikjal) võib mitte kuhugi ühendatud sisendviik täiesti suvalistel ajahetkedel omada 0 või 1 väärtust.
Häired teevadki lülitite kasutamise keerukamaks. Üks peamine meetod määramata olekute vältimiseks on mikrokontrolleri sisend ühendada läbi takisti kas maa- või toitepotentsiaaliga. Sellises funktsioonis olevat takistit nimetatakse inglise keeles kas pull-down või pull-up takistiks. Tavaliselt ulatub pull-up või pull-down takistite takistus mõnest kilo-oomist ühe mega-oomini. Kui lüliti on avatud, jääb sisendile, millele on ühendatud takisti, pinge, kui lüliti sulgeda, rakendub sisendile lüliti pinge, sest lüliti takistus on palju väiksem (nullilähedane) kui takisti oma. Sisuliselt on tegu pingejaguriga.
Pull-up või pull-down takistiga võib andurina kasutada ka lihtsat kahekontaktilist lülitit, nii et lüliti ühendab sisendi ühe potentsiaaliga ja takisti teisega. Tavaliselt on mikrokontrolleritel ka sisseehitatud pull-up või pull-down takisti kasutamise võimalus, mistõttu ei pea skeemi eraldi takistit lisamagi. Näiteks AVR mikrokontrollerites on IO viikudel 20 kuni 50 kilo-oomised pull-up takistid.
Olgu öeldud, et mehhaaniliste lülititega kaasneb siiski veel üks probleem – kontaktide põrkumine. Kuna kontaktid on tehtud metallist, millel on teatav elastsus, siis kontaktide ühendamise või lahti-ühendamise hetkel need põrkuvad ning tulemusena tekib hulga väärlülitusi. Lülituste arv ja kestus sõltub lülitist, kuid enamasti jääb see mõne millisekundi piiresse. Kui lülitit kasutatakse mõne elektriseadme käivitamiseks, siis pole see suur probleem, kuid kui lüliti on kasutusel seadme juhtimiseks, võib mitmekordne lülitumine probleemiks olla.
// Kodulabori Kasutajaliidese mooduli nupu testimise näidisprogramm #include <homelab/pin.h> // Põhiprogramm int main(void) { // LED-i viigu väljundiks ja nupu viigu sisendiks seadmine pin_setup_output(led_green); pin_setup_input(S1); // Lõputu tsükkel while (1) { // Nupule S1 vastab roheline LED, // mis süttib nupu alla vajutades if(pin_get_value(S1) == 1) { pin_set(led_green); } else { pin_clear(led_green); } } }
Põhiline kontaktide põrkumisest tekkinud väärlülitusi välistav meetod on filtreerimine. Filtreerida saab nii elektriliselt kui ka tarkvaraliselt. Elektriliseks filtreerimiseks tuleb lüliti ühendada läbi madalpääsu filtri – näiteks RC filter - mis silub pingemuutusi ja sellest tulenevalt ei omanda mikrokontrolleri viik hetkelisi väärtusi. Tarkvaraline filtreerimine toimub põhimõttel, et viigu, kuhu lüliti on ühendatud, väärtust loetakse mitmel korral ja kui kõikidel kordadel on viigu väärtus sama, siis sellest järeldatakse, et lüliti omab kindlat asendit ning tegu pole põrkumisega. Igasugusel filtreerimisel peab aga arvestama viitega, mis tekib oleku määratlemisel.
Tarkvaraliseks filtreerimiseks on mitmeid meetodeid. Seda võib teha lihtsalt ja keeruliselt, mõlemal variandil on oma eelised ja puudused. Kui programm on selline, et nupuvajutusi oodatakse harva, võib pärast nupu allavajutamise registreerimist lisada pika pausi, mis välistab reageerimise põrkumisest tekkinud lisalülitustele. Samas tuleb sellise lahenduse puhul arvestada, et kui kasutaja hoiab nuppu pikalt all, reageerib programm ka nupu lahtilaskmisel tekkinud väärlülitustele.
Töökindlam on programm, mis kontrollib nupu olekut teatud aja jooksul mitu korda (mida rohkem ja mida pikema aja jooksul, seda kindlam).
Kodulabori Kasutajaliidese mooduli plaadil on kolm surunupp-lülitit. Lülitid ühendavad mikrokontrolleri viike maaga, kuid mitte otse, vaid läbi takisti – seda põhjusel, et juhuslikul mikrokontrolleri viikude väljundiks määramisel neid nupuvajutusel ei lühistataks. Lülititel on ka pull-up takistid, kuid need on palju suurema takistusega kui kaitsetakistid, nii et nupu allavajutamisel jääb vastavale mikrokontrolleri viigule ikkagi 0 V lähedane pinge.
Lülitite asukohad on toodud riistvarakirjelduses. Lülitite oleku lugemiseks tuleb mikrokontrolleri vastavad viigud määrata sisendiks. AVR siseseid pull-up takisteid ei pea tööle rakendama, sest, nagu öeldud, viikudel juba on välised takistid. Kui nupp alla vajutada, on viigule vastaval siinil biti väärtus 0, kui nupp lahti lasta, siis väärtus 1. Selleks et näha, kas mikrokontroller sai nupuvajutusest aru, võib kasutada plaadil olevaid LED indikaatoreid.
Järgnevalt on toodud Kasutajaliidese mooduli nupu filtreeritud väärtuse lugemise funktsioon:
// Funktsioon lüliti filtreeritud väärtuse lugemiseks unsigned char button_read(pin button) { unsigned char buffer = 0xAA; unsigned char timeout = 100; // Ootame, kuni nupu olek on selgunud või oleku selgitamine aegunud while (timeout-- > 0) { // 8-kohalise (bitise) olekupuhvri pidamine // Kõik eelmised olekud (bitid) nihutatakse vasakule // ja paremale lisatakse uus olek (bitt) buffer <<= 1; buffer |= (pin_get_value(pin) ? 0x01 : 0x00); // Kui kõik 8 bitti on madalad, siis // nupp on kindlasti üleval if (buffer == 0xFF) { return 0; } // Kui kõik 8 bitti on kõrged, siis // nupp on kindlasti alla vajutatud if (buffer == 0x00) { return 1; } // Paus 1 millisekund _delay_ms(1); } // Kui olekut ei õnnestunud välja selgitada, siis oletame, // et nuppu ei vajutatud return 0; }
See funktsioon kasutab viite tekitamise funktsiooni, millest räägib lähemalt vastav harjutusülesanne. Siinkohal pole viite funktsiooni kohta vaja suurt midagi teada peale selle, et see tekitab 1-millisekundilise viite iga nupu oleku lugemise tsükli lõpus. Kui nupp on kaheksa lugemise korral samas asendis, tagastab see loetud asendi. Kogu protseduur võib nupu ebastabiilsuse korral kesta kuni 100 ms. Funktsioon sisaldub juba viikude teegis, nii et näite läbimiseks ei pea seda oma programmi lisama.
Järgnev näide illustreerib nuppude kasutamist ja mitmekordse loenduse elimineerimist kasutades tühja tsüklit, mille korral oodatakse nuppu vabastamist.
// Kodulabori nuppude kontaktide põrkumise filtreerimise näidisprogramm #include <homelab/pin.h> // Põhiprogramm int main(void) { int counter = 0; // LED-ide viikude väljundiks seadmine pin_setup_output(led_red); pin_setup_output(led_yellow); pin_setup_output(led_green); // Nupu viigu sisendiks seadmine pin_setup_input(S1); // Lõputu tsükkel while (1) { // Nupu alla vajutamise kontroll if(button_read(S1)) { // Loenduri väärtusele vastava LED-i süütamine if(counter == 0) led_on(led_green); else led_off(led_green); if(counter == 1) led_on(led_yellow); else led_off(led_yellow); if(counter == 2) led_on(led_red); else led_off(led_red); // Loenduri suurendamine ja mooduli 3 võtmine counter = (counter + 1) % 3; // Nupu vabastamise ootamine tühjas tsüklis while(button_read(S1) != 0); } } }
Kui nüüd programmi proovida, siis LED-id süttivad täpselt sellises järjekorras nagu kasutaja nupplülitit vajutab. Nuppude kasutamise näidiskood põhineb Kodulabori viikude teegil, mida on tutvustatud valgusdioodi näites.
Tabelis on näha teegis kirjeldatud nuppude konstandid ja vastavad Kontrollermooduli viigud.
Konstandi nimi | Kodulabor I & II viik | Kodulabor III viik | Kirjeldus |
---|---|---|---|
S0 | PC2 | PQ2 | Kontrollermoodulil olev testnupp |
S1 | PC0 | PH2 | Kasutajaliidese moodulil olev alumine nupp |
S2 | PC1 | PH1 | Kasutajaliidese\ moodulil\ olev\ keskmine\ nupp |
S3 | PC2 | PH0 | Kasutajaliidese moodulil olev ülemine nupp |
// Kodulabori nuppude testimise näidisprogramm #include <homelab/pin.h> // Põhiprogramm int main(void) { // LED-ide viikude väljundiks seadmine pin_setup_output(led_red); pin_setup_output(led_yellow); pin_setup_output(led_green); // Nuppude viikude sisendiks seadmine pin_setup_input(S1); pin_setup_input(S2); pin_setup_input(S3); // Lõputu tsükkel while (1) { // Igale nupule vastab üks LED, // mis süttib nupu alla vajutades if(button_read(S1)) led_on(led_green); else led_off(led_green); if(button_read(S2)) led_on(led_yellow); else led_off(led_yellow); if(button_read(S3)) led_on(led_red); else led_off(led_red); } }