Miskolci Egyetem Gépészmérnöki és Informatikai Kar Elektrotechnikai és Elektronikai Intézet Villamosmérnöki szak Elektronikai tervezés és gyártás szakirány Jelenlét érzékelésen alapuló világítás vezérlés Szakdolgozat Papczun Péter Ernő VQQTTC 2017
Eredetiségi nyilatkozat Alulírott Papczun Péter Ernő (neptun kód:vqqttc ) a Miskolci Egyetem Gépészmérnöki és Informatikai Karának végzős szakos hallgatója ezennel büntetőjogi és fegyelmi felelősségem tudatában nyilatkozom és aláírásommal igazolom, hogy a Jelenlét érzékelésen alapuló világítás vezérlés című komplex feladatom/ szakdolgozatom/ diplomamunkám 1 saját, önálló munkám; az abban hivatkozott szakirodalom felhasználása a forráskezelés szabályi szerint történt. Tudomásul veszem, hogy plágiumnak számít: - szószerinti idézet közlése idézőjel és hivatkozás megjelölése nélkül; - tartalmi idézet hivatkozás megjelölése nélkül; - más publikált gondolatainak saját gondolatként való feltüntetése. Alulírott kijelentem, hogy a plágium fogalmát megismertem, és tudomásul veszem, hogy plágium esetén a szakdolgozat visszavonásra kerül. Miskolc, Hallgató aláírása 1 Megfelelő rész aláhúzandó 1
Tartalomjegyzék 1. Bevezetés...3 2. Jelenlét érzékelő rendszerek működési elvük, fajtáik...4 2.1. PIR Szenzorok[1]...4 2.1.1. Duál infra[8]...5 2.1.2. Quad infra [8]...6 2.1.3. Kettős duál infra [8]...7 2.2. Radar szenzorok[1]...8 2.3. Termikus érzékelők[2]...9 3. Az eszköz tervezése... 11 3.1. Áttekintés... 11 3.2. A felhasznált szenzor... 11 3.3. A mikrokontroller... 13 3.4. I2C kommunikáció... 14 3.5. Relé... 15 3.6. Tranzisztoros kapcsoló... 16 3.7. Alkatrészlista... 18 4. A NYÁK tervezése... 19 5. Az eszköz programozása... 21 5.1. Atmel Studio... 21 5.2. Atmel ICE... 21 5.3. Az IC alapbeállításai... 22 5.4. Forráskód... 22 5.4.1. main.c... 22 5.4.2. softuart.h... 29 5.4.3. softuart.c... 31 6. Tesztelés... 34 6.1. A logikai analizátor... 34 6.2. Kiértékelés... 34 6.3. UART vizsgálata... 35 7. Összefoglalás... 37 8. Summary... 38 9. Irodalomjegyzék... 39 10. Ábrajegyzék... 41 Mellékletek... 42 2
1. Bevezetés A szakdolgozatom egy jelenlét érzékeléses szenzor segítségével történő kapcsoló vezérlés. Jelen világunkban nagyon fontos az energiatakarékosság, és az automatizálás. Rengeteg energiát tudunk megtakarítani világítás, hűtés-fűtés okos felhasználásával. Az eszköz alkalmas eldönteni, hogy van-e ember a szobában majd az információ alapján fel vagy le kapcsolni az adott eszközt. A legtöbb jelenleg használt módszer a mozgás meglétét figyeli, nem pedig a jelenlétet. Ezáltal, ha a személy hosszabb ideig ülő vagy álló helyzetben van, ezek a megoldások nem mindig célszerűek. Célom egy felhasználó barát eszköz kifejlesztése, amely alkalmas a feladat elvégzésére és könnyen felhasználható. Az eszköz több célú felhasználhatósága is szempont, ezért egy programozható mikrovezérlővel kell, hogy az adatokat feldogozzuk. 3
2. Jelenlét érzékelő rendszerek működési elvük, fajtáik 2.1.PIR Szenzorok [1] Minden test 0K felett hőt sugároz ki magából, amely láthatatlan az emberi szem számára. A PIR szenzorok (Passive Infrared Sensor) egy mozgó emberi test hőjének a környezet hőmérsékletére gyakorolt hatását érzékeli. Ez a sugárzás infravörös tartományba esik és ezt egy piroelektromos anyag érzékeli. Az érzékelő, ahogy azt a nevében a passzív szó is jelzi, nem generál vagy sugároz energiát a mérés céljából. Nyugalmi helyzetben nem képes a jelenlét érzékelésre, mert a felületén egyenletes a töltéselosztás. Infravörös sugárzás hatására ez az egyensúly felbomlik, polarizációváltozás következik be, amelyet elektromos jelként érzékelni tudunk. A jelet egy FET-es erősítővel felerősítünk, így alkalmas lesz a jel további felhasználásra. [1] 1. ábra A PIR érzékelő alapelve [1] Hogy megértsük a működését, a szenzor látóterét érzékelő nyalábokra (érzékeny zónák) és üres mezőkre (érzéketlen zónák) bontjuk fel. Ha egy ember elhalad a szenzor előtt, akkor mozgás közben keresztül megy egy nyalábon utána egy üres mezőn, majd ismét egy nyalábon. Az így egymást követő érzékeny és érzéketlen zónákon való haladást méri a szenzor és állapítja meg a mozgást. 4
2. ábra A szenzor látótere [8] A PIR szenzorok estében három típust különbözetünk meg: Duál infra [8] Quad infra [8] Kettős duál infra [8] 2.1.1. Duál infra [8] Ebben az esetben a tokon belül két érzékelő található. A két érzékelő egymás mellet helyezkedik el, egymással sorba kötve fordított polaritással. Az indok a két érzékelő használatára, hogy az állandó hőt generáló testek (pl. fűtőtest) hatására a szenzor ne érzékeljen hamis mozgást. A fordított polaritás miatt ilyenkor az egyik pozitív jelet, míg a másik egy ugyanakkora negatív jelet küld a vezérlő áramkör felé. Ezeknek az összege nulla, tehát nem érzékel mozgást. Ha mozgunk a szenzor előtt, akkor először a pozitív jelet küldő érzékelő nyalábján haladunk keresztül, majd a negatív jelet küldő nyalábján. Ilyenkor a két jel összege már nem nulla lesz, és a szenzor mozgást fog érzékelni [8]. 5
3. ábra A duál infra két érzékelő eleme [8] 2.1.2. Quad infra [8] A quad infrák esetében kétszer annyi érzékelő elemet helyeznek el egy szenzoron belül, mint egy duál infrás kivitelben. Az érzékelőket vagy vonalasan, vagy négyzetesen lehet elhelyezni. A megoldás arra szolgál a nagyobb érzékenységen kívül, hogy a kis állatok ellen való érzékelést hatékonyabban kiküszöbölje. Az elrendezésnek köszönhetően a nagyobb felületet kihasználva érzékelhetjük a test nagyságát annak függvényében, hogy az érzékelő nyalábjai milyen mértékben érzékelnek hőmérséklet változást [8]. 4. ábra A quad infra érzékelésésnek szemléltetése [8] 6
2.1.3. Kettős duál infra [8] A kettős duál infrás kialakításban két érzékelő elemes szenzorokból kettőt raknak egy eszközbe. Ezzel a kialakítással rendkívül pontos, nagyon megbízható érzékelést tudunk elérni. [8] A PIR szenzorok alkalmazása olcsó, egyszerű, azonban jelenlét érzékelésre nem teljesen használható. A gyakorlatban előre definiálunk egy időt, amely érzékelést követően égve hagyja a fényforrást. Ha újabb mozgást érzékel az eszköz, ez az idő újraindul. 5. ábra Egy PIR szenzor elvi kapcsolása [1] Példaként a Micropik D203B szenzor paramétereit az alábbi táblázat mutatja: Táp. feszültség Működési hőmérséklet Tokozás tipusa Kommunikáció tipusa 1. táblázat. Micropik D203B szenzor paraméterei [4] 3-15 V DC -30/+70 C TO-5 1 vezetékes analóg 7
2.2.Radar szenzorok [1] A radar szenzorok képesek kisebb mozgásokat érzékelni, mint a PIR szenzorok. Rádiófrekvenciás elektromágneses hullámokat bocsát ki az eszköz, amely hullámok a K-Band sávba (24,1 GHz) esik. A működési elv a Doppler-effektuson alapszik. Az eszköz által kibocsájtott hullám a mozgó testről eltérő frekvenciával verődik vissza. Ezt a különbséget felhasználva sebesség mérésre is alkalmas az eszköz. A sugárzás fém felületekről rendkívül jól verődik vissza, de az emberi testet is könnyen lehet detektálni vele a testben lévő nagymennyiségű víz miatt [1]. 6. ábra Doppler-effektus szemléltetése [1] Sokszor használják a radar szenzorokat PIR szenzorral egyszerre, ilyenkor úgynevezett duál technológiás érzékelőt kapunk. A radar szenzor ezekben az eszközökben a K-sáv helyett gyakran az úgynevezett X sávot (10,52 GHz) használják. Ilyen kialakításnál a két szenzort logikai ÉS kapcsolatba kötve használják. A technológia célja hogy a PIR szenzorok a föléjük közeledő nyalábokra párhuzamos mozgásra kevésbé érzékenyebb, míg a radar szenzorok esetében ez nem áll fent. Az ÉS kapcsolatra a radar szenzor miatt van szükség, ugyanis a nagy átlátás miatt a radar szenzor a gipszkartonon, üvegen keresztül is tud érzékelni mozgást, emiatt kell, hogy az infra érzékelő látóterében legyen csak mozgás érzékelés. [8] 8
A szenzor, ha képes 1 m/s vagy annál kisebb sebesség detektálására, akkor alkalmazható jelenlét érzékelésre is, bár nem alkalmazható minden területen az elvből adódó problémák (nagy átlátás) miatt [1]. Példaként a JRC NJR4265 szenzor paramétereit az alábbi táblázat mutatja: Táp. feszültség Működési hőmérséklet Szükséges sebesség érzékeléshez Kommunikáció tipusa 2. táblázat. JRC NJR4265 szenzor paraméterei [4] 3.3-5 V DC -40/+85 C 0.25-1 m/s 2 vezetékes digitális (UART) 2.3.Termikus érzékelők [2] A PIR szenzorokkal ellentétben a termikus szenzorok a Seeback-hatást használják. Két különböző fémet összekapcsolnak (forrasztanak, hegesztenek) a két végüknél. A forrasztási pontot mérőpontnak vagy melegpontnak hívják, a szabadon hagyott végeket referenciapontoknak vagy hidegpontoknak hívják. A referencia pont és a melegpont között a hőmérséklet különbség hatására egyenfeszültség alakul ki, amely arányos a hőmérséklet különbségükkel. Ezt hívják Seeback-hatásnak. Az érzékelőben ilyen hőelemeket mátrixba kötik, így képesek egy nagyobb területet pixelekre felbontani [2]. Pédaként tekintsük a Panasonic által kifejlesztett GridEYE szenzort, amely egy 8x8-as hőelem mátrix: 7. ábra GridEYE szenzor [1] 9
8. ábra GridEYE szenzor felbontása [1] A szenzor a mért értékeket egy soros porton adja ki, amelyet egy eszközzel fel kell dolgoznunk. A kommunikáció ennél a típusnál I2C-n történik. A kiolvasás sebessége 1-10 fps 2 -el történhet. [1] Példaként a Panasonic AMG8851 szenzor paramétereit az alábbi táblázat mutatja: 3. táblázat. Panasonic AMG8851szenzor paraméterei [5] Tápfeszültség 5 V DC Működési hőmérséklet Pontosság Kommunikáció tipusa 0/+80 C ±2.5 C 2 vezetékes digitális (I2C) 2 fps- (frame per second) Másodpercenkénti képek száma 10
3. Az eszköz tervezése 3.1.Áttekintés A cél egy olyan eszköz kialakítása, ami képes egy adott hőmérsékletet érzékelve a relét vezérelni. Mivel egy intelligens kapcsolóként működik, így bármilyen eszközt (lámpa, ventillátor, klíma) vagy vezérlőjelet tud kapcsolni. Fontos, hogy az eszköz megvalósítási költségét minél alacsonyabb szinten tartsuk, valamint méretét tekintve kicsi és praktikus legyen. A szenzor adatait egy ATTiny45 mikrokontrollerrel fogom kiolvasni, feldolgozni, majd ugyan ezzel az ATTiny45-tel fogom a relét működtetni. A többcélú felhasználást segítve egy soros porton (UART) kiolvashatjuk az eszköz által mért értékeket. 9. ábra Az eszköz blokkdiagramja 3.2.A felhasznált szenzor Szenzornak az Omron D6T-44L-t választottam méretét és alkalmazási lehetőségeit figyelembe véve. Működési elve a GridEYE szenzorral megegyező, azonban az ára, valamint a kialakítása jobban megfelel a kivitelezés szempontjából. A szenzor I2C kommunikációs lehetőséggel van ellátva, amely tökéletesen megfelel az általam tervezett eszköz megvalósításához. A szenzor 4x4-es mátrixban érzékeli az általa látott teret. Kommunikáció során az egyes pixelek által érzékelt hőmérséklet tízzel 11
megszorzott értékét, valamint a szenzor saját hőmérsékletét (referencia hőmérsékletét) Celsius fokban adja át a mikrokontrollernek. A szenzor ±1.5 C és ±3.0 C pontossággal tudja mérni az emberi test hőmérsékletét. A pontosság függ a referencia és a test hőmérséklet különbségétől. Az eszköznek 4db csatlakozója van, amelyből kettő a betáplálásra, kettő pedig a kommunikációra szolgál. A szenzor 5 V egyenárammal való táplálást igényel. Működési hőmérséklete nullától 50 C-ig terjed, így megfelel a tervezett eszköz igénybevételének [6]. 10. ábra Az Omron D6T-44L szenzor [2] 11. ábra A szenzor látótere [2] A szenzor nem önmagában, hanem egy NYÁK-on található, amely tartalmazza a szenzort, a hozzá tartozó analóg kapcsolást, valamint egy digitális áramkört, amely átalakítja a jelet, hogy alkalmas legyen a feldolgozásra. 12
3.3.A mikrokontroller Mikrokontrollernek az ATTiny45-öt választottam. A döntésem a felhasználás igénybevétele és az ára miatt alakult. Az ATTiny45 alkalmas I2C-n való kommunikációra, amely feltétlenül szükséges a szenzor miatt. Kis mérete és kis teljesítmény felvétele további előny, későbbi bővítés is lehetséges. Az IC programozása ISP-n (In-System Programmable) keresztül történik, azaz beültetés után a külön programozásra tervezett tüskesoron keresztül lehetséges külső programozó segítségével. Az eszköz USI (Universal Serial Interface) soros kommunikációt használ TWI (két vezetékes) módban, amely kompatibilis az I2C protokollal. Fontosabb paraméterek: [7] 8 lábas SOIC kivitel 20 MHz es belső oszcillátor 6 db I/O láb Kimeneti áram lábanként: 40 ma Tápfeszültség: 5 V Adatbusz szélessége: 8 bit RAM mérete: 256 byte Program memória: 4 kb FLASH Kettő 8 és egy 16 bites timer Működési hőmérséklet -40 C/+85 C 12. ábra Az ATTiny45 lábkiosztása [7] 13
13. ábra ATTiny45 blokkdiagram[7] 3.4.I2C kommunikáció A szenzor és a PIC között kétvezetékes, I2C (Inter-Integrated Circuit) kommunikáció zajlik. Az I2C busz jellemzői: Két vonalat használ: egy szinkronjelet (SCL), és egy adatjelet (SDA) Egy buszra több eszköz csatlakoztatható, aminek a számát a busz kapacitása határozza meg, amely maximum 400 pf Kommunikáció csak akkor indítható, ha a busz tétlen, ekkor mind két vonal magas szinten van Soros 8 bit-es kétirányú adatforgalom Mind két vezetéket egy ellenálláson keresztül (3.9 kω) VCC szintre kell felhúzni. 14
14. ábra A szenzor és az ATTiny összekötése [17] 15. ábra I2C kommunikáció folyamata [16] 3.5.Relé Relének, amely érzékelés esetén kapcsolni fogja a világítást ki és be, a G5LE-1-VD 5 VDC "kocka" relét választottam. A döntésem az ár és a paraméterek alapján történt. Mivel a relé tekercs feszültsége is 5 V, így egy hálózatra kapcsolható a többi alkatrésszel. 15
A relé fontosabb paraméterei [10]: Tekercs feszültség: 5 V Tekercs árama: 79,4 m A Tekercs ellenállás: 63 Ω Teljesítmény felvétel: 400 mw Maximális kapcsolási teljesítmény: 240 W, 1200 VA Maximális kapcsolási áram (240 V esetén): 10 A Maximális Kapcsolási idő: 10 ms Maximális elengedési idő: 5 ms 16. ábra A relé elvi kapcsolása [10] 17. ábra A relé [15] 3.6.Tranzisztoros kapcsoló A ATTiny45 lába, amelyet kimenetként fogunk használni, önmagában nem képes olyan áramot leadni (az ATTiny45 kb. 40 ma leadására képes lábanként), amellyel a relét tudnánk irányítani. Ezen probléma megoldása érdekében egy tranzisztort fogunk 16
használni kapcsolóüzemben. Az ATTiny45 lábával így nem a relét fogjuk közvetlen irányítani, hanem a tranzisztort fogjuk kapcsolgatni, amellyel a relét már vezérelni tudjuk. NPN tranzisztort fogunk használni, egy BC337-es megfelel a célra. Mivel a relé kikapcsolásakor a tekercs miatt nagy feszültséglökések keletkeznek, ezért egy védődiódát is be kell iktatnunk. Diódának egy 1N4004 típust választottam. Ez a dióda nagyon általános és a kapcsolásunkhoz elegendő. Az erősítőhöz ki kell számolnunk a bázis ellenállást [11]. A terhelés áramfelvétele a tekercs árama, amit a relé adatlapjáról leolvastunk 79,4 ma. Megkeressük a Béta értékét a tranzisztor adatlapján szereplő grafikonból kiolvasva. 18. ábra A BC337 grafikonja A grafikonból kiolvashatjuk, hogy nekünkh =310, így ezzel számolunk tovább. Az előtét ellenállás meghatározásnak képlete a következő [11]: = = = 3,9 Ω (1), ahol: = Bázis ellenállás értéke = Terhelés működési feszültsége h = Áram erősítési tényező (DC Current gain) = Terhelés áramfelvétele 17
3,9 kω lett kiszámolva előtét ellenállásnak. Az ellenálláson keresztül pár ma-es áram fog csak folyni, ezért teljesítmény szempontjából 0,6 W-os is elegendő, de használhatunk 0,25 W-os kivitelűt is. 3.7.Alkatrészlista 4. táblázat. A felhasználandó alkatrészek listája Leírás RefDes Láblenyomat Egységár [HUF] ATTINY 45 MCU IC1 SOIC-8 440 Omron D6T szenzor IC2 4 db 2,54 mm-es tüske 9700 3.9 Ω ellenállás R1, R2, R3 0207 20 G5LE-1 5DC relé K1 G5LE 360 BC337 tranzisztor T1 TO92 40 Sorkapocs X1 5,08 mm 200 Sorkapocs X2 5,08 mm 120 DC tápcsatlakozó J1 5,5/2,5 260 1N4004 dióda D1 DO41-10 35 A feltüntetett árak csak közelítő jellegűek, ezek változhatnak. Ha ezeket az árakat vesszük figyelembe, a végösszeg 11215 HUF lesz az alkatrészek esetében. Sajnos a szenzor ára, ami az összeget nagyban befolyásolja, azonban a lehetséges szenzorok közül ez a legolcsóbb választás. 18
4. A NYÁK tervezése A NYÁK tervezéséhez a Cadsoft EAGLE programot használtam. Először a kapcsolási rajz tervezőben kell minden alkatrészt elhelyezni, összekötni, majd ellenőrizni. A szoftver saját alkatrész könyvtárral rendelkezik, amely tartalmazza az összes felhasznált alkatrészt. 19. ábra Az eszköz kapcsolási rajza Ezután a NYÁK tervező programjában kell a láblenyomatokat elhelyezni és összekötni azokat. A NYÁK méretét és alakját ahhoz a dobozhoz igazítottam, ami később a házat fogja adni az eszköznek. Az alkatrészek elhelyezésekor fontos volt, hogy a csatlakozó felületeket (DC jack, sorkapocs, UART port) a panel szélére helyezzem, így könnyen elérhető helyen legyen. Mivel a relé nagy teljesítményt tud kapcsolni, így hozzá vastagabb vezetősávok lettek tervezve. 19
20. ábra Az eszköz NYÁK terve A tervezést követően az eszközt kétoldalas FR4 lapra lett kimarva. VIA-k tervezése nem volt szükséges ugyanis az átvezetéseket a THD-alkatrészek szolgáltatják, ezzel is csökkentve a gyártási költségeket. 21. ábra Az eszköz nyitott dobozában 20
5. Az eszköz programozása 5.1. Atmel Studio A program megírásához az Atmel Studio 7.0 nevű és verziószámú fejlesztő környezetet használtam. A szoftver előnye, hogy makróként lehet hivatkozni az egyes Atmel mikrovezérlők memória címeire, valamint tartalmazza a fordítót is. A program megírása C programozási nyelven történt. A szoftver felhasználása egyszerű, a kezdőképernyőn megtaláljuk a program szerkesztőt, amely jelzi, ha hibás egy sor vagy változás történt a programban, így segítve a hibakeresést. A kezdőképernyőn helyt kapott a solution explorer is, ami a projecthez felhasznált fájlokat gyűjti egy helyre, így könnyebben tudunk mozogni a használatban lévő fájlok között. 22. ábra Atmel Studio használat közben 5.2. Atmel ICE Az eszköz programozásához egy külön programozó eszköz szükséges, ez az Atmel ICE. A programozó képes a legtöbb Atmel gyártotta mikrokontrollereket programozni, valamint használható debug módban is, ezzel segítve a fejlesztést. Az eszköz tápellátását USB-ről kapja (5 V). Az eszközhöz csatlakoztatott kábel egy 6-pines csatlakozóban végződik. Ennek a csatlakozónak a lábkiosztásával egyező tüskesort kellett a NYÁK-ra tervezni, hogy az ATTiny-t beépítve programozni tudjuk. 21
5.3. Az IC alapbeállításai Az Atmel Studioban lehetőség van az ATTiny fusebit-jeit beállítani. A fuse bitekkel lehet beállítani, hogy az ATTiny külső órajelgenerátort használjon, vagy a belső oszcillátorát és, hogy azt milyen szorzóval, a reset lábat IO-ként kezelje-e. Itt akár ki és be lehet kapcsolni az eszköz programozhatóságát. A fuse bitek lényege, hogy ezek a beállítások akkor is megmaradnak, ha az eszköz feszültség mentes állapotban van, vagy akár újra programozzuk. A könnyebb és kevesebb alkatrésszel való felhasználáshoz az ATTiny saját RC órajel generátorát használtam, így az eszköz órajele 8 MHz. Az IC bármikor újraprogramozható. 5.4. Forráskód 5.4.1. main.c A main.c tartalmazza az I2C kommunikációhoz tartozó összes függvényt, definíciót és az adatfeldolgozást. A program megírásához kiinduló pontnak a neten nagyon sok hasonló mintaprogramot találtam, amelyek alapján építettem fel a saját programomat is. Először a definíciók vannak leírva. Itt vannak definiálva azok a makrók amelyekkel könnyebben és átláthatóbban lehet felépíteni a programot. Ilyenek a sebességek és idők beállításai egyes port definíciók és címek definíciói. //Időzítések #ifdef I2C_FAST_MODE #define I2C_T1 2 // >1.3us #define I2C_T2 1 // >0.6us #else #define I2C_T1 5 // >4.7us #define I2C_T2 5 // >4.0us #endif // Bit és cím definiciók #define I2C_READ_BIT 0 #define I2C_ADDR_BITS 1 #define I2C_NACK_BIT 0 #define TRUE 1 #define FALSE 0 #define I2C_READ 1 #define I2C_WRITE 0 22
#define OMRON_R #define OMRON_W 0x15 // I2C address 0x14 // I2C address // Hibák #define I2C_ERR_NO_DATA #define I2C_ERR_DATA_OUT_OF_BND #define I2C_ERR_UE_START 0x03 #define I2C_ERR_UE_STOP #define I2C_ERR_UE_DATA_COL #define I2C_ERR_NO_ACK_ON_DATA #define I2C_ERR_NO_ACK_ON_ADDR #define I2C_ERR_MISSING_START_CON #define I2C_ERR_MISSING_STOP_CON0x09 0x01 0x02 0x04 0x05 0x06 0x07 0x08 // IC port definiciók #define I2C_DDR DDRB #define I2C_PORTPORTB #define I2C_PIN PINB #define I2C_SDA PB0 #define I2C_SCL PB2 #define OUT_PIN PB3 Az első függvény alaphelyzetbe állítja az eszközt I2C kommunikációhoz. Az IO lábakat beállítja kimenetként és beállítja az USI kommunikációt kétvezetékes módba. Ehhez a datasheetben leírtak szerint kell a memória címeket vezérelni. Majd nullázza a számlálóhoz felhasznált memóriákat. void I2C_init(void) //IO portok beállitása kimenetként felhúzó ellenállásokkal I2C_PORT = (1<<I2C_SDA) (1<<I2C_SCL); I2C_DDR = (1<<I2C_SDA) (1<<I2C_SCL); //SDA elengedése USIDR = 0xff; //USI Kétvezetékes módba való állítása (a címek rövidítése a fejlesztőkörnyezetben alapértelmezett USICR = (1<<USIWM1) (1<<USICS1) (1<<USICLK); //számláló nullázása USISR = (1<<USISIF) (1<<USIOIF) (1<<USIPF) (1<<USIDC) (0x0<<USICNT0); A következő függvény a teljes kommunikációt végig viszi. Először definiáljuk a bit és byte küldéseket, valamint az itt előforduló hibákat is. 23
// A fő I2C függvény uint8_t I2C_xfer(uint8_t *buffer, uint8_t buflen) // USISR (USI State Register) állapot regiszter 8 bites kommunikációhoz uint8_t SR_8bit = (1<<USISIF) (1<<USIOIF) (1<<USIPF) (1<<USIDC) (0x0<<USICNT0); // USISR (USI State Register) állapot regiszter 1 bites kommunikációhoz uint8_t SR_1bit = (1<<USISIF) (1<<USIOIF) (1<<USIPF) (1<<USIDC) (0xE<<USICNT0); I2C_state.errorState = 0; I2C_state.addressByte = TRUE; #ifdef PARAM_VERIFY if (buffer > (uint8_t*)ramend) I2C_state.errorState = I2C_ERR_DATA_OUT_OF_BND; return FALSE; if (buflen <= 1) I2C_state.errorState = I2C_ERR_NO_DATA; return FALSE; #endif if ((buffer[0] & (1<<I2C_READ_BIT)) == I2C_READ) I2C_state.dataDirection = I2C_READ; else I2C_state.dataDirection = I2C_WRITE; A start jel generálása után az SDA vonalon beállítjuk a küldendő adat első bitjének értékét, közben az SCL vonalat alacsonyan tartjuk. Az adat olvasásra kerül, amikor az SCL vonal magas logikai szintre kerül. A kommunikáció során ez a folyamat ismétlődik az SDA vonalon, amíg az SCL vonal alacsony szinten van, majd olvasás akkor történik, amikor az SCL vonal magas szintre kerül. I2C_gen_start(); do 24
if (I2C_state.addressByte (I2C_state.dataDirection == I2C_WRITE)) // Egy byte küldése az I2C buszon // SCL nullázása I2C_PORT &= ~(1<<I2C_SCL); //Adat regiszter betöltése USIDR = *(buffer++); I2C_byte_xfer(SR_8bit); // N/ACK nyugtázó jel fogadása I2C_DDR &= ~(1<<I2C_SDA); if (I2C_byte_xfer(SR_1bit) & (1<<I2C_NACK_BIT)) I2C_state.errorState = I2C_state.addressByte? I2C_ERR_NO_ACK_ON_ADDR : I2C_ERR_NO_ACK_ON_DATA; return FALSE; while (--buflen); I2C_gen_stop(); I2C_state.addressByte = FALSE; else // Byte fogadás // SDA beállítása mint bemenet I2C_DDR &= ~(1<<I2C_SDA); // Byte olvasása a buszról *(buffer++) = I2C_byte_xfer(SR_8bit); // Nyugtázó jel küldése USIDR = (buflen == 1)? 0xFF : 0x00; I2C_byte_xfer(SR_1bit); return TRUE; A protokoll sajátossága az óra jel nyújtása. A szolga eszköz a kommunikációban alacsony logikai szinten tarthatja az órajel (SCL) vonalát, ezzel jelezve, hogy nem áll készen további adat küldés/fogadásra. // Shift regiszter futtatása amíg a számláló túlcsordul // A függvény vissza állítja az SDA vonalat kimenetre uint8_t I2C_byte_xfer(uint8_t reg) 25
USISR = reg; reg = (1<<USIWM1) (1<<USICS1) (1<<USICLK) (1<<USITC); do I2C_delay(I2C_T1); //Felfutó él USICR = reg; //várakozás while (!(I2C_PIN & (1<<I2C_SCL))) ; I2C_delay(I2C_T2); //Lefutó él USICR = reg; while (!(USISR & (1<<USIOIF))); I2C_delay(I2C_T1); //Shift regiszter mentése reg = USIDR; // SDA elengedése USIDR = 0xFF; //SDA beállítása mint kimenet I2C_DDR = (1<<I2C_SDA); return reg; A kezdő feltételek (Start jel) generálása úgy történik, hogy az IC az SDA vonalat alacsony szintre húzza, míg az SCL vonalat magason tartja. Ezt a szenzor érzékeli és elkezdődik a kommunikáció. uint8_t I2C_gen_start(void) I2C_PORT = (1<<I2C_SCL); while(!(i2c_port & (1<<I2C_SCL))) ; #ifdef I2C_FAST_MODE I2C_delay(I2C_T2); #else I2C_delay(I2C_T1); #endif // Start jel generálása I2C_PORT &= ~(1<<I2C_SDA); I2C_delay(I2C_T2); I2C_PORT &= ~(1<<I2C_SCL); I2C_PORT = (1<<I2C_SDA); #ifdef SIGNAL_VERIFY 26
if (!(USISR & (1<<USISIF))) I2C_state.errorState = I2C_ERR_MISSING_START_CON; return FALSE; #endif return TRUE; Stop bit generálása hasonló, mint a start bit generálása, itt azonban az SDA vonalat magas szintre húzza, míg az SCL magas. uint8_t I2C_gen_stop(void) // SDA nullázása I2C_PORT &= ~(1<<I2C_SDA); //SCL elengedése I2C_PORT = (1<<I2C_SCL); while(!(i2c_pin & (1<<I2C_SCL))) ; I2C_delay(I2C_T2); I2C_PORT = (1<<I2C_SDA); I2C_delay(I2C_T1); #ifdef SIGNAL_VERIFY if (!(USISR & (1<<USIPF))) I2C_state.errorState = I2C_ERR_MISSING_STOP_CON; return FALSE; #endif return TRUE; A szenzor adatolvasási rutinja a szenzor datasheetből olvasható. Először a szenzor írási címét küldjük el (OMRON_W), majd egy parancsot (0x04). Ezek után felkészülünk a fogadásra, amihez az olvasási címet küldjük, majd a szenzorból beolvassuk a mért értékeket. Ahogy azt látjuk minden mért érték két részből áll: az egyik értéket megszorozzuk 256-tal (második byte), a másikat pedig a szorzott értékhez hozzáadjuk (első byte). Az kiolvasása egy példán keresztül: ha a mért pixel értéke 274 a hőmérséklete 27.4 C. // A szenzor adatainak kiolvasása void downloadtemp(void) uint8_t buf[35]; buf[0] = OMRON_W; buf[1] = 0x4C; 27
I2C_xfer(buf, 2); buf[0] = OMRON_R; I2C_xfer(buf, 35); tempstat[0] = 256*buf[2] + buf[1]; temp[0] = 256*buf[4] + buf[3]; temp[1] = 256*buf[6] + buf[5]; temp[2] = 256*buf[8] + buf[7]; temp[3] = 256*buf[10] + buf[9]; temp[4] = 256*buf[12] + buf[11]; temp[5] = 256*buf[14] + buf[13]; temp[6] = 256*buf[16] + buf[15]; temp[7] = 256*buf[18] + buf[17]; temp[8] = 256*buf[20] + buf[19]; temp[9] = 256*buf[22] + buf[21]; temp[10] = 256*buf[24] + buf[23]; temp[11] = 256*buf[26] + buf[25]; temp[12] = 256*buf[28] + buf[27]; temp[13] = 256*buf[30] + buf[29]; temp[14] = 256*buf[32] + buf[31]; temp[15] = 256*buf[34] + buf[33]; check[0] = buf[35]; A main függvény felhasználja az eddig leírt függvényeket, vezérli a relét, majd kiíratja az olvasott értékeket a soros porton. int main(void) //A ATTiny beállítása softuart_init(); I2C_init(); sei(); while (1) downloadtemp(); v = 0; // Az adatok feldolgozása // Ha az érték meghaladja a küszöb értéket az eszköz a kimenetén 1 re vált // Így a relé bekapcsol for(p=1; p<16; p++) if (temp[p]>300) v = 1; 28
if (v == 1) PORTB = (1 << OUT_PIN); else PORTB &= ~(1 << OUT_PIN); A relé kapcsolása után a kiolvasott értékeket az felbontjuk helyi értékekre maradékos osztás segítségével. Miután a felbontás elkészült, az adatokat a soros porton kiküldjük. az üzenet utolsó karakterei a sortörés. // Az olvasott értékek átalakítása helyi értékekre való felbontása for(p=0; p<16; p++) e=temp[p] % 10 ; temp[p] -= e ; temp[p]=temp[p]/10 ; t=temp[p] % 10; temp[p] -= t ; temp[p]= temp[p]/10; sz=temp[p] % 10; f[3]=' '; f[2]=e +'0'; f[1]=t +'0'; f[0]=sz +'0'; //Az értékek kiküldése softuart_puts( f ); _delay_ms(1); // sortörés softuart_puts_p( "\r\n" ); _delay_ms(10); 5.4.2. softuart.h A kód tartalmazza a soros kommunikációhoz tartozó port definíciókat, valamint azokat a makrókat, amiket a softuart.c fog használni. A main.c programban ezt a header fájlt hívom meg. 29
#if defined ( AVR_ATtiny25 ) defined ( AVR_ATtiny45 ) defined ( AVR_ATtiny85 ) #define SOFTUART_TXPORT PORTB #define SOFTUART_TXDDR DDRB #define SOFTUART_TXBIT PB4 #define SOFTUART_T_COMP_LABEL #define SOFTUART_T_COMP_REG #define SOFTUART_T_CONTR_REGA #define SOFTUART_T_CONTR_REGB #define SOFTUART_T_CNT_REG #define SOFTUART_T_INTCTL_REG #define SOFTUART_CMPINT_EN_MASK TIM0_COMPA_vect OCR0A TCCR0A TCCR0B TCNT0 TIMSK (1 << OCIE0A) #endif #define SOFTUART_CTC_MASKA (1 << WGM01) #define SOFTUART_CTC_MASKB (0) #define SOFTUART_PRESCALE (8) #define SOFTUART_PRESC_MASKA (0) #define SOFTUART_PRESC_MASKB (1 << CS01) #define SOFTUART_TIMERTOP ( F_CPU/SOFTUART_PRESCALE/SOFTUART_BAUD_RATE/3-1) #if (SOFTUART_TIMERTOP > 0xff) #warning "Check SOFTUART_TIMERTOP: increase prescaler, lower F_CPU or use a 16 bit timer" #endif #define SOFTUART_IN_BUF_SIZE 32 void softuart_init(void); void softuart_puts( const char *s ); void softuart_puts_p( const char *prg_s ); #define softuart_puts_p(s ) softuart_puts_p(pstr(s )) 30
5.4.3. softuart.c A program kezeli a soros kommunikációt. A program magas logikai szinten tartja a vonalat. #define SU_TRUE 1 #define SU_FALSE 0 #define TX_NUM_OF_BITS (10) volatile static unsigned char flag_tx_busy; volatile static unsigned char timer_tx_ctr; volatile static unsigned char bits_left_in_tx; volatile static unsigned short internal_tx_buffer; #define set_tx_pin_high() ( SOFTUART_TXPORT = ( 1 << SOFTUART_TXBIT ) ) #define set_tx_pin_low() ( SOFTUART_TXPORT &= ~( 1 << SOFTUART_TXBIT ) ) A start bit generálásához alacsony szintre vezérli a vonalat, amit a fogadó érzékelni fog. Amikor alacsony szintről magas szintre kerül a vonal, akkor az adatfolyam végén jelzi az üzenet végét (stop bit). Az üzenetben nincs paritás bit. Az üzenet bitenként lesz elküldve. Az üzenetet a legkisebb helyi értékű bittel kezdjük. ISR(SOFTUART_T_COMP_LABEL) unsigned char tmp; if ( flag_tx_busy == SU_TRUE ) tmp = timer_tx_ctr; if ( --tmp == 0 ) // Az kimenet vezérlése az adatnak megfelelően if ( internal_tx_buffer & 0x01 ) set_tx_pin_high(); // ha a bit 1 else set_tx_pin_low(); // ha a bit 0 internal_tx_buffer >>= 1; tmp = 3; if ( --bits_left_in_tx == 0 ) flag_tx_busy = SU_FALSE; timer_tx_ctr = tmp; 31
static void io_init(void) SOFTUART_TXDDR = ( 1 << SOFTUART_TXBIT ); static void timer_init(void) unsigned char sreg_tmp; sreg_tmp = SREG; cli(); SOFTUART_T_COMP_REG = SOFTUART_TIMERTOP; SOFTUART_T_CONTR_REGA = SOFTUART_CTC_MASKA SOFTUART_PRESC_MASKA; SOFTUART_T_CONTR_REGB = SOFTUART_CTC_MASKB SOFTUART_PRESC_MASKB; SOFTUART_T_INTCTL_REG = SOFTUART_CMPINT_EN_MASK; // számláló nullázása SOFTUART_T_CNT_REG = 0; SREG = sreg_tmp; void softuart_init( void ) flag_tx_busy = SU_FALSE; set_tx_pin_high(); io_init(); timer_init(); unsigned char softuart_transmit_busy( void ) return ( flag_tx_busy == SU_TRUE )? 1 : 0; void softuart_putchar( const char ch ) while ( flag_tx_busy == SU_TRUE ) 32
; timer_tx_ctr = 3; bits_left_in_tx = TX_NUM_OF_BITS; internal_tx_buffer = ( ch << 1 ) 0x200; flag_tx_busy = SU_TRUE; void softuart_puts( const char *s ) while ( *s ) softuart_putchar( *s++ ); void softuart_puts_p( const char *prg_s ) char c; while ( ( c = pgm_read_byte( prg_s++ ) ) ) softuart_putchar(c); 33
6. Tesztelés 6.1.A logikai analizátor Az eszköz teszteléséhez egy Saleae logikai analizátort használtam, amely egy 8 csatornás, maximum 24 MHz-es sávszélességgel tud dolgozni. Az eszközhöz tartozó program a Saleae Logic 1.2.9.-es verzióját felhasználva teszteltem az eszköz működését. A program sok lehetőséget biztosít, ilyen pl.: a jel analizátorok, amelyekkel a fogadott jeleket lehet valamilyen protokoll szerint értelmezni és kiolvasni. Adott esetben ilyen volt az I2C kommunikáció és az UART is. A programban csak a megfelelő csatornákat kell beállítani az analizátorokhoz. 6.2.Kiértékelés Miután az eszköz be lett kötve, egy mintavételezés után a következő képeket kaptam eredményül: 23. ábra I2C kommunikáció kezdete Itt láthatjuk, hogy az írási cím és parancs küldése után, az olvasási címet követően a szenzor elkezdi küldeni a mért adatokat. A jobb alsó sarokban láthatjuk, ahogy az analizátor az adatokat kiolvassa, és azokat decimálisan kijelzi. 34
24. ábra Adat olvasás utáni folyamatok Mint az a képen is látható, az utolsó adat olvasása után a relé vezérlése történik. A vezérlést követően a soros porton kezdődik meg az értékek kiküldése. 6.3. UART vizsgálata A soros port kiolvasását egy USB to TTL soros UART konvertáló kábellel lehet elérni. A kábel tartalmaz egy kis kapcsolást az USB csatlakozóban, amelyben egy IC kezeli az USB protokollokat és jeleket. Az adatokat egy ingyenes soros port figyelő szoftverrel (terminállal) könnyedén ki lehet olvasni. Ha a program alkalmas rá, akkor a kapott adatokat menthetjük egy külön fájlba (log), így további felhasználási módokat lehetővé téve. 25. ábra USB-TTL soros konverter kábel [14] 35
26. ábra A terminálon keresztül olvasott értékek Ahogy azt a képen is látni lehet, az eszköz megfelelően küldi az adatokat. 27. ábra Az eszköz teljesen bekötve 36
7. Összefoglalás Szakdolgozatomban cél volt egy egyszerű és felhasználóbarát eszköz megtervezése, gyártása, és tesztelése. Az eszköz tervezése során próbáltam könnyen hozzáférhető alkatrészeket használni. Ilyen például az eszköz lelke az ATTiny45 mikrovezérlő, amely olcsó, széles körben ismert és felhasznált. Az eszköz felhasználható, amire tervezték, azonban további felhasználási módokra is alkalmas lehet. Alkalmas lehet akár egy alagút világítására, amely érzékeli az alatta elhajtó járművet, így több ilyen érzékelővel a kocsit végig követve lehet a világítást vezérelni, vagy esetleg álló járművet jelezni. Egy ilyen szenzoros kapcsoló tervezése és gyártása sok tanulást és odafigyelést igényel, mint például a mikrovezérlő programozása vagy a NYÁK tervező szoftver használata. 37
8. Summary The goal of my thesis was to design, build and test a user-friendly and simple device. When designing the device, I tried to use easy to acquire parts. Parts, like the ATTiny45 mikrocontroller, which is the heart of the device and is cheap, easy to find and is widely known and used. The device is able to be used for what it was designed, but it has other uses too. It can be used to light a tunnel, which senses vehicles moving under it, so using more if this sensor, it can follow the movement of the vehicle, or sense a stillstanding automobile. Designing a sensor switch like this require a lot of learning and concentration, for example programming the MCU, and using the PCB designer software. 38
9. Irodalomjegyzék [1]: Kiss Zoltán: Mozgásérzékelés a gyakorlatban [ellenőrizve 2016.11.11] http://elektro-net.hu/konstruktor/6831-mozgaserzekeles-gyakorlatban [2]: Presence Detection using MEMS Thermal Sensor [ellenőrizve 2016.11.11]http://shukra.cedt.iisc.ernet.in/edwiki/Presence_Detection_using_MEMS_T hermal_sensor [3]: D203B datasheet [ellenőrizve 2016.11.11] http://www.micropik.com/pdf/d203b-e.pdf [4]: NJR4265 J1 datasheet [ellenőrizve 2016.11.11] http://www.endrich.com/fm/2308/datasheet%20njr4265_j1.490760.pdf [5]: Panasonic GridEYE datasheet [ellenőrizve 2016.11.11] http://www.endrich.com/fm/2308/grid%20eye%20datasheet.pdf [6]: Omron D6T datasheet [ellenőrizve 2016.11.11] http://www.omron.com/ecb/products/pdf/en-d6t.pdf [7]: ATTiny datasheet [ellenőrizve 2016.11.11] http://www.atmel.com/images/atmel-2586-avr-8-bit-microcontroller-attiny25-attiny45- attiny85_datasheet.pdf [8]: OKTEL ELEKTRONIKAI KFT. Mozgásérzékelők [ellenőrizve 2016.11.11] http://oktel.hu/szolgaltatas/riasztoberendezesek/mozgaserzekelok/a-passziv-infratipusai/ [10]: Omron G5LE-1 datasheet [ellenőrizve 2016.11.11] https://www.omron.com/ecb/products/pdf/en-g5le.pdf [11]: Nulláról a robotokig - PIC mikrovezérlők II rész [ellenőrizve 2016.11.11] http://www.hobbielektronika.hu/cikkek/nullarol_a_robotokig_- _pic_mikrovezerlok_ii_resz.html?pg=2 [12]: BC337 datasheet [ellenőrizve 2016.11.11] http://pdf.datasheetcatalog.com/datasheet/philips/bc337_3.pdf' [13]: http://www.robotshop.com/blog/en/files/software_6_atmelstudio.jpg [ellenőrizve 2016.11.11] [14]: http://www.tme.eu/html/gfx/ramka_7049.jpg[ellenőrizve 2016.11.11] 39
[15]: http://www.conrad.com/medias/global/ce/5000_5999/5000/5030/5038/503812_lb_00_ FB.EPS_1000.jpg [ellenőrizve 2016.11.11] [16]: http://i2c.info/wp-content/images/i2c.info/command.gif [ellenőrizve 2016.11.11] [17]: http://www.mouser.com/pdfdocs/d6t01_thermalirsensorwhitepaper.pdf [ellenőrizve 2016.11.11] 40
10. Ábrajegyzék 1. ábra A PIR érzékelő alapelve [1]...4 2. ábra A szenzor látótere[8]...5 3. ábra A duál infra két érzékelő eleme [8]...6 4. ábra A quad infra érzékelésésnek szemléltetése [8]...6 5. ábra Egy PIR szenzor elvi kapcsolása[1]...7 6. ábra Doppler effektus szemléltetése [1]...8 7. ábra GridEYE szenzor[1]...9 8. ábra GridEYE szenzor felbontása[1]... 10 9. ábra Az eszköz blokkdiagramja... 11 10. ábra Az Omron D6T-44L szenzor[2]... 12 11. ábra A szenzor látótere[2]... 12 12. ábra Az ATTiny45 lábkiosztása[7]... 13 13. ábra ATTiny45 blokkdiagram[7]... 14 14. ábra A szenzor és az ATTiny összekötése [17]... 15 15. ábra I2C kommunikáció folyamata [16]... 15 16. ábra A relé elvi kapcsolása[10]... 16 17. ábra A relé [15]... 16 18. ábra A BC337 grafikonja... 17 19. ábra Az eszköz kapcsolási rajza... 19 20. ábra Az eszköz NYÁK terve... 20 21. ábra Az eszköz nyitott dobozában... 20 22. ábra Atmel Studio használat közben... 21 23. ábra I2C kommunikáció kezdete... 34 24. ábra Adat olvasás utáni folyamatok... 35 25. ábra USB-TTL soros konverter kábel [14]... 35 26. ábra A terminálon keresztül olvasott értékek... 36 27. ábra Az eszköz teljesen bekötve... 36 41
Mellékletek 1. melléklet: main.c // A program egyes elemeit a következő programból szerkesztettem // I2C library using USI hardware support // Kenneth Finnegan, 2010 // kennethfinnegan.blogspot.com // https://gist.github.com/phirephly/747140 #include <avr/pgmspace.h> #include "softuart.h" #include <util/delay.h> #include <avr/io.h> #include <inttypes.h> #include <avr/interrupt.h> //Időzítések #ifdef I2C_FAST_MODE #define I2C_T1 2 // >1.3us #define I2C_T2 1 // >0.6us #else #define I2C_T1 5 // >4.7us #define I2C_T2 5 // >4.0us #endif // Bit és cím definiciók #define I2C_READ_BIT0 #define I2C_ADDR_BITS 1 #define I2C_NACK_BIT0 #define TRUE 1 #define FALSE 0 #define I2C_READ 1 #define I2C_WRITE 0 #define OMRON_R #define OMRON_W 0x15 // I2C address 0x14 // I2C address // Hibák #define I2C_ERR_NO_DATA #define I2C_ERR_DATA_OUT_OF_BND #define I2C_ERR_UE_START 0x03 #define I2C_ERR_UE_STOP #define I2C_ERR_UE_DATA_COL 0x05 #define I2C_ERR_NO_ACK_ON_DATA #define I2C_ERR_NO_ACK_ON_ADDR #define I2C_ERR_MISSING_START_CON 0x08 #define I2C_ERR_MISSING_STOP_CON 0x09 0x01 0x02 0x04 0x06 0x07 // IC port definiciók #define I2C_DDR #define I2C_PORT #define I2C_PIN #define I2C_SDA #define I2C_SCL #define OUT_PIN PORTB DDRB PINB PB0 PB2 PB3 //Globálisok 42
union I2C_state uint8_t errorstate; struct uint8_t addressbyte :1; uint8_t datadirection :1; uint8_t unused :6; ; I2C_state; //Függvény definiciók void I2C_init(void); uint8_t I2C_xfer(uint8_t *buffer, uint8_t length); //Privát függvény definiciók uint8_t I2C_byte_xfer(uint8_t reg); uint8_t I2C_gen_start(void); uint8_t I2C_gen_stop(void); void I2C_delay(uint8_t length) do _delay_us(1); while (--length); void I2C_init(void) //IO portok beállitása kimenetként felhúzó ellenállásokkal I2C_PORT = (1<<I2C_SDA) (1<<I2C_SCL); I2C_DDR = (1<<I2C_SDA) (1<<I2C_SCL); //SDA elengedése USIDR = 0xff; //USI Kétvezetékes módba való állítása (a címek rövidítése a fejlesztőkörnyezetben alapértelmezett USICR = (1<<USIWM1) (1<<USICS1) (1<<USICLK); //számláló nullázása USISR = (1<<USISIF) (1<<USIOIF) (1<<USIPF) (1<<USIDC) (0x0<<USICNT0); // A fő I2C függvény uint8_t I2C_xfer(uint8_t *buffer, uint8_t buflen) // USISR (USI State Register) állapot regiszter 8 bites kommunikációhoz uint8_t SR_8bit = (1<<USISIF) (1<<USIOIF) (1<<USIPF) (1<<USIDC) (0x0<<USICNT0); // USISR (USI State Register) állapot regiszter 1 bites kommunikációhoz uint8_t SR_1bit = (1<<USISIF) (1<<USIOIF) (1<<USIPF) (1<<USIDC) (0xE<<USICNT0); I2C_state.errorState = 0; I2C_state.addressByte = TRUE; #ifdef PARAM_VERIFY if (buffer > (uint8_t*)ramend) I2C_state.errorState = I2C_ERR_DATA_OUT_OF_BND; return FALSE; if (buflen <= 1) I2C_state.errorState = I2C_ERR_NO_DATA; return FALSE; 43
#endif if ((buffer[0] & (1<<I2C_READ_BIT)) == I2C_READ) I2C_state.dataDirection = I2C_READ; else I2C_state.dataDirection = I2C_WRITE; I2C_gen_start(); do if (I2C_state.addressByte (I2C_state.dataDirection == I2C_WRITE)) // Egy byte küldése az I2C buszon // SCL nullázása I2C_PORT &= ~(1<<I2C_SCL); //Adat regiszter betöltése USIDR = *(buffer++); I2C_byte_xfer(SR_8bit); while (--buflen); I2C_gen_stop(); // N/ACK nyugtázó jel fogadása I2C_DDR &= ~(1<<I2C_SDA); if (I2C_byte_xfer(SR_1bit) & (1<<I2C_NACK_BIT)) I2C_state.errorState = I2C_state.addressByte? I2C_ERR_NO_ACK_ON_ADDR : I2C_ERR_NO_ACK_ON_DATA; return FALSE; I2C_state.addressByte = FALSE; else // Byte fogadás // SDA beállítása mint bemenet I2C_DDR &= ~(1<<I2C_SDA); // Byte olvasása a buszról *(buffer++) = I2C_byte_xfer(SR_8bit); // Nyugtázó jel küldése USIDR = (buflen == 1)? 0xFF : 0x00; I2C_byte_xfer(SR_1bit); return TRUE; // Shift regiszter futtatása amíg a számláló túlcsordul // A függvény vissza állítja az SDA vonalat kimenetre uint8_t I2C_byte_xfer(uint8_t reg) USISR = reg; reg = (1<<USIWM1) (1<<USICS1) (1<<USICLK) (1<<USITC); do I2C_delay(I2C_T1); //Felfutó él 44
USICR = reg; //várakozás while (!(I2C_PIN & (1<<I2C_SCL))) ; I2C_delay(I2C_T2); //Lefutó él USICR = reg; while (!(USISR & (1<<USIOIF))); I2C_delay(I2C_T1); //Shift regiszter mentése reg = USIDR; // SDA elengedése USIDR = 0xFF; //SDA beállítása mint kimenet I2C_DDR = (1<<I2C_SDA); return reg; uint8_t I2C_gen_start(void) I2C_PORT = (1<<I2C_SCL); while(!(i2c_port & (1<<I2C_SCL))) ; #ifdef I2C_FAST_MODE I2C_delay(I2C_T2); #else I2C_delay(I2C_T1); #endif // Start jel generálása I2C_PORT &= ~(1<<I2C_SDA); I2C_delay(I2C_T2); I2C_PORT &= ~(1<<I2C_SCL); I2C_PORT = (1<<I2C_SDA); #ifdef SIGNAL_VERIFY if (!(USISR & (1<<USISIF))) I2C_state.errorState = I2C_ERR_MISSING_START_CON; return FALSE; #endif return TRUE; uint8_t I2C_gen_stop(void) // SDA nullázása I2C_PORT &= ~(1<<I2C_SDA); //SCL elengedése I2C_PORT = (1<<I2C_SCL); while(!(i2c_pin & (1<<I2C_SCL))) ; I2C_delay(I2C_T2); I2C_PORT = (1<<I2C_SDA); I2C_delay(I2C_T1); #ifdef SIGNAL_VERIFY if (!(USISR & (1<<USIPF))) I2C_state.errorState = I2C_ERR_MISSING_STOP_CON; return FALSE; #endif return TRUE; 45
uint16_t check[1]; uint16_t temp[16]; uint16_t tempstat[1]; int p = 0; int v = 0; int e = 0; int t = 0; int sz = 0; char f[6]; // A szenzor adatainak kiolvasása void downloadtemp(void) uint8_t buf[35]; buf[0] = OMRON_W; buf[1] = 0x4C; I2C_xfer(buf, 2); buf[0] = OMRON_R; I2C_xfer(buf, 35); tempstat[0] = 256*buf[2] + buf[1]; temp[0] = 256*buf[4] + buf[3]; temp[1] = 256*buf[6] + buf[5]; temp[2] = 256*buf[8] + buf[7]; temp[3] = 256*buf[10] + buf[9]; temp[4] = 256*buf[12] + buf[11]; temp[5] = 256*buf[14] + buf[13]; temp[6] = 256*buf[16] + buf[15]; temp[7] = 256*buf[18] + buf[17]; temp[8] = 256*buf[20] + buf[19]; temp[9] = 256*buf[22] + buf[21]; temp[10] = 256*buf[24] + buf[23]; temp[11] = 256*buf[26] + buf[25]; temp[12] = 256*buf[28] + buf[27]; temp[13] = 256*buf[30] + buf[29]; temp[14] = 256*buf[32] + buf[31]; temp[15] = 256*buf[34] + buf[33]; check[0] = buf[35]; int main(void) //A ATTiny beállítása softuart_init(); I2C_init(); sei(); while (1) downloadtemp(); v = 0; // Az adatok feldolgozása // Ha az érték meghaladja a küszöb értéket az eszköz a kimenetén 1 re vált // Így a relé bekapcsol for(p=1; p<16; p++) if (temp[p]>300) v = 1; if (v == 1) 46
PORTB = (1 << OUT_PIN); else PORTB &= ~(1 << OUT_PIN); // Az olvasott értékek átalakítása helyi értékekre való felbontása for(p=0; p<16; p++) e=temp[p] % 10 ; temp[p] -= e ; temp[p]=temp[p]/10 ; t=temp[p] % 10; temp[p] -= t ; temp[p]= temp[p]/10; sz=temp[p] % 10; f[3]=' '; f[2]=e +'0'; f[1]=t +'0'; f[0]=sz +'0'; //Az értékek kiküldése softuart_puts( f ); _delay_ms(1); // sortörés softuart_puts_p( "\r\n" ); _delay_ms(10); 47
2. Melléklet: softuart.c // Forrás: // Generic code from // Colin Gittins, Software Engineer, Halliburton Energy Services // https://github.com/blalor/avr-softuart/blob/master/softuart.c #include <avr/io.h> #include <avr/interrupt.h> #include <avr/pgmspace.h> #include "softuart.h" #define SU_TRUE 1 #define SU_FALSE 0 #define TX_NUM_OF_BITS (10) volatile static unsigned char flag_tx_busy; volatile static unsigned char timer_tx_ctr; volatile static unsigned char bits_left_in_tx; volatile static unsigned short internal_tx_buffer; #define set_tx_pin_high() ( SOFTUART_TXPORT = ( 1 << SOFTUART_TXBIT ) ) #define set_tx_pin_low() ( SOFTUART_TXPORT &= ~( 1 << SOFTUART_TXBIT ) ) ISR(SOFTUART_T_COMP_LABEL) unsigned char tmp; if ( flag_tx_busy == SU_TRUE ) tmp = timer_tx_ctr; if ( --tmp == 0 ) // Az kimenet vezérlése az adatnak megfelelően if ( internal_tx_buffer & 0x01 ) set_tx_pin_high(); // ha a bit 1 else set_tx_pin_low(); // ha a bit 0 internal_tx_buffer >>= 1; tmp = 3; if ( --bits_left_in_tx == 0 ) flag_tx_busy = SU_FALSE; timer_tx_ctr = tmp; static void io_init(void) SOFTUART_TXDDR = ( 1 << SOFTUART_TXBIT ); static void timer_init(void) unsigned char sreg_tmp; 48
sreg_tmp = SREG; cli(); SOFTUART_T_COMP_REG = SOFTUART_TIMERTOP; SOFTUART_T_CONTR_REGA = SOFTUART_CTC_MASKA SOFTUART_PRESC_MASKA; SOFTUART_T_CONTR_REGB = SOFTUART_CTC_MASKB SOFTUART_PRESC_MASKB; SOFTUART_T_INTCTL_REG = SOFTUART_CMPINT_EN_MASK; // számláló nullázása SOFTUART_T_CNT_REG = 0; SREG = sreg_tmp; void softuart_init( void ) flag_tx_busy = SU_FALSE; set_tx_pin_high(); io_init(); timer_init(); unsigned char softuart_transmit_busy( void ) return ( flag_tx_busy == SU_TRUE )? 1 : 0; void softuart_putchar( const char ch ) while ( flag_tx_busy == SU_TRUE ) ; timer_tx_ctr = 3; bits_left_in_tx = TX_NUM_OF_BITS; internal_tx_buffer = ( ch << 1 ) 0x200; flag_tx_busy = SU_TRUE; void softuart_puts( const char *s ) while ( *s ) softuart_putchar( *s++ ); void softuart_puts_p( const char *prg_s ) char c; while ( ( c = pgm_read_byte( prg_s++ ) ) ) softuart_putchar(c); 49
3. Melléklet: softuart.h //Forrás: //https://github.com/blalor/avr-softuart/blob/master/softuart.h #if!defined(f_cpu) #warning "F_CPU not defined in makefile - now defined in softuart.h" #define F_CPU 8000000UL #endif #define SOFTUART_BAUD_RATE 4800 #if defined ( AVR_ATtiny25 ) defined ( AVR_ATtiny45 ) defined ( AVR_ATtiny85 ) #define SOFTUART_TXPORT PORTB #define SOFTUART_TXDDR DDRB #define SOFTUART_TXBIT PB4 #define SOFTUART_T_COMP_LABEL #define SOFTUART_T_COMP_REG #define SOFTUART_T_CONTR_REGA #define SOFTUART_T_CONTR_REGB #define SOFTUART_T_CNT_REG #define SOFTUART_T_INTCTL_REG #define SOFTUART_CMPINT_EN_MASK TIM0_COMPA_vect OCR0A TCCR0A TCCR0B TCNT0 TIMSK (1 << OCIE0A) #endif #define SOFTUART_CTC_MASKA (1 << WGM01) #define SOFTUART_CTC_MASKB (0) #define SOFTUART_PRESCALE (8) #define SOFTUART_PRESC_MASKA (0) #define SOFTUART_PRESC_MASKB (1 << CS01) #define SOFTUART_TIMERTOP ( F_CPU/SOFTUART_PRESCALE/SOFTUART_BAUD_RATE/3-1) #if (SOFTUART_TIMERTOP > 0xff) #warning "Check SOFTUART_TIMERTOP: increase prescaler, lower F_CPU or use a 16 bit timer" #endif #define SOFTUART_IN_BUF_SIZE 32 void softuart_init(void); void softuart_puts( const char *s ); void softuart_puts_p( const char *prg_s ); #define softuart_puts_p(s ) softuart_puts_p(pstr(s )) 50