0,00 €

V košarici ni izdelkov.

0,00 €

V košarici ni izdelkov.

More
    DomovRevijaProgramiranjeGeekcreit UNO R3 starter kit (6) - infrardeča in radijska komunikacija

    Geekcreit UNO R3 starter kit (6) – infrardeča in radijska komunikacija

    Avtorja: Vladimir Mitrović in Robert Sedak
    Poleg ostalih komponent se v Geekcreit kompletu nahajajo tudi daljinski krmilnik in visokofrekvenčni krmilnik ter sprejemnik.
    V tem članku bomo pokazali, kako z njihovo pomočjo lahko pošljemo ali sprejmemo smiselno sporočilo.
    Daljinski krmilnik
    Slika 37 prikazuje daljinski krmilnik iz Geekcreit kompleta. Kot tudi večina drugih daljincev ta pošilja informacijo o pritisnjeni tipki s pomočjo infrardeče (infra-red, IR) svetleče diode, v kompletu se nahaja tudi ustrezen sprejemnik. Preden postavimo programsko nalogo in pristopimo njenemu reševanju, moramo reči nekaj o principu, na katerem bazirajo infrardeči daljinski krmilniki!
    Čeprav je nevidna človeškemu očesu, je infrardeča svetloba del elektromagnetnega spektra blizu nam vidni svetlobi in se obnaša po istih fizikalnih zakonih, kar pomeni tudi širjenje v ravni črti. Ker infrardeča dioda daljinskega krmilnika oddaja svetlobo v snopu širine nekaj deset stopinj, se bo najboljša komunikacija ustvarila takrat, ko daljinski krmilnik usmerimo proti sprejemniku, posebej če se nahajamo na večji oddaljenosti: samo tako bomo zagotovili, da dovoljšnja količina svetlobne energije doseže do sprejemnika, da bi lahko dešifriral informacijo, ki mu jo pošiljamo.

    Zelo je pomembno, da je signal iz daljinskega krmilnika dovolj močen, ker razen sprejema informacije iz daljinskega krmilnika je sprejemnik izpostavljen tudi vplivu raznih motenj, kot je dnevna svetloba, umetna razsvetljava ali elektromagnetnih signalov drugega izvora. Intenzivnost teh motenj je velikokrat večkratno večja od koristnega signala, ki mu ga je poslal daljinski krmilnik. Da bi se zmanjšal njihov vpliv, proizvajalec vgrajuje sprejemnike v ohišje, ki prepušča samo infrardečo svetlobo, pogosto pa jih tudi oklopi s kovinskim oklopom. Prav takšno je tudi integrirano vezje TL1838 (ali VS1838B) iz našega kompleta, prikazan na sliki 39 zgoraj levo.

    Vendar niti to ni dovolj, da bi se z zanesljivostjo mogla razločiti koristna informacija od motnje! Ta koristna informacija je sestavljena iz svetlobnih bliskov določenega trajanja in bliski niso konstantni, ampak so sestavljeni iz impulzov frekvence 38 kHz. Elektronsko vezje znotraj sprejemnika bo med vsemi infrardečimi blisku, ki jih sprejme, izločil samo tiste s frekvenco 38 kHz in tako razločil koristno informacijo od motnje. Na izhodnem priključku se bodo pojavili samo impulzi s pripadajočimi pavzami, na osnovi katerih nato mikrokontroler lahko ugotovi, ali je sprejeta logična ničla ali enica.

    Obstaja več vrst protokolov, po katerih se informacija pošilja in vsi so v principu podobni. Podrobneje bomo razdelali samo NEC protokol, ki ga uporablja tudi daljinski krmilnik iz Geekcreit kompleta (slika 38).
    Po NEC protokolu se logična ničla pošilja kot svetlobni blisk v trajanju 562,5 µs, po katerem sledi enako dolga pavza. Logična enica se pošlje na isti način, vendar je pri njej trajanje pavze trikrat daljše. Struktura kompletnega sporočila je prikazana na sliki 38 spodaj. Ko pritisnemo neko tipko, bo daljinski krmilnik najprej poslal niz impulzov frekvence 38 kHz v trajanju 9 ms, sledila bo tišina trajanja 4,5 ms, in šele nato sledi pošiljanje informacije o pritisnjeni tipki. Pošlje se skupno 16 bitov, 8-bitni naslov in 8-bitni podatek. Naslov karakterizira daljinski krmilnik, ki pošlje sporočilo, podatek pa vsebuje informacijo o pritisnjeni tipki. Na osnovi sprejetega naslova, bo sprejemnik ugotovil, ali gre za “njegov” daljinski krmilnik ali ne, oziroma, ali je potrebno sprejeti prejeto sporočilo ali ne.
    Naslov in podatek se pošiljata dvakrat: enkrat v originalnem in enkrat v komplementarnem zapisu. To navidezno nepotrebno ponavljanje ima smisel: če primerjamo originalen in komplementirani zapis lahko mikrokontroler ugotovi, ali je sprejeta informacija korektna ali pa je poškodovana med prenosom in jo je zato potrebno zavreči. Druga korist je to, da bo kompletno sporočilo vedno vsebovalo 16 ničel in 16 enic, zato bodo vsa sporočila enako dolga. Po poslanem sporočilu sledi pavza dokler ne pritisnemo neke nove tipke. Izjemoma kadar držimo neko tipko pritisnjeno dalj časa, bo daljinski krmilnik v določenem ritmu pošiljal sporočilo “tipka je še vedno pritisnjena”, dokler je ne spustimo. Programerju za vse to ni potrebno skrbeti – Arduino ima knjižnico za NEC protokol, ki jo je potrebno samo vključiti v program in brati prejeta sporočila!
    Delo z daljinskim krmilnikom iz Geekcreit kompleta bomo prikazali s pomočjo vezja, katerega shema je prikazana na sliki 39. Izhod integriranega senzorja TL1838 je digitalen in ga lahko vežemo na kateri koli priključek Arduino Uno ploščice. V shemi je povezan na A0 samo zato, ker je tako shema izpadla preglednejše – v tem primeru, A0 ne bomo uporabili kot analogni, pač pa kot digitalni vhod 14! Komponente bomo zložili na veliko testno ploščico po risbi na sliki 40. LCD smo postavili kot v predhodnih primerih; paziti moramo samo na to, kako obrniti senzor IC1.
    11. programska naloga
    Napišite program za vezje na slikah 39 in 40, ki bo sprejemalo sporočila iz daljinskega krmilnika in jih prikazovala na LCD-ju po skici na sliki 39 zgoraj desno. V zgornji vrstici je potrebno izpisati vsebino prejetega sporočila v heksadecimalnem zapisu, v spodnji vrstici pa, katera tipka je pritisnjena na daljinskem krmilniku. Sporočilo je potrebno zbrisati po izteku 2 sekund ali pa ga takoj zamenjati z novim sporočilom, če je vmes bila pritisnjena neka druga tipka. Če je neka tipka bila pritisnjena dalj časa, je sporočilo potrebno zadržati dokler je tipka pritisnjena.
    Arduino rešitev (program Geekcreit_11.ino)
    Za delo z infrardečim daljinskim krmilnikom moramo uporabiti knjižnico funkcije, ki bo prepoznala krmilnikov protokol. Ena od knjižnic je IRremote avtorja Armina Jaochimsmeyera. Trenutna verzija je 4.1.2 in prepoznava več kot 10 protokolov za sprejem in pošiljanje ukazov preko infrardeče svetleče diode. V programu bomo pazili, da se na alfanumeričnem displeju izpisuje samo sprememba, in da se brisanje sporočil izvrši samo enkrat.

    Na začetku programa definiramo uporabo knjižnic IRremote in LiquidCrystal. Prav tako bomo definirali naslednje globalne spremenljivke:

    • IRRECV_PIN – vsebuje priključek na katerega je vezan IR sprejemnik,
    • printTime – vsebuje trenutno trajanje izpisa na LCD-ju,
    • timeThreshold – vsebuje maksimalen čas izpisa; po njegovem izteku je sporočilo potrebno zbrisati,
    • toClearLCD – s pomočjo nje signaliziramo, če ke potrebno zbrisati prikaz na LCD-ju (0 onemogoča, 1 omogoča brisanje),
    • lastDecodedRawData – vsebuje predhodno dekodirano sporočilo, da bi lahko ugotovili, ali je pritisnjena nova tipka.
    Po definicije spremenljivk, definiramo objekt z imenom lcd in sočasno jim pridružimo komunikacijske priključke:
    #include <IRremote.hpp>
    #include <LiquidCrystal.h>
    const int IRRECV_PIN = A0;
    unsigned long printTime = 0;
    unsigned long timeThreshold = 2000; // 2 seconds
    bool toClearLCD = 0;
    IRRawDataType lastDecodedRawData = 0;
    LiquidCrystal lcd(2, 3, 4, 5, 6, 7);
    V funkciji setup() definiramo vrsto alfanumeričnega displeja, ki ga uporabljamo in inicijaliziramo objekt IrReceiver:
    void setup(){
    lcd.begin(16, 2);
    IrReceiver.begin(IRRECV_PIN, DISABLE_LED_FEEDBACK);
    }
    Parametri funkcije lcd.begin(16,2) ustrezajo displeju z 2 vrstama in s 16 znaki v vsaki vrsti. Izpis se avtomatsko prične od prvega mesta v zgornji vrstici. Parametri funkcije IrReceiver.begin() definirajo, da je IR sprejemnik vezan na priključek, katerega številka je vpisana v spremenljivko IRRECV_PIN in onemogoča pošiljanje povratne informacije daljinskemu krmilniku.
    V funkciji loop() preverjamo, ali je IR sprejemnik sprejel podatek. Ko ga sprejme, vsebino sprejetega sporočila shranimo v lokalno spremenljivko decodedRawData vrste IRRawDataType:
    void loop(){
    if (IrReceiver.decode()) {
    IRRawDataType decodedRawData = IrReceiver.
    decodedIRData.decodedRawData;
    Če je tipka na daljinskem krmilniku pritisnjena dalj časa, je vrednost dekodiranega sporočila enaka nič (0). Ali se ponavlja isto sporočilo, je odvisno od verzije protokola. Obdelovali bomo samo sporočila z vrednostmi večjimi od ničle in so različna od predhodnega sporočila. Da bi lahko napraviti primerjavo, bomo morali vsako sprejeto sporočilo shraniti v spremenljivko lastDecodedRawData.

    Sporočilo izpisujemo v prvi vrsti LCD-ja, v drugi vrsti izpisujemo kateri tipki to sporočilo ustreza:

    if (decodedRawData > 0 && lastDecodedRawData != decodedRawData) {
    lastDecodedRawData = decodedRawData;
    lcd.setCursor(0, 0);
    lcd.print(“Koda: 0x”);
    lcd.print(decodedRawData, HEX);
    lcd.setCursor(0, 1);
    lcd.print(“Gumb: “);
    lcd.setCursor(6,1);
    To bomo ugotovili s pomočjo switch-case ukaza s primerjanjem vrednosti v spremenljivki decodedRawData s poznanimi kodami vsake posamezne tipke. V kolikor vrednost dekodiranega podatka nie na spisku, se bo izpisalo se samo sprejeto sporočilo (heksadecimalni kodi), ampak ne tudi ime tipke:
    switch (decodedRawData) {
    case 0xF30CFF00:
    lcd.print(“1”);
    break;
    case 0xE718FF00:
    lcd.print(“2”);
    break;
    case 0xA15EFF00:
    lcd.print(“3”);
    break;
    default:
    lcd.print(“”);
    }
    }
    Daljinski krmilnik ima 21 tipk, mi smo v tem programu prepoznali samo prve tri, da bi skrajšali ponavljajoči del programa. Po istem principu boste lahko dodelali program in mu dodali tudi ostale tipke, ko ugotovite njihove kode.
    Po izpisa sporočila shranimo trenutni čas v spremenljivko printTime, in omogočamo sprejem naslednjega podatka preko infrardečega sprejemnika in brisanje vsebine na alfanumeričnem displeju:
    printTime = millis();
    IrReceiver.resume();
    toClearLCD = 1;
    }
    Če je podatek na alfanumeričnem displeju prikazan dalj od časa definiranega v spremenljivki timeThreshold (2 sekundi), in če je omogočeno brisanje vsebine, brišemo vsebino LCD-ja in onemogočamo ponovno brisanje:
    if ((millis() – printTime >= timeThreshold) && toClearLCD) {
    lcd.clear();
    toClearLCD = 0;
    lastDecodedRawData = 0;
    }
    }
    Opazili boste, da je heksadecimalna vrednost zadnjih dveh bajtov v sprejetih sporočilih vedno FF00 – to je naslov, specifičen za daljinski krmilnik iz Geekcreit kompleta. Prva dva bajta sta pri pritisnjeni tipki. Program, ki smo ga analizirali, je lahko nadgraditi da bi namesto izpisa sporočila na LCD-ju, povzročil  neko “pravo” aktivnost: vklopil ali izklopil LED-ico, proizvedel zvočni signal, zagnal motor… V tem primeru bi morali zmanjšati vrednost timeThreshold konstante, da bi reakcija programa na nov ukaz bila hitrejša. Edino kar ni možno napraviti je pošiljanje povratne informacije: komunikacija je enosmerna!
    Radio komunikacija
    V Geekcreit kompletu se nahajata dva visokofrekvenčna modula: radijski krmilnik in radijski sprejemnik (slika 41). Oddajnik vsebuje oscilator frekvence 433 MHz, ki se vklaplja in izklaplja z digitalnim signalom na DATA priključku:
    če DATA = 1, oscilator dela,
    če DATA = 0, oscilator ne dela.
    Takšna vrsta modulacije se imenuje Amplitude Shift Keying (ASK): z dovajanjem niza binarnih ničel in enic na DATA vhod moduliramo visokofrekvenčni signal, ki jih oddajnik proizvaja in oddaja preko svoje antene v okolico.
    Sprejemnik je sestavljen iz visokofrekvenčnega dela, ki iz signalov, ki jih je sprejela antena, izloča in obdeluje samo tiste frekvence 433 MHz, in dekoderja, na katerem DATA izhodu dobimo niz impulzov v skladu s tem, kar je sprejemnik sprejel. Z drugimi besedami, logična enica na DATA vhodu oddajnika bo rezultiralo v logični enici na DATA izhodu sprejemnika, ničla bo rezultirala z ničlo. Kvaliteto sprejema lahko včasih poboljšamo z uglaševanjem “rumene” tuljave. Pri tem si je dobro zapomniti v katerem začetnem položaju je bila zareza v jedru, ker je sprejemnik morda že bil optimalno nastavljen na frekvenco oddajnika – pri poceni modulih tega nikoli ne moremo vedeti zagotovo.
    Radio komunikacijo bomo preizkusili s pomočjo shem na slikah 42 in 44. Slika 42 prikazuje oddajni del, v katerem poleg oddajnika VF1 uporabljamo tudi  potenciometer P1. Komponente bomo zložili na malo testno ploščico po risbi na sliki 43. Ob postavljanju oddajnika bodite pozorni, kako ga obrnete: okroglo kovinsko ohišje visokofrekvenčnega oscilatorja mora biti obrnjeno “proti spodaj”. Kot anteno bomo uporabili kos bakrene žice dolžine približno 20 cm.
    Slika 44 prikazuje shemo sprejemnega vezja, v katerem poleg samega sprejemnika VF2, uporabljamo še tudi LCD za prikaz sprejetih podatkov. Komponente bomo zložili na veliko testno ploščico po risbi na sliki 45. Ob postavljanju sprejemnika bodite pozorni, kako ga obrniti: stran s tuljavo za nastavljanje sprejemne frekvence in ostalimi “izbočenimi” komponentami je potrebno obrniti “proti zgoraj”. Kot tudi do sedaj, s potenciometrom P1 nastavljamo optimalni kontrast na LCD-ju. Tudi tukaj bomo kot anteno uporabili kos bakrene žice dolžine približno 20 cm; na manjših oddaljenostih, in ob dobro nastavljenem sprejemniku, antene morda sploh ne bodo potrebne.
    Tukaj moramo poudariti, da za preverjanje radijske komunikacije potrebujemo dve Arduino Uno ploščici: Arduino Uno s slik 42 in 44 niso isti moduli! Ker smo potenciometer P1 iz Geekcreit kompleta že uporabili v vezju na slikah 42 in 43, v sprejemnem vezju na slikah 44 in 45 ga bomo nadomestili po navodilih iz petega članka (SE323)!
    12. programska naloga
    Napišite program za vezja na slikah 42 in 43, ki bodo brala napetost na drsniku potenciometra P1 in odčitano vrednost v razponu od 0-1023 pošljite preko radijske komunikacije s pomočjo oddajnika VF1.
    Napišite program za vezja na slikah 44 in 45, ki bodo brala informacije iz DATA izhoda sprejemnika VF2 in jih prikažite v obliki vidni na sliki 44.
    Arduino rešitev (program oddajnika, Geekcreit_12a.ino)
    Za radijsko komunikacijo bomo uporabiti knjižnico RadioHead, ki jo lahko prevzameti s strani:
    http://www.airspayce.com/mikem/arduino/RadioHead/RadioHead-1.121.zip
    Instaliranje knjižnice iz zip datoteke se izvaja s pomočjo izbire “Sketch->Include library ->Add .ZIP libarary…”; ko se odpre novo okno, v njemu izberete zip datoteko s knjižnico.
    Na začetku programa definiramo uporabo knjižnic RH_ASK in SPI (knjižnica RH_ASK je odvisna od knjižnice SPI):
    #include <RH_ASK.h>
    #include <SPI.h>
    Nato definiramo univerzalni objekt za radijsko komunikacijo vrste RH_ASK in z imenom rf_driver:
    RH_ASK rf_driver(2000,
    12, 8);
    Pridruženi parametri definirajo hitrost prenosa (2000), priključek preko katerega sprejemamo podatke (12) in priključek preko katerega oddajamo podatke (8).
    V funkciji setup() inicializiramo objekt rf_driver:
    void setup() {
    rf_driver.init();
    }
    V funkciji loop() bomo prebrali stanje na analognem vhodu A3 in ga shranili v spremenljivko potValue vrste uint16_t. Ta podatek bomo poslali s pomočjo funkcije rf_driver.send(), kateri predamo dva parametra: ime niza z elementi dolžine 8 bitov in število elementov tega niza. Ker je potValue 16-bitna spremenljivka, jo bomo transformirali v niz z elementi dolžine 8 bitov s pomočjo ukaza (uint8_t*)&potValue. Dolžino niza izračunamo s pomočjo funkcije sizeof():
    void loop() {
    uint16_t potValue = analogRead(A3);
    rf_driver.send((uint8_t*)&potValue,
    sizeof(potValue));
    S pomočjo funkcije rf_driver.waitPacketSent() bomo počakali dokler se prenos ne dokonča, nato bomo napravili še dodaten postanek dolg 200 ms:
    rf_driver.waitPacketSent();
    delay(200);
    }
    Arduino rešitev (program sprejemnika, Geekcreit_12b.ino)
    Kot tudi v predhodnem primeru na začetku programa definiramo uporabo knjižnic RH_ASK in SPI in univerzalni objekt za radijsko komunikacijo vrste RH_ASK z imenom rf_driver. V programu bomo uporabiti tudi LCD, zato definiramo tudi uporabo knjižnice LiquidCrystal, kateri bomo takoj  nato pridružili še ustrezne komunikacijske priključke:
    #include <RH_ASK.h>
    #include <SPI.h>
    #include <LiquidCrystal.h>
    RH_ASK rf_driver(2000, 12, 8);
    LiquidCrystal lcd(2, 3, 4, 5, 6, 7);
    Opazili boste, da smo pri inicializaciji objekta rf_driver() navedli isto hitrost komunikacije, kot v predhodnem programu. Sprejemni priključek je naveden kot priključek 12, v skladu s shemo na sliki 44. V funkciji setup() definiramo vrsto alfanumeričnega displeja, ki ga uporabljamo, inicializiramo objekt rf_driver in izpišemo začetke obeh vrst na alfanumeričnem displeju:
    void setup(){
    lcd.begin(16, 2);
    rf_driver.init();
    lcd.print(“A/D izhod:”);
    lcd.setCursor(0, 1);
    lcd.print(“napetost:”);
    }
    V funkciji loop() definiramo niz buf vrste uint8_t z dvema elementoma in spremenljivko buflen, v katero vpišemo število elementov v nizu buf:
    void loop(){
    uint8_t buf[2];
    uint8_t buflen = sizeof(buf);
    Preverjamo, če so s pomočjo radijske komunikacije sprejeti podatki v niz buf in ko se to zgodi, transformiramo niz od dveh 8-bitnih podatkov v enega 16-bitnega v spremenljivko rcvdata vrste uint16_t:
    if (rf_driver.recv(buf, &buflen)) {
    uint16_t rcvdata = buf[1] * 256 + buf[0];
    Želimo si, da je izpis številke poravnan v desno oziroma, da se število enic vedno izpisuje kot zadnji znak v prvi vrsti.
    Da bi to dosegli, s pomočjo if-elseif-else ukaza preverjamo, koliko mest ima branje potenciometra in sočasno izpisujemo potrebno število praznih mesta. Po tem izpisujemo vrednost spremenljivke rcvdata in postavljamo kursor na pozicijo za izpis napetosti:
    lcd.setCursor(12,0);
    if (rcvdata > 999 ) {
    } else if (rcvdata > 99) {
    lcd.print(“”);
    } else if (rcvdata > 9) {
    lcd.print(“”);
    } else {
    lcd.print(“”);
    }
    lcd.print(rcvdata);
    lcd.setCursor(11,1);
    Napetost moramo prikazati kot številko z dvema decimalnima mestoma, pa bomo pretvoriti prebrano vrednost v decimalni razpon od 0.00 do 5.00:
    float napetost = rcvdata * (5.0 / 1023.0);
    Opazili boste, da smo cela števila 5 in 1023 morali pisati z decimalno piko in enim decimalnim mestom; če bi to opustili, izračun ne bi bil točen! Sedaj lahko izpišemo rezultat in merilno enoto:
    lcd.print(napetost);
    lcd.print(“V”);
    }
    }
    Ukaz lcd.print() bo avtomatsko zaokrožil število na dve decimalki!
    Opomba:
    Programe Geekcreit_11.ino, Geekcreit_12a.ino in Geekcreit_12b.ino lahko brezplačno dobite od uredništva revije Svet elektronike.
    https://svet-el.si

    _