Budapesti Műszaki és Gazdaságtudományi Egyetem Villamosmérnöki és Informatikai Kar Elektronikai Technológia tanszék
Szokol Attila
MODULÁRIS FELÉPÍTÉSŰ VILÁGÍTÓRENDSZER TERVEZÉSE
KONZULENS
Dr. Berényi Richárd BUDAPEST, 2012
Tartalomjegyzék Összefoglaló ..................................................................................................................... 5 Abstract............................................................................................................................ 6 1
Bevezetés .................................................................................................................. 7
2
Piacon létező hasonló vezérlők............................................................................... 8
3
A feladathoz rendelkezésre álló eszközök........................................................... 10
4
5
6
3.1
Arduino MEGA platform................................................................................ 10
3.2
Atmel ATmega8 ............................................................................................. 11
Moduláris felépítés, kommunikációs formák..................................................... 12 4.1
SPI busz .......................................................................................................... 13
4.2
I2C busz........................................................................................................... 15
4.3
Kommunikációs formák összehasonlítása ...................................................... 17
Saját elképzelés bemutatása................................................................................. 18 5.1
Normál buszrendszerű verzió ......................................................................... 19
5.2
Daisy-chain verzió .......................................................................................... 20
5.3
Kimenet beállítása, PWM ............................................................................... 22
5.4
A PWM egység működése az Atmel ATmega8 AVR-ben:............................ 23
5.4.1
Normal Mode (normál mód)................................................................... 23
5.4.2
Clear Timer on Compare match (CTC mód) .......................................... 23
5.4.3
Fast PWM Mode (nagyfrekvenciás PWM mód) .................................... 24
5.4.4
Phase Correct PWM mode (fázishelyes PWM mód).............................. 25
Megvalósítás, tervezés .......................................................................................... 27 6.1
Tápellátás ........................................................................................................ 29
6.2
Kommunikációs, programozóhoz tartozó kivezetések ................................... 30
6.3
Mikrokontroller, illetve a működéséhez szükséges alapvető csatlakozások,
kiegészítők, valamint a kivezetései............................................................................. 31
7
6.4
Kimenet........................................................................................................... 31
6.5
Layout terv ...................................................................................................... 31
Programozás.......................................................................................................... 35 7.1
Közös funkciók ............................................................................................... 35
7.2
Normál buszrendszerű verzió ......................................................................... 38
7.2.1
Master ..................................................................................................... 38
7.2.2 7.3
Slave........................................................................................................ 40
Daisy chain verzió .......................................................................................... 43
7.3.1
Master ..................................................................................................... 43
7.3.2
Slave........................................................................................................ 45
8
Tesztelés, mérési eredmények.............................................................................. 48
9
Összegzés................................................................................................................ 53
Irodalomjegyzék............................................................................................................ 54 Mellékletek .................................................................................................................... 56
HALLGATÓI NYILATKOZAT
Alulírott Szokol Attila hallgató kijelentem, hogy ezt a szakdolgozatot meg nem engedett segítség nélkül, saját magam készítettem, csak a megadott forrásokat (szakirodalom, eszközök stb.) használtam fel. Minden olyan részt, melyet szó szerint, vagy azonos értelemben, de átfogalmazva más forrásból átvettem, egyértelműen, a forrás megadásával megjelöltem. Hozzájárulok, hogy a jelen munkám alapadatait (szerző(k), cím, angol és magyar nyelvű tartalmi kivonat, készítés éve, konzulens(ek) neve) a BME VIK nyilvánosan hozzáférhető elektronikus formában, a munka teljes szövegét pedig az egyetem belső hálózatán keresztül (vagy hitelesített felhasználók számára) közzétegye. Kijelentem, hogy a benyújtott munka és annak elektronikus verziója megegyezik. Dékáni engedéllyel titkosított diplomatervek esetén a dolgozat szövege csak 3 év eltelte után válik hozzáférhetővé. Kelt: Budapest, 2012. 12. 07.
...……………………………………………. Szokol Attila
Összefoglaló A szakdolgozat során a feladatom az volt, hogy megismerjem a moduláris felépítésű vezérlők felépítéseit, működési, vezérlési módjaikat, valamint ezek alapján meg kellett terveznem egy prototípus szintű hálózatot világítás vezérlésének céljából. A hálózatnak modulokból, vezérlőből, és vezérelt eszközökből kell összeállnia, a lényegesebb szempontok között a kis helyigény, valamint a rugalmasan, dinamikusan változtatható, bővíthető hálózat szerepeltek. A feladat végrehajtása során megismerkedtem az Arduino nyílt platformmal, valamint betekintést nyerhettem az AVR mikrokontrollerek felhasználási lehetőségeibe, alkalmazástechnikájába. A vezérlőprogramot mind a vezérlő, mind a vezérelt eszközhöz nekem kellett megírni, ezért az Arduino, és az Atmel Studio fejlesztőkörnyezet használatát is el kellett sajátítanom. A tervezés és a megvalósítás közben tanulmányoznom kellett a hálózat elemei között létrehozható kommunikációs formák lehetőségeit, egymáshoz képesti előnyeiket, hátrányaikat, korlátaikat, részletesen megismerve az SPI, és I2C buszok működését. A megvalósításhoz kiválasztott SPI buszra saját kommunikációs protokollt kellett létrehoznom, hogy lehetőség legyen szoftveres címzésre. A dolgozat sikeres végrehajtásához meg kellett terveznem a vezérelt egységet, melyhez meg kellett ismerkednem az EAGLE layout editor programmal, amiben lehetőségem volt kétrétegű nyomtatott huzalozású lemezt tervezni, majd legyártatni, összeszerelni, aminek folyamán kézi pick&place és gőzfázisú forrasztó berendezést is használtam.
Abstract The task of my thesis was to study the structure, working and communication methods of various modular home automation systems and to plan and build a modular lighting control system similar to them, based on the acquired informations. My system has to have a controller, and many controlled appliances, which we can control separately. The following directives were considered during the planning phase: -
The controlled units must be relatively small
-
The created network must be capable of controlling units added later to the network, without major rewiring During the planning and materializing I had to learn about the Arduino open
source electronic prototyping platform, and the usage of AVR microcontrollers. I had to make programs for both platforms, thus I had to acquire basic programming knowledge for both the Arduino’s, and Atmel’s development environment. Also I had to study various forms of communication methods which i could use to connect the units, and learn about their downsides and advantages compared to each other, mainly about SPI and I2C buses. For implementation I chose the SPI bus, but I had to customize it, and design a simple communication protocol for it, to make it able to work with software addresses. To reach the goal of my thesis, I also had to design the whole circuit. I used EAGLE layout editor, where I had the opportunity to design a two sided PCB on my own, which was sent into production. During the assembly procedure I used manual pick&place, and vapour phase soldering appliances.
6
1 Bevezetés A szakdolgozatom egy igen aktuális témával foglalkozik, az úgynevezett „Smart Home”, vagy magyarosan az okos, automatizált otthonok témaköréhez kapcsolódik. A Smart Home kifejezés még csak most kezd a köztudatba kerülni, alatta olyan központi vezérlést értünk, amivel akár az otthonunktól távolról is irányíthatunk bármilyen a hálózatba bekötött, automatizált eszközt, például nyithatunk/zárhatunk ablakokat, berendezéseket kapcsolhatunk ki/be, szellőzést, fűtést szabályozhatunk teljesen automatikusan, előre beprogramozott módon, vagy mint a szakdolgozatom témája is mutatja, világítást is vezérelhetünk vele. A Smart Home rendszer lényege a moduláris felépítés, azaz, hogy egyetlen központi vezérlő egységgel egy sor további berendezést tudunk irányítani, vagy automatizálni (például ha nem vagyunk otthon, vagy ha szellőztetünk, és kinyitjuk az ablakot a fűtést automatikusan lejjebb lehet venni), mindezt egy helyről. A szakdolgozatom célja is egy ilyen moduláris rendszer létrehozása világítás szabályozás céljára. A szakdolgozat keretén belül csak a központilag irányítható, egyénileg vezérelhető világítás szabályozó rendszer megtervezése, és megvalósítása, valamint a számítógépes vezérlőprogrammal történő interakciójának megtervezése volt a cél egy pár, egyéb funkció megvalósításával (programba történő visszaolvasás, beállítások elmentése nem illanó memóriába).
7
2 Piacon létező hasonló vezérlők A szakdolgozatomat a már létező, hasonló célú vezérlők megismerésével, működésük, kommunikációs fajtáik feltérképezésével kezdtem. A kifejezetten világítás vezérlő rendszerek általában valamilyen fajta irodaépületekben, színházakban, vagy külső, díszvilágítást alkalmazó épületekben találhatóak meg. Ezeket a rendszereket valamilyen beágyazott rendszerek, ipari irányító berendezések vezérlik, amikhez egy vagy több hordozható, vagy rögzített beviteli egység (billentyűzet, touchscreen) tartozik, de létezhet okostelefonra írt irányító szoftver is hozzájuk. [10] A fogyasztói piacra szánt termékek is moduláris felépítésűek, általában egy központi vezérlő egységből állnak, amire PC-vel, és/vagy okostelefonnal lehet csatlakozni, majd ez továbbítja valamilyen vezeték nélküli csatornán a parancsokat az egyes vezérelt berendezéseknek. A vezérelt eszközök kaphatóak készen is, direkt az adott vezérlőhöz készítve, de megtalálhatóak egyszerű hálózati konnektorba dugható egységek is, amelyeket távolról lehet ki, illetve bekapcsolni. Példák ilyen termékekre: -
INSTEON: o USB vezérlő PC alapú vezérléshez: [14] o Wi-Fi-s vezérlő okostelefonnal történő vezérléshez: [15] o Kifejezetten a vezérlőhöz tervezett irányítható lámpatest: [16] o Általános ki/be kapcsoló modul: [17]
-
X10: o PC adó/vevő vezérlő egység, külön hálózati aljzatba illeszthető egységek: [18] Sajnos az üzleti érdekek miatt, ezekről a berendezésekről csak azt lehet tudni,
hogy valamilyen rádiófrekvenciás alapú kommunikációt valósítanak meg, a részletek nem ismertek. Ezeknek a kész termékeknek az előnye, hogy bárki, szaktudás nélkül is pillanatok alatt összeállíthat, és beépíthet egy komplett vezérelhető hálózatot, hátrányuk viszont, hogy mivel nem nyílt rendszerűek, kevésbé testre szabhatóak, egyes speciális igényeknek nem biztos, hogy meg tudnak felelni. 8
Léteznek direkt okos otthonhoz kitalált vezeték nélküli hálózatok, amelyek a segítségünkre lehetnek, ha mi magunk szeretnénk megtervezni a vezérlő egységeket, ilyenekre példa: -
ZigBee [11],[12] o A ZigBee egy magas szintű kommunikációs protokoll specifikáció, amit leginkább az alacsony fogyasztási igényeknek megfelelően terveztek. A hálózat ad-hoc felépítésű, azaz decentralizált, a hálózat tagjainak nem kell közvetlen összeköttetésben állniuk, az üzenetek több átjárón is keresztül mehetnek, így érik el egymást a legtávolabbi csomópontok.
-
Z-wave [13] o A Z-wave kommunikációs protokollt kifejezetten az okos otthonok igényeit szem előtt tartva tervezték. Ennek megfelelően alacsony fogyasztású, megbízható, kis késleltetésű, kis méretű adatcsomagok forgalmazására fejlesztették ki, valamint a 900MHz-es sávot használja, ezzel elkerülve a 2,4GHz-es amúgy is telített (Bluetooth, Wifi is ezen működik), szabad sávot.
9
3 A feladathoz rendelkezésre álló eszközök A feladat elkészítéséhez a konzulensem egy Arduino MEGA fejlesztő platformot biztosított, valamint javasolta az Atmel ATmega8 típusú mikrokontroller használatát.
3.1 Arduino MEGA platform Az Arduino MEGA nyílt hardveres fejlesztő platform, mely könnyen összeállítható, vagy készen is megvásárolható, és egy nyílt forrású, szabadon letölthető fejlesztőkörnyezet is jár mellé. Az áramkör lényegében egy Atmel ATmega1280-as típusú 8 bites mikrokontrollert, illetve a működéséhez minimálisan szükséges alkatrészeket tartalmazza. A platform lényege, hogy a mikroprocesszorba egy előre megírt programot, úgynevezett „bootloadert” töltöttek, ezért külön programozó használata nélkül, az egyébként kommunikációra használt soros porton keresztül is feltölthetjük rá a saját programunkat. A bootloader soha nem íródik felül, így bármit is teszünk, lényegében mindig képesek leszünk kommunikálni az eszközzel, elrontott program esetén is újra fel tudjuk programozni azt. A bootloaderen kívül a fejlesztőkörnyezet is segíti a munkánkat, a kivezetések elnevezése egyezik az aktuális board kivezetéseinek számozásával, előre megírt példaprogramokat találhatunk benne, automata formázási segédletet biztosít, ellenőrizhetjük, feltölthetjük vele a programunkat, valamint soros konzol monitort is biztosít, amivel parancsokat küldhetünk, vagy információkat írathatunk ki az Arduinoval valós időben. A fejlesztőkörnyezet segítségével a programozás magas szinten történhet, nem kell alacsony szintű, hardverközeli kóddal bajlódnunk. Az Arduino MEGA az Arduino termékcsalád fejlettebb, nagyobb tagjai közül való, hiszen az ATmega 1280 mikroprocesszorban a többi Arduino boardhoz képest sok memória (mind program, mind SRAM) és integrált periféria (számláló, PWM, ADC, komparátor), valamint kivezetés található.
10
3.2 Atmel ATmega8 A konzulensem a feladat sikeres végrehajtásához az ATmega8-as típusú, Atmel gyártmányú, az AVR termékcsaládba tartozó mikrokontrollert javasolta. Ez egy 8 bites, Harvard architektúrájú, RISC (Reduced Instruction Set Computer, csökkentett utasításkészletű
számítógép)
utasításkészletű
mikrokontroller.
A
feladatom
szempontjából főbb tulajdonságai: [1] -
130 féle utasítás (a legtöbbje 1 órajel alatt végrehajtódik)
-
32 x 8 általános célú regiszter
-
akár 16 MIPS teljesítmény 16 MHz-es működési frekvencián
-
8KB belső, flash alapú program memória
-
512B EEPROM (adatok tárolására)
-
1KB SRAM
-
2db 8bites számláló
-
1db 16bites számláló
-
3 PWM csatorna
-
I2C interfész
-
programozható soros interfész
-
Master/Slave SPI interfész
-
Külső, és belső megszakítási források Az adatokból tehát látható, hogy ez a mikrokontroller bőven rendelkezik még
tartalékokkal, a szükséges hardverelemeken felül is lesznek még kihasználatlan erőforrásai. A moduláris felépítésű világítás szabályozó slave-jeként minimálisan egy PWM csatorna, a hozzá tartozó számlálóval, illetve egy kommunikációs interfész szükséges.
11
4 Moduláris felépítés, kommunikációs formák A moduláris felépítés azt jelenti, hogy a teljes rendszerünk különálló, önmagában egy egységet képviselő alkotóelemekből, úgynevezett modulokból áll össze. Az én témámnál a moduláris felépítés úgy képzelhető el, hogy van egy központi vezérlőegység, és több, különálló vezérelt egység. A vezérlő egység (master) az Arduino lesz, a vezérelt egységet (slave) nekem kell megterveznem. A vezérlő és a vezérelt egység között valamilyen módon kommunikálni kell. A feladathoz egyszerű parancsok átvitele kell, ezért a legegyszerűbb kommunikációs formák is megfelelőek, például: - vezeték nélküli - IR (Infra Red, infravörös) - Bluetooth - ZigBee - RF (Radio Frequency, rádiófrekvenciás) - vezetékes - SPI (Serial Peripherial Interface bus) - I2C (Inter-Integrated Circuit) - CAN (Controller Area Network) - RS232 (Point-to-Point, nem lehet multi-slave) - RS485
Megvalósításra
az
egyszerűség,
olcsóság
(nem
kellenek
külön
moduláramkörök), és a feladat alapjául szolgáló Arduino eszköz, valamint az ATmega8 képességei miatt a vezetékes megoldásokat vizsgáltam. A CAN busz használatáért licenszdíjat kell fizetni a Robert Bosch GmbH-nak [3], az RS232 pedig Point-to-Point rendszerű, így nem lehet vele multi-slave rendszert építeni. Az RS485 használatához külön IC lenne szükséges, mivel az üzemi feszültségszintjei kívül esnek a
12
mikrokontroller által toleráltakon, így lényegében az I2C-re, és az SPI-ra szűkült a választási lehetőség.
4.1 SPI busz Az SPI busz egy szinkron soros kommunikációs busz, amelyet a Motorola nevezett el (a National Semicondustors által fejlesztett Microwire utódjaként lehet rá tekinteni)[2]. A rá kapcsolódó eszközök master/slave üzemmódban kommunikálhatnak rajta, amely üzemmódok nem felcserélhetőek, az egyes vezetékeken csak egy irányban folyhat kommunikáció. Az SPI busz működéséhez 4 vezeték szükséges: -
MOSI (Master Out – Slave In), amely a slave-nek küldött információt továbbítja
-
MISO (Master In – Slave Out), amely a slave-től a master felé küldött információt továbbítja
-
SCK (Serial ClocK), amely az adatforgalmazás ütemezéséért és a szinkronitásért felel
-
SS (Slave Select), amivel a master a kiválasztja, hogy melyik salve-nek küldi az adatot
1. ábra Egyszerű SPI vezetékezés [2]
Az SPI-hoz kapcsolódó érdekesség, hogy itt a vezetékeket nem kell keresztbe kötni, a master MOSI kivezetését a slave, szintén MOSI jelölésű bemenetére kell csatlakoztatni. Azoknál az eszközöknél, amelyek mindkét üzemmódban, tehát masterként, és slaveként is tudnak üzemelni (mint például az ATmega8), szoftveres beállítástól függ, hogy az adott láb kimenetként, vagy bemenetként fog viselkedni. Az SPI busz egy ún. de facto szabvány, ami azt jelenti, hogy hivatalosan nem tekinthető szabványnak, bizonyos funkciói, megoldásai nem rögzítettek, emiatt elég nagyfokú szabadságunk van azt a saját felhasználási igényeinknek leginkább megfelelő módon alakítani. A jelenleg készen kapható, SPI képes eszközök között is különbségek 13
vannak a velük való kommunikáció során, így általában a mastert kell úgy kialakítani, illetve programozni, hogy a slave által elvárt jelformákat és sebességet szolgáltassa. Az egyes SPI implementációk között a fő különbség az órajel vezeték (SCK) alapállapotában, illetve a mintavételezés ütemezésében áll. A Motorola ennek megfelelően négy különböző SPI módot különböztet meg. Az órajel polaritását CPOL (Clock POLarity)–lal, a mintavételezés felfutó vagy lefutó élre történő ütemezését pedig CPHA (Clock PHAse)-val jelöli.[4] MÓD
CPOL
CPHA
0 1 2 3
0 0 1 1
0 1 0 1
1. Táblázat SPI módok
2. ábra Különböző SPI módok időzítési diagramja [2]
Az SPI busz belső adatforgalmazása a szabvány szerint nem tesz említést az eszközök megcímzéséről, ezt egy külső jellel, a Slave Select vonallal végzik a címzést, ami így minden eszköz számára egyedi kell legyen a mastertől. Így alapesetben a slaveek számával növekszik a szükséges vezetékek száma is. A szabvány a címzést ugyan nem definiálja, de nem is tiltja, a küldött adatok lehetnek akár címek is. Az adatok helyes értelmezéséről (adat, cím szétválasztásáról) ilyenkor szoftveres úton kell gondoskodni. Egy másik lehetséges mód, hogy több slave esetén se emelkedjen a szükséges vezetékszám, ha az eszközöket láncszerűen, úgynevezett daisy-chainbe felfűzzük. 14
Ilyenkor a SS vonal is közös lesz, az egész gyűrű pedig n slave esetén egy n+1 méretű shift regiszterként modellezhető.
3. ábra SPI daisy chain
A master a küldött adatot az első slave-be lépteti, amely a következőnek küldi, és így tovább, míg a sorban utolsó slave visszalépteti az adatot a masterbe. Ilyenkor a kommunikáció jelentősen hosszabb ideig tarthat, hiszen ha pl. az utolsó slave-et címezzük, akkor végig kell léptetni a láncban előtte található összes eszközön. Ha szeretnénk ellenőrizni is, hogy a megcímzett slave helyes adatot kapott-e, akkor minden esetben végig kell léptetni az összes adatot az összes eszközön, amíg vissza nem ér minden a masterbe, ami össze tudja hasonlítani az elküldött információval. Ha a kettő egyezik, a kommunikáció során nem lépett fel hiba. Az SPI busz hiányosságaként említhető egyébként, hogy nincsenek benne az adatátvitelt vezérlő jelek, illetve azt sem jelzi, hogy a megcímzett eszköz rendben megkapta-e az üzenetet. Így tehát előfordulhat az az eset is, hogy a master eszköz úgy küldi az adatokat, hogy esetleg a másik végén nincs is slave, vagy a kommunikáció során valamilyen hiba (zaj, szakadt kábel) keletkezik, és ezt a master nem is érzékeli.
4.2 I2C busz Az I2C buszt a Philips fejlesztette ki azzal a céllal, hogy alacsony bitrátájú perifériákat kapcsolhassanak össze egy multi-master, illetve multi-slave képes, kevés vezetéket igénylő buszrendszerrel. Az I2C mindössze két vezetéket igényel, egy SDA (Serial Data Line, soros adatvonal) és egy SCL (Serial CLock, soros órajel) elnevezésűt, melyeken mindkét irányban folyhat adatforgalom. Mivel az SPI-al ellentétben itt csak egyetlen adatvezeték van, ezért itt a kommunikáció half-duplex jellegű, azaz egyszerre csak egy irányban történhet adatáramlás. A buszra kapcsolódó eszközöknek mind nyitott kollektoros kivezetésűeknek kell lenniük, a busz vezetékeit pedig felhúzó ellenállásokkal, tipikusan 5, illetve 3,3V-ra kell kötni. Ez azt jelenti, hogy a buszon lévő 15
eszközök vagy lebegtetik a vonalat, ami ilyenkor a magas feszültségszintet veszi fel, vagy földre húzzák.
4. ábra I2C topológia [5]
Mivel az I2C nem használ külön vezetékezést az egyes slave eszközök kiválasztására, a címzést is az adatvonalak segítségével oldották meg. A szabvány szerint 2 fajta, 7 bites és 10 bites címzés lehetséges. A megcímzett eszköz egy ACK (acknowledged) bittel válaszol, ha vette a saját címét, és készen áll az adatok fogadására, vagy küldésére. Mindig a master dönti el, hogy éppen adatot szeretne küldeni a címzettnek, vagy adatot kér tőle, ezt a cím után álló W/R (write / read) bittel jelzi. Tekintsünk egy egyszerű példát:
5. ábra I2C kommunikáció példa
A master kommunikációs szándékát egy START bittel (S) jelzi. A START bit olyan különleges bit, amikor az órajel változatlan magas értéke mellett az adatvonal alacsony értékűre vált. Ezután a master elkezdi generálni az órajelet, és kiküldi a 7 bites címet, a végén pedig a R/W bitet, amivel jelzi, hogy adatot fog-e küldeni, vagy adatot szeretne kérni a címzettől. Ha a megcímzett slave felismerte a saját címét, és készen áll
16
az adatok küldésére, vagy fogadására akkor küld egy ACK bitet, ami aktív alacsony (ez a busz nyitott kollektoros mivolta miatt van, ha ugyanis például nem létezne az adott című slave, vagy valamilyen hiba volt a kommunikáció során, akkor a slave nem válaszol, tehát lebegteti a vonalat, ami így magas értékű maradna). Ezután a R/W bittől függően a master órajelének megfelelően a master, vagy a slave küldi az adatot a buszra, amit minden 8. bit után a másik fél egy ACK bittel nyugtáz. A kommunikáció végül egy STOP bittel (P) zárul, ami hasonlóan a START bithez, egy speciális körülmények között előálló bit, az órajel magas éréke közben vált az adatvonal alacsonyból magas értékűre. [5],[6]
4.3 Kommunikációs formák összehasonlítása A fentiek áttekintése után egy rövid táblázatban szeretném összefoglalni a főbb különbségeket, előnyöket és hátrányokat a feladatom szempontjából. A táblázatba belevontam az RS485-öt is, mivel ugyan külön buszmeghajtó IC kellene hozzá, de használatához
nem
szükséges
licenszdíjat
fizetni,
valamint
a
hatótávja
nagyságrendekkel nagyobb, mint a fentebb taglalt megoldásokénak, amelyeket leginkább egyetlen nyomtatott áramkörön belüli felhasználásra terveztek.
Szükséges vezetékek száma:
SPI I2C 3 + slave select 2 vonal(ak)
RS-422/RS-485 2 (half duplex) 4 (full duplex)
~7,6m [7], illetve Max. hatótáv:
5-10m
400pF max.
1200m
buszkapacitás Feszültség szintek:
0 - 5V
0 - 5V
-7 - 12V
Max. sebesség:
Akár 100Mbit/s
3,4Mbit/s
10Mbit/s
2. Táblázat Vezetékes buszok összehasonlítása
Az egyszerűbb implementálás (nincsenek kötött szóhosszok, ACK üzenetek) és a szabadabb alakíthatóság miatt az SPI protokollt választottam.
17
5 Saját elképzelés bemutatása
6. ábra Moduláris felépítés
A feladat elkészítéséhez fő vezérlőegységként (master) egy Arduino MEGA alaplapot kaptam. A feladatom ennek megfelelő felprogramozása, valamint a slave-ek megtervezése, és hozzájuk tartozó program megírása. A slave-ek megtervezéséhez Atmel ATmega8 típusú mikrokontrollerek voltak elérhetőek, így e köré építettem meg a szükséges áramkört. Az ATmega8-ban minden megtalálható, ami a feladat elvégzéséhez szükséges: - támogatja az SPI kommunikációt mind master, mind slave üzemmódban - hardveres PWM támogatás Sajnálatos módon az SPI, illetve a PWM funkciójú lábak kötöttek, azokat más kivezetésekre áthelyezni nem lehet, és a két funkció nagyrészt átfedi egymást, így SPI használata mellett egyetlen szabad PWM kivezetés marad. Ez a jelen feladathoz elegendő, de a későbbi fejlesztéseket (több vezérelt csatorna, esetleg RGB ledek vezérlése) hátrányosan érinti. A feladat során úgy terveztem meg az áramkörömet, hogy a fentebb említett mindkét fajta SPI kommunikációt (hagyományos busz rendszerű, illetve daisy chain)
18
meg lehessen valósítani, és azok között jumperekkel lehessen választani. A két eltérő működéshez két különböző program szükséges, illetve egyes tulajdonságaikban is különböznek, ezért külön alfejezetben mutatom be mindkét verziót.
5.1 Normál buszrendszerű verzió Áttekintés, tervezési vezérelvek: -
belső címzés, ne kelljen egyesével SS-elni őket
-
fix címek
-
az egyes egységek szabadon eltávolíthatóak, deaktiválhatóak, a többi működőképes marad
7. ábra Normál buszrendszerű SPI kommunikáció szoftveres címzéssel
A normál buszrendszerű verzióban minden eszköz közvetlen kapcsolódik a buszra. Mivel a feladat megköveteli az egyes eszközök egyéni vezérelhetőségét, mindenképpen valami módon címezni kell az eszközeinket. Az SPI erre a SS jelet használja, de ennek minden eszköz számára dedikált kell, hogy legyen, ami azt jelenti, hogy a vezérelt eszközök számával egyenes arányban nő a szükséges vezetékek száma is, illetve a vezérlőegységnek is egyre több kivezetését foglalja le ez a funkció. Nyilvánvaló, hogy ez a megoldás itt nem célravezető, elveszik az univerzális bővíthetőség, átkonfigurálás lehetősége, illetve a vezérlőszoftvert is minden változtatás 19
esetén újra kellene írni, fordítani. Emiatt másik megoldást választottam. A külső, hardveres címzés helyett, a belső adatbuszon keresztül címezzük meg a slave-eket. Mivel az SPI alapesetben nem kezeli a szoftveres címeket, így egy saját, egyszerű kommunikációs protokollt kellett terveznem. A feladatból kifolyólag, ha a kommunikáció során hiba lép fel, az nem kritikus, így a hibadetektálással, hibajavítással nem foglalkoztam, az adatok elküldése egyszerűen két lépcsőből áll. Első lépésként egy címet küldünk el, majd egy adatot. Minden slave megkapja mindkét információt, de a második csomagot mindegyik figyelmen kívül hagyja, kivéve a megcímzett eszköz. Ennek a megoldásnak a hátránya, hogy az SPI busz nem alkalmas nagy távolságok áthidalására, működésének feltétele a busz kellően alacsony kapacitása. Ez egyrészt a buszra kapcsolt eszközök számával is nő, másrészt a távolsággal is, így esetenként repeaterek/buszerősítők használata is szükséges lehet. További hátránya, hogy az egyes eszközök címét egyesével, a felprogramozás fázisában kell beállítani és figyelni kell a címek egyediségére, így a programot mindig újra kell fordítani. Másfelől ez lehet akár előny is, hiszen az egyes eszközök mindig ugyanarra a címre hallgatnak, további eszközök buszra kapcsolásával, vagy a rendszer átkonfigurálásával ez nem változik, és a számítógépen futó vezérlőprogramban fix neveket adhatunk nekik. További jó tulajdonsága ennek a megoldásnak, hogy az egyes eszközök meghibásodása, vagy tápfeszültség kimaradása esetén a többi üzemképes marad, a busz működésében nem lép fel zavar.
5.2 Daisy-chain verzió Áttekintés, tervezési vezérelvek: -
belső címzés
-
dinamikus címek (fix cím is lehet)
-
mindnek működnie kell, különben megszakad a gyűrű
A gyűrűs rendezésű verzióban szintén szoftveres úton gondoskodunk az egyes eszközök címzéséről, de itt lehetőségünk van a címek dinamikus, bekapcsoláskor történő kiosztására. Ez megkönnyítheti a slave-ek felprogramozását, hiszen változtatás
20
nélkül ugyanúgy kell felprogramozni őket, a címeket később, futás közben kapják meg. A dinamikus címzéshez egy bekapcsolás utáni, egyszer lefutó algoritmust dolgoztam ki:
8. ábra A master program blokkdiagramja SPI daisy chain, és dinamikus címzés esetén
A master lehúzza a Slave Select jelet, majd kiküld egy speciális byte-ot, amit az egyszerű címzés miatt „255” értékűnek definiáltam. Amikor a slave-ek ezt először megkapják, tudják, hogy a következő byteok címek sorozata lesz. A master a speciális byte után elkezdi kiléptetni a címeket szépen sorban, egészen addig amíg vissza nem kapja a 255-öt. Ha visszaért a konfiguráló byte, akkor a master tudja, hogy a kiküldött byte-ok rendben végigértek a gyűrűn, és most minden slave soros adatregiszterében egy egyedi szám található. Ekkor a master felhúzza a SS vonalat, a slave-ek pedig ebből tudják, hogy a címek kiosztása befejeződött, a náluk lévő szám lesz ezentúl a címük (a következő újraindításig), a master pedig tudja hány eszköz van a körben. Innentől kezdve az adatok átvitele hasonlóan történik mint a normál buszrendszerű verziónál, az első kiküldött byte egy cím lesz, az azt követő a beállítandó érték. Eltérés azonban, hogy itt eltérő mennyiségű transzferrel érjük csak el az egyes eszközöket. Erre egyszerű megoldást jelenthet, ha egyszerűen az egész körön végigléptetjük az összes adatot, így mindegyik eszköz meg fogja kapni az összes byteot. A master onnan tudja, hogy végigléptette az egész gyűrűt, hogy visszakapja az elsőre kiküldött adatot, vagyis a címet.
21
Ennek a megoldásnak az előnye, hogy az egyes eszközök mintegy buszerősítőként működnek, minden slave a beérkezett adatot a következő transzferben újra elküldi, így nagyobb távolságok is áthidalhatóak, de a Clock jelvezeték, illetve a visszatérő, Master In vonal is erősítetlenül halad végig a két végpont között. Előnyként említhető továbbá, hogy mindkét címzési eljárás működik ebben a rendszerben, hátránya viszont minden egységnek folyamatosan működnie kell, meghibásodás, tápfeszültség hiány, vagy bármilyen szakadás esetén az egész hálózat működésképtelen lesz.
5.3 Kimenet beállítása, PWM Az előző részekben leírtam, hogy hogyan tervezem átvinni az adatokat, és hogyan címzem meg egyesével a slave-eket. Most bemutatom, hogy hogyan dolgozza fel a fogadott adatokat. A mikrokontroller kivezetésein csak alacsony (0V), illetve magas (5V) jelszintet képes előállítani, így szabályzásra alapesetben nem alkalmas, legfeljebb kapcsolgatásra. Kihasználva viszont az emberi szem tehetetlenségét, ha elegendően gyorsan kapcsolgatjuk a kimenetet, akkor úgy tűnhet, mintha a fényforrásunk folyamatosan világítana, csak épp halványabban, mint ha folyamatosan be lenne kapcsolva. Hasonló ez ahhoz, ahogyan a mozifilmeknél, vagy a hagyományos katódsugárcsöves megjelenítőknél a mozgás illúzióját keltik az egyes képkockák gyors váltogatásával. Ezt a gyors kapcsolgatást megvalósíthatjuk szoftveres úton, de ez nem előnyös, mert ilyenkor az egész mikrokontroller ennek az elvégzésével lesz elfoglalva, ha bármi történik közben, pl. az SPI buszon egy parancs érkezik, akkor az vagy késleltetve lesz feldolgozva, vagy a kimenet nem fog megfelelően állítódni a parancs feldolgozása alatt, így egy villanást lehetne látni. A mikrokontrollerek alkalmazásánál gyakran merül fel hasonló igény, ezért ezt a funkciót nagyon sok mikrovezérlőbe külön részegységként beleintegrálták. Az általam használt ATmega8 kontrollerben két teljesen függetlenül működő ilyen modul is van, ezek a PWM (Pulse Width Modulation) modulok. A PWM modulokkal időzíteni, különböző frekvenciákat előállítani is lehet, illetve mint esetünkben, egy aluláteresztő szűrővel egyszerű DAC–ként (Digital to Analog Converter) is használható. Sajnálatos módon az ATmega8-ban, a PWM-re használt kivezetések nem áthelyezhetőek, és átfedik egymást az SPI kommunikációra használt lábakkal, így egyetlen szabad PWM csatorna marad, a Timer1-es egységhez tartozó OC1A, így a következőkben ennek működését fogom bemutatni.
22
5.4 A PWM egység működése az Atmel ATmega8 AVR-ben: A PWM modul gyakorlatilag egy 8, illetve 16 bites számláló, egy sor hasznos kiegészítéssel. Megadható neki, hogy merre számoljon, hogy csak abba az irányba, vagy a két végpontja között felváltva lefele/felfele számoljon, hogy meddig számoljon, a számolás frekvenciája (akár egy külső frekvenciaforrásról is), illetve egy konstans, amivel ha éppen egyezik a számláló értéke, akkor megszakítás, újrakezdés (számláló törlése), vagy egy kivezetés bekapcsolása történhet. Az általam használni kívánt Timer1 egy 16 bites számláló, és a következő működési módokat támogatja:
5.4.1 Normal Mode (normál mód) Ebben a működési módban a számláló mindig felfelé számlál, a számláló értéke soha nem törlődik, csak túlcsordul. A túlcsordulást egy bit (TOV1, Timer1 OVerflow) jelzi a TIFR (Timer Interrupt Flag Register) regiszterben, amit, mint a regiszter neve is mutatja, megszakításkérésre is lehet használni. Ezt a módot tehát leginkább időzítésre, valamilyen utasítás rendszeres időközönkénti végrehajtására, például egy regiszter értékének lekérdezésére lehet használni.
9. ábra Normál mód
5.4.2 Clear Timer on Compare match (CTC mód) Ebben a működési módban is felfelé számol a számláló, de egy előre beállított értéknél, amit az OCR1A (Output Compare Register timer1 channel A), vagy ICR1 (Input Capture Register timer 1) regiszterbe programozunk, a számláló értéke törlődik. Ezt a beállítást tehát belső órajelről hajtva különböző frekvenciák generálására használhatjuk, külső impulzusokról hajtva (ICP1 láb) pedig külső eseményeket tudunk egyszerűen számlálni, majd a beállított érték után megszakítást kérni.
23
10. ábra CTC mód [1]
5.4.3 Fast PWM Mode (nagyfrekvenciás PWM mód) Ebben a működési módban nagyfrekvenciás PWM jelformákat tudunk generálni. A számláló felfelé számol, majd ha elérte a maximumot túlcsordul, és kezdi előről. A kimenetet két ponton állítja be, egyszer a számlálás elején (0 érték), egyszer pedig ha a számláló értéke megegyezik az OCR1A regiszterben beállítottéval. Azt, hogy melyik alkalommal legyen a kimenet értéke magas, vagy alacsony, a TCCR1 (Timer/Counter1 Control Register) regiszterben lehet beállítani. A két különböző beállítás neve invertált, illetve nem invertált PWM. Nem invertált módban a kimenet értéke magas lesz, ha a számláló a 0 értéket veszi fel, és alacsony, ha a számláló felveszi az OCR1A regiszterben beállított értéket. Invertált módban ennek pont az ellenkezője történik, alacsony lesz 0 értéknél, és magas, ha egyezés van.
11. ábra Nagyfrekvenciás PWM mód [1]
24
A TCCR1 regiszter további beállítási lehetőségeket is kínál ebben a módban. Megadható neki például a számláló maximum értéke. Ez a beállítás azért lehet fontos, mert nem-invertált PWM módban a kimenet értéke mindenképpen legalább egy órajel hosszig magas lesz, hiszen a számláló mindig 0-tól kezdi a számlálást, az alacsony érték nem állítható. Ez pedig azt jelenti, hogy csupán PWM szabályzással nem invertált esetben nem tudunk statikus 0, azaz alacsony kimenetet generálni, ami miatt a fogyasztónk kvázi kikapcsolt esetben is fogyaszt, hiszen a kimeneten mindig lesz jel. Ez nem csak fogyasztás szempontjából aggályos, hanem LED-es világítótest esetén halványan mindig világítani fog a fényforrásunk, ami sötét környezetben kellemetlen is lehet, amellett, hogy ez egy nem kívánt működési mellékhatás. Ezt a későbbiekben mindenképpen figyelembe kell venni, illetve ki kell küszöbölni. Megoldást jelenthet például az invertált PWM mód, ahol a számláló magas értékét (ahol a számláló nullázódik) alacsonyabbra tudjuk választani a komparálási szintnél, így gyakorlatilag soha nem lesz magas a kimenet. Ez azonban nehézséget jelenthet a későbbiekben, mert fordított logikával kell kezelni a szabályzást, a magasabb érték innentől kezdve alacsonyabb fényerősséget jelentene.
5.4.4 Phase Correct PWM mode (fázishelyes PWM mód) Ez a működési mód jelentősen különbözik az eddigiektől, a számláló ugyanis itt nem csak egy irányba számol. Itt egy úgynevezett dual-slope működési módot valósítottak meg a számlálóban, azaz ha a számláló a 0 értéktől kezdve eljut a maximum értékéig, túlcsordulás (és ezzel nullázódás) helyett visszafele kezd el számolni. Emiatt a PWM maximális frekvenciája a fele a nagyfrekvenciás PWM móddal elérhetőnek, viszont a kitöltési tényező változtatásánál is megtartja a fázisát, így motorok szabályozására ez a mód jobb, mint a nagyfrekvenciás PWM mód. Ebben az üzemmódban is van lehetőség a maximális érték beállítására, így változtatható a PWM frekvenciája is.
25
12. ábra Fázishelyes PWM mód [1]
A világítás szabályozás céljaira leginkább a nagyfrekvenciás PWM mód felel meg, mivel itt nem szükséges figyelmet fordítani a fázishelyes modulációra, viszont a nagyfrekvenciás működés segítségével könnyebben kiküszöbölhető a villogás egy aluláteresztő szűrővel, valamint a hallható tartomány felett is tudjuk üzemeltetni az eszközt, így esetleges zaj sem keletkezhet a fojtótekercsből.
26
6 Megvalósítás, tervezés Az elméleti tervek kidolgozása után meg is kellett valósítani az áramkört, így az előzetesen feltárt problémák és funkciók szükségének megfelelően megterveztem a kapcsolási rajzot. Az áramkör sematikus rajzánál figyelembe vett tényezők: -
legyen lehetőség mindkét fajta SPI kommunikációs topológia létrehozására
-
a daisy-chain verziónál kritikus, hogy minden eszköz folyamatosan kapjon tápfeszültséget, így jó ötlet lenne, ha két külön áramforrásról is lehetne üzemeltetni az eszközt
-
a kimenetén egy nagyáramú aluláteresztő szűrő megvalósítása szükséges
-
a világítótest nagyobb feszültségen üzemel, mint a kontroller, ezért a mikroprocesszor védelmében egy optokapus leválasztás is előnyös lenne
-
előre nem látható problémák, illetve tesztelési célokra mindenképp érdemes lenne kivezetni egy tüskesorra a nem használt lábakat is
-
a csatlakozóknak olyan kialakításúaknak kell lenniük, hogy ha valahol megszakítjuk a láncot, a kábelek egymásba csatlakoztathatóak legyenek Ezen pontok figyelembevételével az áramköröm sematikus rajzát a CadSoft
EAGLE nevű szoftver 6.2.0-ás verziószámú példányával készítettem el, mely a következő lett:
27
28
A rajzot négy fő részegységre lehet bontani: -
tápellátás
-
kommunikációs, programozói kivezetések
-
mikrokontroller, illetve a működéséhez szükséges alapvető csatlakozások, kiegészítők, valamint a kivezetései
-
kimenet
6.1 Tápellátás A tápellátó részleg kidolgozásához az Arduino nyílt hardveres platform ugyanilyen funkciójú részegységéből vettem ötletet. A lényege, hogy amennyiben nincs megfelelő külső feszültségforrás, egy másodlagos feszültségforrásból nyerjük a működéshez szükséges energiát. Ha van, akkor a másodlagost lekapcsoljuk, így elkerülhetjük annak túlterhelődését, illetve hogy a feszültség különbségükből adódóan egymás ellen dolgozzanak. Az áramkör működése röviden: Tegyük fel, hogy van külső feszültségforrásunk. Ekkor a D3 dióda véd a rossz polaritású tápfeszültség ellen, helyes polaritás esetén az 7805 feszültség szabályzó (IC2) bekapcsol, és kimenetén megjelenik a +5V Vcc. Ez tápfeszültséget biztosít az LM358 műveleti erősítő párnak (IC3), melynek első tagját komparátorként használjuk. A nem invertáló bemenetére az R4, R5 feszültségosztón keresztül a külső feszültségforrás fele kerül, az invertáló bemenetére a Vcc 75%-a kerül, ez kb. 3,75V fix. Ha ennek a duplájánál több mérhető a D3 védődióda katódjánál, akkor ez a feszültség már elegendő a 7805-ös IC megfelelő működéséhez [9], a műveleti erősítő kimenetén pedig magas jelszint fog stabilizálódni, ami bezárja a Q3 FET-et, így lekapcsolja a kiegészítő, másodlagos tápfeszültséget. Ellenkező esetben, ha nincs külső feszültségforrásunk, a műveleti erősítőnek nincs tápfeszültsége, kimenete alacsony szinten van, a Q3 tranzisztor kinyit, így megjelenik a rendszerben a Vcc. Bekapcsol a műveleti erősítő, de mivel a nem invertáló bemenetén ilyenkor 0V mérhető, a kimenete is alacsony szintű lesz, így Q3 nyitva marad, és így kap tápot az áramkör.
29
6.2 Kommunikációs, programozóhoz tartozó kivezetések Ennek a részegységnek a két fajta SPI topológia megvalósítása, illetve azok közötti váltása a feladata, illetve ide került a programozó csatlakozó is, mivel az ATMega8 felprogramozása is az SPI buszon történik. A két topológia között jumperekkel lehet választani, egyszerűen a kommunikációs vonalak megfelelő szét-, illetve összekapcsolásával.
13. ábra A két fajta topológia között jumperekkel lehet váltani
A normál buszos verziót JP1 és JP2 jumperek rövidre zárásával, a daisy chaint a JP3 jumperrel tudjuk megvalósítani. Programozáskor ügyelni kell, hogy az összes jumper el legyen távolítva, ellenkező esetben lehetséges, hogy a programozó nem észleli a mikroprocesszort. A csatlakozók tekintetében az RJ-45-re esett a választás, mivel az SPI kommunikáció már eleve 4 vezetéket igényel, ehhez hozzájön még a másodlagos táp 2 vezetéke, és ezzel a csatlakozóval a 6 vezeték kezelése egyszerű, valamint speciális toldókkal össze is kapcsolhatóak, ha egy slave-et eltávolítunk a körből/buszból. A maradék 2 vezetéket kivezettem egy külön csatlakozóra, későbbi felhasználás céljából. Ezek segítségével a táp, illetve föld vonalak megkettőzhetők, illetve kevés egység esetén akár a LED fényforrás táplálása is megoldható. 30
6.3 Mikrokontroller, alapvető
illetve
a
csatlakozások,
működéséhez
kiegészítők,
szükséges
valamint
a
kivezetései Bár ez a részegység tartalmazza a lényegi részt, a mikrokontrollert, itt csak alapvető dolgokra kellett figyelni. A reset láb, alapállapotban tápfeszültségre húzva legyen, de beépítésre került egy gomb is, amivel alapállapotba lehet hozni a mikroprocesszort. Az analóg részre nincs szükségünk, kivezetéseit (analóg referencia, analóg föld) tápfeszültségre, illetve földre kötöttem. A gyors SPI kommunikáció érdekében az órajelet egy külső kristály oszcillátor adja, az adatlap ajánlásának megfelelő méretű kondenzátorokkal. A nem használt lábak portok szerint kivezetésre kerültek. Ez segíthet az élesztés, illetve a programozás során is, mivel ide a debuggerhez hasonlatos töréspont jellegű LEDeket lehet például illeszteni.
6.4 Kimenet A mikrokontroller PWM kivezetését egy optokapuval védtem meg a nagyobb feszültségű részektől, például ha tönkremenne a potenciométer, vagy a végfok tranzisztor. A potenciométer a tranzisztor munkapontjának beállítására szolgál, a D1 dióda a fojtótekercsben indukálódó áramot söntöli a tranzisztor zárásakor, a D2 dióda egy egyszerű túlfeszültség védelemként szolgál. A PWM négyszögjelek simításáért egyrészt az L1 induktivitás, másrészt a C3 puffer kondenzátor felel.
6.5 Layout terv Az áramkör sematikus tervének elkészülte után meg kellett tervezni a nyomtatott huzalozású lemezt is. Tervezési irányelvek: -
kis méret, el kell férnie 6x6cm-en
-
lehetőleg minél több SMD alkatrész
-
maximum kétoldalas legyen
31
-
nagyfrekvenciás jelvezetékek miatt a kihasználatlan felületeket földre kötött vezetővel kell kitölteni
-
a nagyáramú tápvonalakhoz vastagabb vezető kell Az áramkör elkészítésénél figyelmet fordítottam a nagy, és kisebb feszültségű
részek szétválasztására, a hidegítő kondenzátorok megfelelő elhelyezésére, valamint, hogy az IC-k a tápfeszültséget a lehető legrövidebb úton, viák közbeiktatása nélkül kapják meg. A kommunikációs vonalaknál igyekeztem őket egymástól térben is elkülöníteni, hogy a köztük fellépő kapacitás minél kisebb legyen. A nagy áramú tápvonalak vezetőinek szélességének meghatározásánál az IPC-2221 „Generic Standard on Printed Board Design” ajánlását vettem figyelembe.
14. ábra IPC-2221 vezető keresztmetszet ajánlása külső (felületi) vezetőkhöz
E szerint, külső, felületi vezetők esetén egy adott keresztmetszetű vezetőn maximálisan megengedhető átfolyó áram a következő képlet alapján számítható ki: I = 0,048 ⋅ dT 0, 44 ⋅ A 0, 725 ahol: I = maximálisan átfolyó áram [A] dT = a vezető hőmérséklet változása a környezethez képest [°C] A = a vezető keresztmetszete [mil2] 32
(6.5.1)
A vezérelendő fényforrásunk egy 10W-os, 12V-os LED lámpa, ami így 833mAes áramigénnyel bír. A nyomtatott áramköri lapok általában 35µm rézvastagságúak, így én is ezzel fogok számolni. A vezető hőmérséklet változása legyen az IPC-2221 által meghatározott legkisebb, azaz 10°C. Így a képlet a következő lesz: 0,833 = 0,048 ⋅ 10 0, 44 ⋅ (1,38 ⋅ w ) 0, 725
(6.5.2)
ahol „w” a vezető minimális szélessége. „w”-re rendezve az egyenletet a következőt kapjuk: 1
0,833 0,048 ⋅ 10 0, 44 w = 1,38 0, 725
0, 725 = 9,18mil
(6.5.3)
Látható, hogy az igényelt vezető vastagsága nem lineáris függvénye az áramnak, így kisebb túlterhelés, vagy nagyobb fogyasztó bekötése esetén vastagabb vezetékezés kell, mint ahány szorosára az áram változik. Például 1,25A-nél (50% emelkedés) a minimális vezetőszélesség már 16,09mil (75% emelkedés). Ráadásul a kapott adat ideális esetre vonatkozik, nem számol a gyártás során fellépő pontatlanságokkal, így jó ötletnek tűnik vastagabbat használni nála. A biztonság kedvéért a nagy áramú vezetékeket 40mil szélességűnek definiáltam, a mikroprocesszorhoz tartozó táp, illetve adat vonalak 16mil szélességűek lettek. A layoutot a CadSoft EAGLE 6.2.0 verziójával készítettem.
33
15. ábra A kész layout terv
A kész layout tervből ezután Gerber fájlokat generáltam, majd gyártásra leadtam az egyetem nyákgyártó laborjába. Az elkészült nyákokat DIMA SMPA-0200 típusú kézi pick&place beültetővel ültettem be, majd ASSCON QUCKY-450 típusú gőzfázisú forrasztógéppel
végeztem
a
forrasztást.
A
furatszerelt
alkatrészeket
kézi
forrasztópákával forrasztottam. Ezzel a folyamattal elkészültek a slave egységeim, elkezdődhetett a vezérlő programok írása és tesztelése mind az Arduino, mind a most elkészült modulokra.
34
7 Programozás A hardver elkészülte után el kellett készíteni a vezérlő programokat is. Az előzetes terveknek megfelelően két féle program készült el a vezérlőegységeimre, illetve az Arduino-ra is.
7.1 Közös funkciók Először szeretném bemutatni azokat a problémákat, és megoldásaikat, amelyek mindkét variációnál előfordultak. Először is, a kommunikáció a PC – Arduino vonalon mindig a soros porton keresztül zajlik, legyen az virtuális, USB-n keresztüli, vagy valós RS-232 kompatibilis kapcsolat. A számítógépen futó vezérlőprogramnak nem kell tudnia, hogy milyen topológiát használunk, az eltérő buszrendszerből adódó kommunikációs különbségek kezelését a master program oldja meg. A PC vezérlőprogram mindig csak egy karakterláncot küld a következő formában: <slave címe>,
. A slave címe 1 és 254 között lehet (a „0” cím az üresjárati, illetve dummy bájtunk, amivel daisy chain kapcsolat esetén továbbléptetjük az adatokat, a „255” pedig a konfiguráló bájtunk, így ez a két érték foglalt), a beállítandó érték 0-255 értéket vehet fel. Felmerült egy olyan igény is, hogy a számítógép, vagy az azon futó vezérlőprogram újraindítása esetén is tudnia kell a programnak, hogy éppen melyik slave milyen értékre van beállítva, így megtartva a konzisztenciát. Erre a célra a „0” címet jelöltem ki, mivel ilyen című eszköz nem lehet a buszon, így ha az Arduino 0-s címet fogad, azt nem küldi tovább az SPI buszra, hanem a PC felé küldi vissza táblázatszerűen, hogy az egyes vezérlők milyen értékre vannak beállítva. A 15. ábrán egy példa válasz látható, ha elküldjük a „0,33.” karaktersorozatot. Az érték a 0-ás cím mellet nem számít, azt a master program nem veszi figyelembe. Az értékeket áramszünet, resetelődés, vagy bármilyen más hibalehetőség elkerülése végett az Arduino EEPROM-jában is el kell tárolni.
35
16. ábra Példa egy visszaolvasásra az Arduino soros monitoron keresztül
Mindkét verziónál felmerült probléma volt a kimenet beállítása. Az eredeti elképzelések szerint 8 bites fast PWM módot használtam volna, de a 255 lépcsőre osztott szabályzás nem bizonyult elégségesnek felbontás szempontjából. A vezérelt LED nem lineáris karakterisztikájából következett, hogy az 1/255 időegységre bekapcsolt kimenet is viszonylag fényesen világított, így elvesztek az egészen halvány tónusok. A megoldást a 16 bites PWM használata jelentette, viszont ezt 65535 lépcsőben kellene állítani, hogy elérjük a két végpontot. Ez sok esetben nem szerencsés, jobbnak láttam, ha maradunk az eredeti, 255 lépcsős szabályzásnál. Így 1 fokozat változás a PWM-ben 256 lépcsőnek felelne meg, ha lineáris szabályozást valósítottam volna meg, így végül is az eredeti 8 bites PWM felbontást kaptam volna eredményül. Nem lineáris szabályzással azonban már más a helyzet, az 1/65536 időegységnyire bekapcsolt kimeneten már nem volt látható, hogy világít, ezért a továbbiakban egy nem lineáris karakterisztikát valósítottam meg a kimenet szabályzásában, amit az emberi szem relatív fényérzetéhez próbáltam igazítani. Az emberi szem relatív fényérzetéhez a Stevens törvényt vettem alapul. A Stevens törvény az inger, valamint az észlelés mértéke közötti összefüggést írja le [8]. Ez alapján egy sötétben, 5° látószög alatt látszó fényforrás fényintenzitása, és a látszólagos fényessége közti összefüggés a következő egyenlettel írható le: 36
B = 3 ⋅ I 0,33
(7.1)
ahol B = látszólagos fényesség I = fényintenzitás Ahhoz, hogy közel lineárisan tudjuk a fényerősséget állítani, ennek a függvénynek az ellentétével kell dolgoznunk, így az egyenletet I-re rendezve a következőt kapjuk:
B I= 3
3
(7.2)
Mivel így I=255 esetre a végeredmény 621378, ezt a képletet még normálnunk kell 65536-ra, a végeredményül kapott képlet tehát: 3
B 3 I= 9,4815
(7.3)
A (7.3) képlet alapján kapott nem lineáris karakterisztika ábrázolva: Nem lineáris PWM karakterisztika 70000
60000
PWM komparálási érték
50000
40000
nem lineáris PWM karakterisztika
30000
20000
10000
0 1
11 21 31 41 51 61 71
81 91 101 111 121 131 141 151 161 171 181 191 201 211 221 231 241 251 Fokozat
17. ábra Nem lineáris kimeneti karakterisztika
Mivel a beállítandó értékek mindig ebből a 256 diszkrét értékből kerülnek ki, és a mikrokontrollerem véges számítási kapacitású, főleg ha lebegőpontos számításokról
37
van szó, ezért jobbnak láttam előre kiszámítani az egyes diszkrét értékeket, és azokat egy tömbben eltárolni, majd onnan szükség esetén előhívni. Így egyfajta LUT-ot (Look Up Table) hoztam létre, mely hatékonyan képes a nem lineáris függvényt megvalósítani, a kimenetet beállítani. Először tekintsük át a normál buszrendszerű verziót:
7.2 Normál buszrendszerű verzió 7.2.1 Master A normál buszrendszerű verzióban kénytelen vagyunk fix címeket használni, sehogyan nem tudjuk külön címezni az egységeket egyetlen SS vonal használatával. Ezért aztán az Arduino master programjában nem is kell mást csinálni, csak soros porton fogadni a parancsokat, majd azokat átalakítva, az SPI buszon továbbküldeni. A kódot az ingyenes Arduino fejlesztőkörnyezet 1.0.1-es verziója alatt készítettem, mely a következő lett: #include "SPI.h" // SPI használatához szükséges header #include "EEPROM.h" // EEPROM használatához szükséges header int ss=53; // a Slave Select az 53as digitális kivezetés lesz int stats[9]; //ebben a tömbben tároljuk a slavek állapotát, egyelőre csak 8-ét // a tömb minden egyes eleme egy slave-hez tartozik, a 0. eleme (mivel ilyen című slave nem létezhet) azt jelzi, hogy visszakérdezéskor ki kell-e írni, változtattuk-e valaha az értékét void setup() //egyszer lefutó függvény, beállítások { pinMode(ss, OUTPUT); // az SS kimenet lesz digitalWrite(ss, HIGH); // felhúzzuk az SS vonalat, deaktiváljuk a slaveket SPI.begin(); // SPI busz felélesztése SPI.setBitOrder(MSBFIRST); // SPI-on az MSB-t küldjük először SPI.setDataMode(SPI_MODE0); // SPI mód beállítása SPI.setClockDivider(SPI_CLOCK_DIV64); // SPI sebesség megadása, hosszú kábelezés esetén ezt csökkenteni kell, SPI_CLOCK_DIV128-ra Serial.begin(9600); // soros port felélesztése readStatus(); // visszatöltjük az elmentett adatokat } void setValue(int value) keresztül adatokat küldeni { digitalWrite(ss, LOW); delay(1); SPI.transfer(value); digitalWrite(ss, HIGH); vonal magas állapotba hozása }
//
// // // //
ezzel
a
függvénnyel
tudunk
SPI-on
slave-ek aktiválása biztonsági várakozás adat elküldése slave-ek deaktiválása, a Slave Select
38
void sendStatus() // ezzel a függvénnyel küldjük vissza a slave-ek állapotát, ha 0 címet kapunk { int mask = 2; // maszk a léptetéshez, hogy ki kell-e írni for (int i = 1; i < 9; i++) // végigléptetjük az egész tömbön { if((stats[0]&mask) > 0) // ha a változtattunk, kiírjuk { Serial.print(i,DEC); // adatok visszaküldése a soros vonalon Serial.print(": "); Serial.println(stats[i],DEC); } mask = mask<<1; // maszk shiftelése eggyel balra // tehát első körben 0b00000010 -> 0b00000100 } } void writeStatus(int addr, int val) // ezzel a függvénnyel elmentjük az EEPROM-ba az értékeket, és jelezzük a státusz tömb 0. elemében a változást { stats[addr]=val; // a tömb megfelelő elemébe beírjuk ez értéket EEPROM.write(addr,val); // az EEPROM-ba is elmentjük (!!!nem ajánlom, az EEPROM-nak véges, nagyjából 100.000 írási ciklusa van!!!) stats[0]=stats[0]|(1< 0) { // várunk, amíg nem érkezik parancs a soros porton // addig olvasunk, amíg nem egy szám a következő karakter, majd a beolvasott értéket int típusúvá konvertáljuk, és eltároljuk az address változóban: int address = Serial.parseInt(); // addig olvasunk, amíg nem egy szám a következő karakter, majd a beolvasott értéket int típusúvá konvertáljuk, és eltároljuk a value változóban: int value = Serial.parseInt(); // várunk a karaktersorozat végére, amit itt „.”-nak definiáltam if (Serial.read() == '.') {
39
if(address==0) //ha 0 címet kaptunk, visszaküldjük az értékeket sendStatus(); else // ha más címet kaptunk, meg kell néznünk, hogy az érvényes-e, ha nem, akkor átkonvertáljuk 1 és 254 közé { address = constrain(address, 1, 254); value = constrain(value, 0, 255); // az adatokat is megvizsgáljuk, hogy érvényes-e, ha nem, 0-255 közöttire alakítjuk setValue(address); setValue(value);
// cím küldése SPI buszon // adat küldése SPI buszon
writeStatus(address,value); // értékek mentése az EEPROM-ba } } } }
7.2.2 Slave A slave program fogadja az SPI porton bejövő adatokat, szétválasztja címekké, és adatokká, melyekkel a Timer1-hez tartozó komparálási értékeket állítja be. A slave programot az Atmel Studio 6.0.1843-as verziójával készítettem. #define F_CPU 16000000UL // CPU órajel definiálása a késleltetésekhez #include // a ki/bemenetekhez szükséges header #include // késleltetésekhez szükséges header #include // megszakításhoz szükséges header int address=0x02; // saját cím definiálása int i; bool firstPacket; // ezzel jelezzük, ha nem kaptunk még SPI-on adatot, tehát a következő kapott adat egy cím lesz bool data4Me; // ezzel jelezzük, ha az előző SPI csomagban felismertük a saját címünket, tehát az adat nekünk szól majd // a fentebb taglalt LookUpTable unsigned int LUT[256]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,19,23,27,31,36,42,48,54,6 1,69,77,86,95,105,116,128,140,154,167,182,198,214,232,250,269, 289,311,333,356,380,406,432,460,488,518,549,582,615,650,686,723,762,802,84 4,887,931,977,1024,1073,1123,1175,1228,1283,1340,1398, 1458,1520,1583,1648,1715,1783,1854,1926,2000,2076,2154,2233,2315,2399,2484 ,2572,2662,2754,2848,2943,3042,3142,3244,3349,3456,3565, 3676,3790,3906,4024,4145,4268,4394,4522,4652,4785,4920,5058,5199,5342,5488 ,5636,5787,5941,6097,6256,6418,6582,6750,6920,7093,7269, 7447,7629,7814,8001,8192,8385,8582,8781,8984,9189,9398,9610,9825,10044,102 65,10490,10718,10949,11184,11422,11663,11908,12156,12408, 12663,12921,13183,13448,13717,13990,14266,14546,14829,15116,15407,15701,15 999,16301,16607,16916,17229,17546,17867,18192,18521,18854, 19190,19531,19876,20224,20577,20934,21295,21660,22029,22402,22780,23162,23 548,23938,24333,24732,25135,25542,25954,26371,26792,27217, 27646,28081,28519,28963,29411,29863,30320,30782,31248,31719,32195,32676,33 161,33651,34146,34646,35150,35659,36174,36693,37217,37746, 38281,38820,39364,39913,40467,41027,41591,42161,42736,43316,43902,44492,45 088,45689,46296,46908,47525,48147,48775,49409,50048,50692,
40
51342,51997,52658,53325,53997,54675,55358,56047,56742,57443,58149,58861,59 579,60302,61032,61767,62508,63255,64008,64767,65536}; ISR(SPI_STC_vect) // ha SPI megszakítási kérelem történt { if(firstPacket) // ha ez az első adat, akkor ez egy cím { if(SPDR==address) // ha a fogadott adat a mi címünk { data4Me = true; // a következő csomag nekünk szól majd firstPacket = false; // a következő csomag nem cím } else // ha nem a mi címünk { data4Me = false; // a következő csomagot figyelmen kívül hagyjuk firstPacket = false; // a következő csomag nem cím } } else // ha nem ez az első csomag, akkor ez egy adat { if(data4Me) // ha nekünk szól { if(SPDR==0){ // ha 0 a fogadott adat DDRB &=~(1<<1); // kikapcsoljuk a kimenetet } else { // ha nem 0 DDRB |=(1<<1); // kimenetként definiáljuk a kimenetet OCR1A = LUT[SPDR]; // beállítjuk a komparálási értéket a LUT alapján } data4Me = false; // a kimenetet beállítottuk, alaphelyzet } firstPacket = true; // alaphelyzet visszaállítása } }
void pwm_init() //Timer1 PWM beállítása { TCCR1A |= (1<<WGM11) | (1<
// 16bit
// TOP érték beállítása
}
int main(void) { DDRB = 0x12; MISO kimenete pwm_init();
// a fő programunk //PORT B 1,4 kimenet, a B1 a PWM kimenet, a B4 az SPI
// PWM előkészítése, indítása
SPCR |= (1<<SPE); SPCR |= (1<<SPIE); sei();
// SPI engedélyezése // SPI megszakítás engedélyezése // globális megszakítási kérelmek engedélyezése
41
PORTB |= (1<<1);
// port B1 felhúzó ellenállás bekapcsolása
firstPacket = true; // SPI alaphelyzet beállítása, először címet várunk data4Me = false; // nem címeztek még meg minket while(1) { // mivel minden megszakítás alapon működik, a fő programunk innentől kezdve nem csinál semmit, szabadon felhasználható a továbbiakban egyéb célokra } }
A program beállításainál használt fontosabb regiszterek: -
SPI:
o SPDR: SPI adat regiszter, ide kerülnek az SPI-on fogadott, illetve az elküldendő adatok (8bit) o SPSR: SPI státusz regiszter, nekünk az SPIF bit az érdekes, ez jelzi ha készen van egy SPI transzfer, megszakítási kérelmet generál o SPCR: SPI kontrol regiszter, itt lehet az SPI megszakítást (SPIE), illetve az SPI buszt (SPE) engedélyezni, beállítani, hogy a mikrokontroller master/slave üzemmódban működjön-e (MSTR). Mivel az MSTR bit alapértelmezetten 0 értékű, ezért a programomban ezt nem szükséges beállítani. Ebben a regiszterben található meg az SPI módra vonatkozó beállítások is (CPOL, CPHA), de mivel a 0-s módot használom, ezeket se kell átállítanom. Az SPR1 és SPR0 bitekkel az SPI frekvencia előosztót lehet állítani, de itt erre nincs szükség, az órajel a master beállításaitól függ. -
PWM:
42
o TCCR1: Timer/Counter1 kontrol regiszter, ezek segítségével lehet beállítani a különböző PWM módokat. A COM1A1, COM1A0 párossal a kimenet módját lehet megadni (invertáló, nem invertáló), a WGM13, WGM12, WGM11, WGM10 bitekkel pedig a PWM működési módját lehet beállítani. Én 16 bites, nem invertáló beállítást használtam, ahol külön lehet definiálni, hogy milyen értékig számoljon a számláló, ezt az ICR1 regiszterbe kell betölteni. Az OCR1A regiszterbe a komparálási érték kerül, ahol a kimenet vált.
7.3 Daisy chain verzió A daisy chain verzióban címek nélkül is meg tudjuk különböztetni a slave-eket, egyszerűen azáltal, hogy hány SPI transzfert hajtunk végre. Ennek segítségével az első parancs fogadása előtt csökkenő sorrendben automatikusan kioszthatunk nekik címeket, így a későbbiekben nem kell azzal foglalkozni, hogy hány SPI transzfert kell kiküldeni az egyes egységek eléréséhez. A program a 8. ábrán látható blokkdiagram szerint működik.
7.3.1 Master #include "SPI.h" // SPI használatához szükséges header #include "EEPROM.h" // EEPROM használatához szükséges header int ss=53; // a Slave Select az 53as digitális kivezetés lesz int stats[9]; //ebben a tömbben tároljuk a slavek állapotát, egyelőre csak 8-ét // a tömb minden egyes eleme egy slave-hez tartozik, a 0. eleme (mivel ilyen című slave nem létezhet) azt jelzi, hogy visszakérdezéskor ki kell-e írni, változtattuk-e valaha az értékét int slaves = 0; // slave-ek száma void setup() //egyszer lefutó függvény, beállítások { pinMode(ss, OUTPUT); // az SS kimenet lesz digitalWrite(ss, HIGH); // felhúzzuk az SS vonalat, deaktiváljuk a slaveket SPI.begin(); // SPI busz felélesztése SPI.setBitOrder(MSBFIRST); // SPI-on az MSB-t küldjük először SPI.setDataMode(SPI_MODE0); // SPI mód beállítása SPI.setClockDivider(SPI_CLOCK_DIV64); // SPI sebesség megadása, hosszú kábelezés esetén ezt csökkenteni kell, SPI_CLOCK_DIV128-ra Serial.begin(9600); // soros port felélesztése conf_slaves(); // kiosztjuk a címeket a slave-eknek readStatus(); // visszatöltjük az elmentett adatokat } int conf_slaves() {
// slave-eknek címek kiosztása
43
digitalWrite(ss, LOW); delay(1); SPI.transfer(255); for(int i = 1; i<255; i++) konfiguráló byte { if(SPI.transfer(i) == 255) { slaves = i; break; } } digitalWrite(ss, HIGH); }
// slave-ek aktiválása // biztonsági várakozás // konfiguráló byte küldése // címek küldése, amíg vissza
nem
ér
a
// ha visszaért a konfig byte // elmentjük a slave-ek számát // befejezzük a címek küldését
// deaktiváljuk a slave-eket
void setValue(int address, int value) // ezzel tudunk SPI-on keresztül adatokat küldeni { digitalWrite(ss, LOW); // slave-ek aktiválása delay(1); // biztonsági várakozás SPI.transfer(address); // cím elküldése SPI.transfer(value); // adat elküldése for(int i = 0; i < 255; i++) { if(SPI.transfer(0) == address) // dummy byte küldése, ér a cím break; // ha visszaért, befejezzük } digitalWrite(ss, HIGH); // slave-ek deaktiválása, vonal magas állapotba hozása }
a
függvénnyel
amíg vissza nem a kommunikációt a Slave Select
void sendStatus() // ezzel a függvénnyel küldjük vissza a slave-ek állapotát, ha 0 címet kapunk { // maszk a léptetéshez, hogy ki kell-e írni int mask = 2; for (int i = 1; i < 9; i++) // végigléptetjük az egész tömbön { if((stats[0]&mask) > 0) // ha a változtattunk, kiírjuk { Serial.print(i,DEC); // adatok visszaküldése a soros vonalon Serial.print(": "); Serial.println(stats[i],DEC); } mask = mask<<1; // maszk shiftelése eggyel balra // tehát első körben 0b00000010 -> 0b00000100 } } void writeStatus(int addr, int val) // ezzel a függvénnyel elmentjük az EEPROM-ba az értékeket, és jelezzük a státusz tömb 0. elemében a változást { stats[addr]=val; // a tömb megfelelő elemébe beírjuk ez értéket EEPROM.write(addr,val); // az EEPROM-ba is elmentjük (!!!nem ajánlom, az EEPROM-nak véges, nagyjából 100.000 írási ciklusa van!!!) stats[0]=stats[0]|(1<
44
void readStatus() // bekapcsoláskor ezzel olvassuk vissza az EEPROM-ba mentett értékeket { for (int i = 1; i<9; i++) { stats[i] = EEPROM.read(i); //az összes értéket beolvassuk if(stats[i]!=0) //ha nem 0, tehát változtattuk { setValue(i, stats[i]); // beállítjuk a kimenetet // jelezzük a státusz tömb 0. elemében stats[0]=stats[0]|(1< 0) { // várunk, amíg nem érkezik parancs a soros porton // addig olvasunk, amíg nem egy szám a következő karakter, majd a beolvasott értéket int típusúvá konvertáljuk, és eltároljuk az address változóban: int address = Serial.parseInt(); // addig olvasunk, amíg nem egy szám a következő karakter, majd a beolvasott értéket int típusúvá konvertáljuk, és eltároljuk a value változóban: int value = Serial.parseInt(); // várunk a karaktersorozat végére, amit itt „.”-nak definiáltam if (Serial.read() == '.') { if(address==0) //ha 0 címet kaptunk, visszaküldjük az értékeket sendStatus(); else // ha más címet kaptunk, meg kell néznünk, hogy az érvényes-e, ha nem, akkor átkonvertáljuk 1 és 254 közé { address = constrain(address, 1, 254); value = constrain(value, 0, 255); // az adatokat is megvizsgáljuk, hogy érvényes-e, ha nem, 0-255 közöttire alakítjuk setValue(address, value);
// cím és adat küldése SPI buszon
writeStatus(address,value); // értékek mentése az EEPROM-ba } } } }
7.3.2 Slave #define F_CPU 16000000UL // CPU órajel definiálása a késleltetésekhez #include // a ki/bemenetekhez szükséges header #include // késleltetésekhez szükséges header #include // megszakításhoz szükséges header int address=0x00; int i;
// saját cím definiálása
45
bool firstPacket; // ezzel jelezzük, ha nem kaptunk még SPI-on adatot, tehát a következő kapott adat egy cím lesz bool data4Me; // ezzel jelezzük, ha az előző SPI csomagban felismertük a saját címünket, tehát az adat nekünk szól majd bool configured = false; // volt-e már cím kiosztás? bool conf_started = false;// jött-e már a konfiguráló byte? // a fentebb taglalt LookUpTable unsigned int LUT[256]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,19,23,27,31,36,42,48,54,6 1,69,77,86,95,105,116,128,140,154,167,182,198,214,232,250,269, 289,311,333,356,380,406,432,460,488,518,549,582,615,650,686,723,762,802,84 4,887,931,977,1024,1073,1123,1175,1228,1283,1340,1398, 1458,1520,1583,1648,1715,1783,1854,1926,2000,2076,2154,2233,2315,2399,2484 ,2572,2662,2754,2848,2943,3042,3142,3244,3349,3456,3565, 3676,3790,3906,4024,4145,4268,4394,4522,4652,4785,4920,5058,5199,5342,5488 ,5636,5787,5941,6097,6256,6418,6582,6750,6920,7093,7269, 7447,7629,7814,8001,8192,8385,8582,8781,8984,9189,9398,9610,9825,10044,102 65,10490,10718,10949,11184,11422,11663,11908,12156,12408, 12663,12921,13183,13448,13717,13990,14266,14546,14829,15116,15407,15701,15 999,16301,16607,16916,17229,17546,17867,18192,18521,18854, 19190,19531,19876,20224,20577,20934,21295,21660,22029,22402,22780,23162,23 548,23938,24333,24732,25135,25542,25954,26371,26792,27217, 27646,28081,28519,28963,29411,29863,30320,30782,31248,31719,32195,32676,33 161,33651,34146,34646,35150,35659,36174,36693,37217,37746, 38281,38820,39364,39913,40467,41027,41591,42161,42736,43316,43902,44492,45 088,45689,46296,46908,47525,48147,48775,49409,50048,50692, 51342,51997,52658,53325,53997,54675,55358,56047,56742,57443,58149,58861,59 579,60302,61032,61767,62508,63255,64008,64767,65536}; ISR(SPI_STC_vect) // ha SPI megszakítási kérelem történt { if(!configured) // ha nem volt még címkiosztás { if(SPDR==255) // ha megérkezett a konfiguráló byte conf_started = true; // elkezdődött a címek kiosztása } else if(firstPacket) // ha ez az első adat, akkor ez egy cím { if(SPDR==address) // ha a fogadott adat a mi címünk { data4Me = true; // a következő csomag nekünk szól majd firstPacket = false; // a következő csomag nem cím } // ha nem a mi címünk else { data4Me = false; // a következő csomagot figyelmen kívül hagyjuk firstPacket = false; // a következő csomag nem cím } } else // ha nem ez az első csomag, akkor ez egy adat { if(data4Me) // ha nekünk szól { if(SPDR==0){ // ha 0 a fogadott adat DDRB &=~(1<<1); // kikapcsoljuk a kimenetet } // ha nem 0 else {
46
DDRB |=(1<<1); // kimenetként definiáljuk a kimenetet OCR1A = LUT[SPDR]; // beállítjuk a komparálási értéket a LUT alapján } data4Me = false; // a kimenetet beállítottuk, alaphelyzet } firstPacket = true; // alaphelyzet visszaállítása } } void pwm_init() //Timer1 PWM beállítása { TCCR1A |= (1<<WGM11) | (1<
// 16bit
// TOP érték beállítása
} int main(void) { DDRB = 0x12; MISO kimenete pwm_init();
// a fő programunk //PORT B 1,4 kimenet, a B1 a PWM kimenet, a B4 az SPI
// PWM előkészítése, indítása
SPCR |= (1<<SPE); SPCR |= (1<<SPIE); sei();
// SPI engedélyezése // SPI megszakítás engedélyezése // globális megszakítási kérelmek engedélyezése
PORTB |= (1<<1);
// port B1 felhúzó ellenállás bekapcsolása
firstPacket = true; // SPI alaphelyzet beállítása, először címet várunk data4Me = false; // nem címeztek még meg minket while(!conf_started) {}//ha még nem kezdődött el a konfigurálás, várunk a konfiguráló byte-ra while(!(PINB & (1<<2))) {} // amíg alacsony a slave select, várunk address = SPDR; // befejeződött a címek kiosztása, elmentjük a nálunk lévőt configured = true; // megvan a címünk while(1) { // mivel minden megszakítás alapon működik, a fő programunk innentől kezdve nem csinál semmit, szabadon felhasználható a továbbiakban egyéb célokra } }
47
8 Tesztelés, mérési eredmények Az összeállított rendszert végül teszteltem, lemértem. A mérések során különös figyelmet fordítottam a PWM kimenet analizálására.
18. ábra Mérési összeállítás
A 18. ábrán látható mérési összeállításban a fő tranzisztor gate elektródáján fellépő jelalak látható. Ugyanezen mérés alkalmával a mikrokontroller PWM kimenetén megjelenő jelalakot is vizsgáltam, több beállításnál is. A 19. ábrán látható a kimeneti jelalak, ha a vezérlő egység „0” bemeneti jelet ad. A program szerint ilyenkor az előző fejezetekben említett probléma miatt a mikrokontroller kimenete tri-state állapotba kerül, a kimenet lebeg. Összehasonlítva a 20. ábrával ez jól látszik, ilyenkor a kimenet output módba kapcsol, a kimenet földpotenciálra kerül.
48
19. ábra PWM kimenet "0" input esetén, a kimenet lebeg
20. ábra PWM kimenet "1" input esetén, a kimenet földpotenciálon
49
21. ábra PWM kimenet "80" input esetén
Az Arduinon keresztül 80as értéket megadva a bemeneten a kimeneti jel már jól látható, az oszcilloszkóp mérése szerint ilyenkor a duty cycle körülbelül 3,2%, ami körülbelül 2097-es PWM komparálási értéket sejtet. Összehasonlítva a LUT 80. értékével (2076) nagyjából megfelel a várakozásoknak.
22. ábra PWM kimenet "160" input esetén
A slave-re 160-as inputot küldve a 22. ábrán látható jelalak jelenik meg a kimeneten, az oszcilloszkóp mérése szerint 24,9%-os a kitöltési tényező. Ez alapján a PWM komparálási értéke 16318 körülre tehető, a LUT-ból ellenőrizve ez 16301, tehát a mért eredmény helyesnek mondható, az áramkör jól működik. 50
23. ábra PWM kimenet "254" input esetén
A bemenetre 254es értéket küldve a 23. ábrán jól látható, hogy a kimenet szinte teljesen be van kapcsolva, a kitöltési tényező 98,8%. Ebből a PWM komparálási regiszterének számított értéke 64749, ami nagyjából megfelel a beprogramozott 64771es értéknek.
24. ábra PWM kimenet "255" input esetén
Az áramköröm a 255-ös input esetén folyamatosan be van kapcsolva, a kimeneten nem látható semmilyen zavar, 1 órajel ciklusra sem vált 0V-ra a vártaknak megfelelően.
51
Végezetül egy diagramon szemléltetem a programozott karakterisztikát és rá vetítve a néhány ponton mért értékeket: Mért és programozott PWM karakterisztika 70000
60000
PWM komparálási érték
50000
40000
programozott PWM karakterisztika
30000
mért PWM karakterisztika
20000
10000
0 1
11 21 31 41
51 61 71 81 91 101 111 121 131 141 151 161 171 181 191 201 211 221 231 241 251 Fokozat
25. ábra Mért és programozott PWM karakterisztika
52
9 Összegzés A szakdolgozat készítése során különálló modulokból álló rendszert kellett terveznem, melynek vezérlő egységét (Arduino) csak megismernem, programoznom kellett, de a vezérelt egységet saját magamnak kellett megterveznem, és megvalósítanom, melynek során betekintést nyertem a nyomtatott huzalozású áramkörök tervezésébe. A rendszer összekapcsolásához meg kellett ismernem az SPI, és az I2C kommunikációs buszok működését, lehetőségeit, valamint implementálnom kellett egy saját, egyszerű, byte alapon működő protokollt, mivel az SPI busz nem használ szoftveres címeket, nekem pedig arra volt szükségem. Megismertem továbbá az Atmel AVR vezérlőit, az Arduino, és a saját tervezésű vezérelt egységem is ezt használja, és míg az Arduino a saját fejlesztőszoftverén keresztül elrejti az alacsony szintű kódokat, a slave egységeknél ez néha elkerülhetetlen volt, közvetlenül regisztereket kellett elérnem, és bitszintű műveleteket kellett végeznem. Részleteibe menően meg kellett vizsgálnom a hardveres PWM egység működését, lehetőségeit, valamint a későbbiekben ezt oszcilloszkópon is lemértem. A feladat készítése során olyan előre nem látott problémákat kellett megoldanom, mint a kimenet nem lineáris vezérlése, alkalmazkodva az emberi szem fényérzetéhez, valamint a helyes PWM beállítás megtalálása, amivel teljes szélességében ki lehet vezérelni a kimenetet, és meg kellett oldani a PWM teljes lekapcsolását is. A feladatomhoz fejlesztési javaslatnak megemlíteném, hogy előnyös lenne valamilyen vezeték nélküli kommunikáció implementálása, mind a hálózat tagjai között, mind pedig a vezérlő oldaláról, akár egy egyszerű infravörös távkapcsoló jelleggel, mert a számítógépes, vagy akár okostelefonos irányítási megoldás szerintem sokszor kényelmetlen lehet. További fejlesztési javaslat, hogy a kimenet értékét egy feszültségosztón keresztül érdemes lehet visszavezetni a mikrokontroller egy ADC csatornájára, mert alacsony fokozaton nagyon sokáig tart a nagy kimeneti pufferkondenzátor feltöltődése, ezt talán jobban is meg lehetne oldani valamilyen szabályzással.
53
Irodalomjegyzék [1]
Atmel Corporation: ATmega8 datasheet http://www.atmel.com/images/doc8159.pdf (Rev.8159D, Feb. 2011)
[2]
Wikipedia: Serial Peripheral Interface Bus, http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus (23 November 2012)
[3]
Robert Bosch GmbH: Can protocol license http://www.semiconductors.bosch.de/en/ipmodules/can/canprotocollicense/canpro tocollicense.asp
[4]
Motorola Inc.: SPI Block Guide (revision V03.06, 04 Feb. 2003)
[5]
Wikipedia: I2C, http://en.wikipedia.org/wiki/I%C2%B2C (4 December 2012)
[6]
Philips Semiconductors: I2C manual http://www.nxp.com/documents/application_note/AN10216.pdf
[7]
Wikipedia: List of network buses http://en.wikipedia.org/wiki/List_of_network_buses (4 December 2012)
[8]
Wikipedia: Stevens’ power law http://en.wikipedia.org/wiki/Stevens%27_power_law (4 December 2012)
[9]
ST Microelectronics: 7805 datasheet http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LIT ERATURE/DATASHEET/CD00000444.pdf (Doc ID 2143 Rev 30, September 2012)
[10] Wikipedia: Lighting control system http://en.wikipedia.org/wiki/Lighting_control_system (6 December 2012) [11] Wikipedia: ZigBee http://en.wikipedia.org/wiki/ZigBee (6 December 2012) [12] ZigBee Alliance http://www.zigbee.org/ [13] Wikipedia: Z-Wave http://en.wikipedia.org/wiki/Z-Wave (6 December 2012) [14] INSTEON PowerLinc USB: http://www.insteon.net/2413U-PowerLinc-USB.html (6 December 2012) [15] INSTEON Hub: http://www.insteon.net/2242-222-insteon-hub.html (6 December 2012) [16] INSTEON Network dimmable light bulb: http://www.insteon.net/bulb.html (6 December 2012)
54
[17] INSTEON Plug-in Appliance On/Off Module: http://www.insteon.net/2456s3appliancelinc.html (6 December 2012) [18] Wikipedia: X10 industry standard: http://en.wikipedia.org/wiki/X10_%28industry_standard%29
55
Mellékletek
A teljes áramkör sematikus rajza 56
26. ábra Az Arduino MEGA fényképe, és kivezetéseinek listája
57