Fórum témák
» Több friss téma |
Cikkek » Építsünk be utólag távirányítót! Építsünk be utólag távirányítót!
Szerző: sargarigo, idő: Júl 31, 2012, Olvasva: 28104, Oldal olvasási idő: kb. 4 perc
Miután meggyőződtem róla hogy az elmélet és a gyakorlat szerencsésen fedi egymást, írtam egy programot, ami a fentiek alapján dekódolja a vett infra adást, és soros porton kiírja a címet, és a parancskódot is. A noteszembe kíváncsiságból felirkáltam a távirányítón található összes gomb kódjait, majd kiválasztottam azokat, amiket fel kívánok használni. Mindkét program egyben letölthető a cikk végén. LoggerA logger főprogram az alábbi: int main(void) { PORTB = 0x00; DDRB &= ~(1<<PB3); // PB3(2) bemenet lett PORTB &= ~(1<<PB3); // nem kell felhuzo ellenallas DDRB |= (1<<PB4); // PB4(3) kimeneti led TCCR0A |= (1<<WGM01); // ctc mode OCR0A = 255; // ... csak szepen lassan.. TIMSK0 |= 1<<OCIE0A; sei(); _delay_ms(5000); PutString("nrnrnr"); LED_OFF(); for(; { wait_for_sync(); // varjuk a startbitet receive(); // vesszuk az adatot send_pattern(); // kiirjuk a terminalra } return 0; } Mint látható a főprogram nem lett elbonyolítva. Egy bemenet az infrának, egy-egy kimenet a LED-nek és a soros kommunikációnak. Beállítjuk a timert hogy ctc módban dolgozzon, ezáltal szép, szabályos időközönként veszi a mintákat. Megjegyzem, meg lehetett volna oldani timer nélkül is, de már ezért nem akartam újra átírni az egészet. A kódméretet illetően el kell mondanom, hogy egy nyomorult copyright szöveg sem fért már bele! Ezért itt mondom, hogy szabadon felhasználható, átírható terjeszthető, de kérlek legalább említésként a nevem szerepeljen ott valahol... creativecommons.org/licenses/by-nc-nd/2.5/hu/ A wait_for_sync addig várakozik, amíg a vonal nyugalmi állapotba nem kerül, majd megérkezik az első startbit. A GET_IR makró már tartalmazza a fentebb említett invertálást, tehát standard logikai jelként értelmezhető a kimenete. A startbit detektálását követően már nem foglalkozunk a második startbittel, elhisszük neki hogy az is jön. Ennyi egyszerűsítés már igazán belefér. void wait_for_sync(void ) { unsigned int counter; start: counter = 0; LED_OFF(); // Ha most magas, akkor varni kell, amig alacsony nem lesz while (GET_IR); // most mar biztosan alacsony // Most varni kell amig magasba nem megy, de kozben szamolunk while (!GET_IR) { if (counter < 0xffff) counter ++; // nincs tulcsordulas _delay_ms(1); } // most mar magasban van if (counter < 500) // ha meg nem eleg hosszu ideig volt alacsony goto start; // akkor elolrol az egesz // Eleg sokaig volt alacsony, jelzest adunk if (counter >1100) LED_ON(); _delay_ms(10); LED_OFF(); } Miután biztosan megérkezett a startbit, következik a tényleges vétel. void receive(void) { LED_ON(); // Jelezzuk a startot TCNT0 = 0; // Nullarol szamolunk received_word = 0; // Ez lesz a vett adat TCCR0B |= (1<<CS01) | (1<<CS00); // clk/16 _delay_ms(300); TCCR0B &= ~(1<<CS01) & ~(1<<CS00); // stop received_word >>= 1; // egyel tulleptettuk, korrigalunk } Ez annyiból áll, hogy elindítja a timer-t, ami összeszedi az érkező biteket, majd leállítja azt, és egy korrekciót végez. Az ISR kóddal együtt lesz értelmes egész, így az itt következik. ISR(TIM0_COMPA_vect) { // Jelezzuk a mintavetel helyet PORTB ^= 1<<PB4; // majd eltaroljuk az aktualis erteket if (GET_IR) { received_word |= 1; } // leptetunk egy bitet es kesz is vagyunk egyenlore received_word <<= 1; } A LED-et átkapcsolja (ha ki volt kapcsolva akkor bekapcsolja, ha be volt akkor meg ki), amivel jelzi, hogy hol történik a mintavétel. Beolvassa a vonal aktuális állapotát, tárolja, majd végezetül ellépteti a tárolót, hogy jöhessen a következő bit. A receive eljárás határozza meg hogy mennyi ideig fusson a timer, tehát hogy hány bitet várjon. Végezetül a sendpattern megjeleníti vett adatot a soros terminálon. Ezt az alábbi formában teszi (a cím, és a parancs is hexa szám): 11 0 10000 010000 RCV: 1A10 ADDR: 10 CMD:10 ParserAz előbbi program már megvalósított szinte minden funkciót amire szükségem volt, mindössze át kellett egy kicsit faragni, hogy az alkalmazáshoz jó legyen. Kivettem belőle a soros port kezelését, és betettem helyette egy "szótárazó" kódot, ami egy táblázatból kikeresi a vett kódot, és ha megtalálja, akkor hozzárendel egy kimenetet. A főprogram teljesen ugyanaz mint az előbbi, csak az eljárások változtak meg. char funcs[4] = { PB0, PB1, PB4, PB2}; char addrs[4] = {0x10, 0x10, 0x10, 0x10}; char cmds[4] = { 0x10, 0x11, 0x0f, 0x06}; // {Vol+, Vol-, DSC (mode), DBB (input)} Bevezettünk három új tömböt, ami majd a szótárazáshoz fog kelleni. Itt jegyzem meg, hogy ugyan csak négy gomb kezelésére van a program felkészítve, de tetszőleges számút lehet használni a fenti tömbök bővítésével! void parser(void) { unsigned char addr = ((received_word & 0x07c0) >> 6); unsigned char cmd = (received_word & 0x003f); unsigned char repeat = ((received_word & 0x0800) >> 11); // if ((old_addr != addr) || (old_cmd != cmd) || (old_repeat != repeat)) // Ha cim, parancs, vagy ismetles elter // Kikeressuk a hozza tartozo funkciot for (char i=0; i<4; i++) { if ((addrs[i] == addr) && (cmds[i] == cmd)) { // Ha egyezik a kod, akkor aktivaljuk (alacsony szinten aktiv PORTB &= ~(1<< funcs[i]); _delay_ms(1000); // majd kikapcsoljuk PORTB |= (1<< funcs[i]); } } old_repeat = repeat; old_addr = addr; old_cmd = cmd; } Az eljárás motorja ugyanaz maradt, mint az előbb, szétdarabolja a bitsorozatot cím, és parancs részekre. Miután ezzel végzett, kikeresi a szótárból, hogy van-e ilyen tárolt cím:parancs kombináció. Ha van, akkor a hozzá tartozó kimenetet aktívvá teszi. Vár egy kicsit, majd visszatér a fő ciklusba. Ugyan itt nem használjuk ki, de a kódban benne van a gombismétlés tiltása. Erre szolgál az old_repeat (ami valójában a toggle-bit), az old_addr, és az old_cmd. Összehasonlítja az értéküket az előzővel, és ha egyezik, akkor eldobja. A funkció aktiválásához a megjegyzést vegyük ki a hetedik sor elől! Ezzel a programmal már sikerült elérni, hogy a próbapanelon csak a kijelölt gombok megnyomásakor villant a hozzá tartozó LED. Mivel az erősítő előlapján lévő gombok felhúzott állapotban vannak, ezért fordított logikát kell a kimenethez alkalmazni. Alapból magas, gombnyomásra alacsony szintet vesz fel az adott kimenet, így az AVR közvetlenül le tudja húzni, vagyis megnyomja a gombot. Az IC-t a foglalatba rakva rögtön működőképes volt szépen lehet irányítani az Elta erősítőt a Philips távirányítóval. Kívülről pedig semmi sem látszik. Muris mi? A működésről egy videó: youtu.be/IUEm-foVKB8 Itt tudod a programokat letölteni: 876/taviranyito.zip Remélem hasznos volt a cikket végigolvasni! Értékeléshez bejelentkezés szükséges! |
Bejelentkezés
Hirdetés |