Miskolci Egyetem Gépészmérnöki és Informatikai Kar Elektrotechnikai-Elektronikai Intézet
Villamosmérnöki szak Elektronikai tervezés és gyártás szakirány
8x8x8-as Led-kocka építése és vezérlése
Szakdolgozat
Brogli Péter PDUDRZ 2016
Tartalomjegyzék
1
Bevezetés ................................................................................................................... 3
2
Irodalomkutatás a különböző típusú kijelzők területén [1] ....................................... 4 2.1
2.1.1
Flip-disc kijelző [1] ..................................................................................... 4
2.1.2
VFD - vákuum fluoreszcens kijelző [1] ...................................................... 4
2.1.3
LCD - Folyadék kristályos kijelző [1] ........................................................ 5
2.1.4
EP - Elektronikus papír kijelző [1] ............................................................. 6
2.1.5
PDP - Plazma kijelző [1] ............................................................................ 6
2.1.6
LED - Light Emitting Diode kijelző ........................................................... 7
2.2 3
4
5
Kijelző technológiák [1] ..................................................................................... 4
Multiplexálás ...................................................................................................... 8
A kijelzők vezérlése leghatékonyabban .................................................................... 9 3.1
Bevezetés............................................................................................................ 9
3.2
Tárolós vezérlés [3] ............................................................................................ 9
3.3
Shift regiszteres vezérlés .................................................................................. 10
3.4
FPGA vezérlés ................................................................................................. 11
LED-kocka hardware tervezése és építése [3] ......................................................... 13 4.1
Beszerzés .......................................................................................................... 14
4.2
A LED Mátrix [3]............................................................................................. 15
4.3
LED előtét ellenállás ........................................................................................ 16
4.4
Az egyes panelek kapcsolási rajza ................................................................... 17
4.4.1
4db shift regisztert tartalmazó panelek ..................................................... 17
4.4.2
Táp panel................................................................................................... 18
4.4.3
Multiplexálást végző panel ....................................................................... 19
4.4.4
Animáció generáló panel .......................................................................... 21
LED-kocka software készítése ................................................................................ 23
1
5.1
A PIC16F628A mikrovezérlő [5]..................................................................... 23
5.2
A PIC16F628A programja, multiplexálás........................................................ 24
5.2.1
Konfigurációs bitek beállítása .................................................................. 24
5.2.2
Inicializálások ........................................................................................... 25
5.2.3
Függvények ............................................................................................... 28
5.2.4
A multiplexálás sebessége ........................................................................ 29
5.2.5
Adatok fogadása UART-on ...................................................................... 30
5.3
A PIC18F4550-es mikrovezérlő [6] ................................................................. 31
5.4
A PIC18F4550 programja [7] .......................................................................... 31
5.4.1 5.5
USB firmware [7] ..................................................................................... 32
PC-n futó szoftver [7]....................................................................................... 41
5.5.1
Program.cs ................................................................................................ 41
5.5.2
Form1.cs ................................................................................................... 41
5.5.3
usbDemoDevice.cs ................................................................................... 43
5.6
USB vezérlés, USB-UART átalakítóval .......................................................... 43
6
Összefoglalás ........................................................................................................... 46
7
Summary.................................................................................................................. 47
8
Irodalom jegyzék ..................................................................................................... 48
9
Ábra jegyzék ............................................................................................................ 49
10
Mellékletek .......................................................................................................... 51
10.1
PIC16F628A .................................................................................................... 51
10.2
PIC18F4550 ..................................................................................................... 58
10.3
LED-kocka vezérlő .......................................................................................... 65
10.4
LED-kocka USB-UART átalakítóval .............................................................. 69
2
1
Bevezetés
A mai világban szinte minden feladatot igyekszünk digitális úton megoldani, ehhez elengedhetetlen, hogy a kiszámolt adatokat megjelenítsük a külvilág számára, vagyis kijelezzük azokat. Ma már a mindennapi életünk bármely területén találkozhatunk kijelzőkkel: -
számítógépek monitora
-
televíziók
-
telefonok, táblagépek
-
a menetrend kijelzése buszmegállóknál
-
buszokon a következő megálló kijelzése/pontos idő
-
óriási hirdető panelek a reklámoknak
-
ébresztő órák
-
autó rádiók
Rengeteg féle technológia létezik az információk megjelenítésére, ugyanis különböző eszközöknek különböző elvárásaik vannak. Ezen kívül a technológia előrehaladásával újabb és jobb megoldásokat találtak a mérnökök az egyes kijelzők megvalósítására. Mára már bárhol találkozhatunk digitális megjelenítőkkel, az emberek többsége mégsem tud róluk sok mindent. Engem mindig is érdekelt, hogy hogyan működnek és amint találkoztam egy háromdimenziós LED kockával az interneten, eldöntöttem, hogy készítek egyet magamnak a szakmai kihívás miatt, és mert nagyon megtetszettek. Szakdolgozatomban egy ilyen, USB-n keresztül konfigurálható LED-kocka tervezését és építését fogom bemutatni, a hozzá tartozó programok tervezésével együtt.
3
2
Irodalomkutatás a különböző típusú kijelzők területén [1] 2.1 Kijelző technológiák [1]
Egy pixel megjelenítésére, fénykibocsátására különböző technológiákat fejlesztettek ki: -
Flip-disc
-
VFD - vákuum fluoreszcens
-
LCD - Folyadék kristály
-
EP - Elektronikus papír kijelző
-
PDP - Plazma kijelző
-
LED - Light Emitting Diode
2.1.1 Flip-disc kijelző [1] Ezek a kijelzők elektromechanikai elven jeleznek ki ugyanis egy billenő lemez található minden egyes pixelnél, amiket elektromágnesekkel lehet ki - be, kapcsolni. Amikor áramot folyatnak át az elektromágnes tekercsén, annak mágneses hatása átfordítja a pixel lemezét, aminek az egyik oldala fekete a másik pedig élénk színű, általában sárga. Léteznek olyan változatok amikbe LED-es háttérvilágítást adnak a pixeleknek a jobb láthatóság miatt.
1. ábra Flip-disc kijelző [1]
2.1.2 VFD - vákuum fluoreszcens kijelző [1]
Működési elve: a fluor gerjesztése elektronokkal, ami során a fluoreszcenciát használjuk a kijelzésre. A fémből kilépő elektronokat egy nagyon vékony izzószál és 50V-os rácsfeszültség segítségével felgyorsítják, és amikor azok elérik az anódot, fény emittálódik. Előnye a hosszú élettartama, megbízhatósága és jó kontrasztja. Hátránya, 4
hogy a megjelenítő terület sokkal kisebb, mint a tényleges mérete egy pixelnek, így ezt a technológiát olyan alkalmazásokban használják ahol kevés a megjelenítendő adat. Általában 7 szegmenses vagy speciális felosztású kijelzők, de nem mátrix elrendezésű. Leghétköznapibb példa rá a HI-FI berendezésekben lévő megjelenítő.
2. ábra - VFD - vákuum fluoreszcens kijelző [1]
2.1.3 LCD - Folyadék kristályos kijelző [1]
3. ábra Folyadék kristály [1]
A folyadékkristályos kijelzők működési elve, hogy a háttérvilágítást ki - be tudjuk kapcsolni. Ha a kristályok enyhén rovátkolt felülettel érintkeznek, beállnak azzal párhuzamosan. A folyadékkristály réteget két ilyen réteg közé tesszük, ahol alap állapotban a kristályok beállnak a rovátkoltságnak megfelelően és egy csavart szerkezetet vesznek fel, ami miatt a fény átjut a két db 90°-al elforgatott polarizált 5
szűrőn. Amikor feszültséget kapcsolunk rá, akkor a kristályok nem forgatják el a fényt így nem, vagy csak kis mértékben engedik át. Leggyakrabban használt folyadékkristályok: nematikus, koleszterikus és szmektikus.
2.1.4 EP - Elektronikus papír kijelző [1]
Az elektronikus papír kijelzőket 1970-ben kezdték el fejleszteni, de csak 2004-ben jelent meg az első e-book olvasó a Sony fejlesztésével. A technológiát azért fejlesztettét ki hogy a nyomtatott szöveg olvasásának kényelme megmaradjon. Működése hasonlít a flip-disc-éhez ugyanis itt minden pixelben apró mágnesezett, a mágnesezettség szerint festett golyók vannak, amik alatt és felett állítható mágneses tér van. Ennek a mágneses térnek a kapcsolgatásával egyszer a fekete másszor a fehér oldal kerül felülre.
4. ábra EP - Elektronikus papír kijelző [1]
2.1.5 PDP - Plazma kijelző [1]
A plazma kijelzők működési elve: a három alapszínt kell tudni külön vezérelni ahhoz, hogy egy színes pixelt kapjunk. A neon és xenon gázok keverékét elektródák segítségével begyújtják, ami során UV sugárzás kíséretében a pixelnek megfelelő színű fény sugárzódik ki. Előnye, a tökéletes színvilág, nagy betekintési szög. Hátránya hogy beéghet egy idő után a kijelző bár az újabb modelleknél már nem tapasztalható ez a jelenség.
6
5. ábra PDP - Plazma kijelző [1]
2.1.6 LED - Light Emitting Diode kijelző
LED kijelzőket egyre gyakrabban használnak, mivel rendkívül jó fényereje van, az utcákon reklám megjelenítésére tökéletesen alkalmas akár nappal is. 2.1.6.1 LED-ek működése [2] A LED lényegében egy dióda, amire ha nyitó feszültséget kapcsolunk, a p-n átmenet szennyezettségétől függő hullámhosszúságú fényt bocsát ki. A LED áramvezérelt eszköz, minél nagyobb áram folyik a diódán, annál nagyobb fényt bocsát ki. Az áram gerjeszti az atomok elektronjait, amik ettől nagyobb energiaszintű elektronpályára lépnek, majd amikor visszatérnek az előző energiaszintre fotonokat bocsátanak ki. Előnyei: olcsó, hosszú élettartamú, energiatakarékos, gyors kapcsolású és kültéri berendezéseknél is használható. 2.1.6.2 LED háttérvilágítás [1] A LED-es háttérvilágítást használnak manapság az LCD kijelzőkben is, mivel előnyösebb jellemzőkkel bír a hagyományos háttérvilágításnál: -
jobb kontraszt arány
-
keskenyebb készülék
-
több szín
-
20 – 30%-al kevesebb energiafogyasztás 7
2.1.6.3 LED kijelzők [1] Az LCD kijelzőkön kívül hatalmas hirdető tábláknál is használják a LED-eket, LED mátrixokat létrehozva. Ezeket a mátrixokat modulárisan hozzák létre tehát több LED mátrix összekapcsolásából alakul ki egy nagyobb kép. Ez azért is előnyös, mert könnyű szállítani, és olyan méretű kijelzőt rakhatunk össze, amilyenre szükség van.
2.2 Multiplexálás
Ha egy LED-ekből álló kijelzőt szeretnénk vezérelni, szükségünk lesz rengeteg LED-re és egy meghajtó áramkörre, ami legyen egy mikrovezérlő. Az első probléma, amivel szembesülünk, hogy nincs elegendő lába a mikrovezérlőnek, hogy vezérelni tudja önmagában a LED-eket. Ezt a problémát multiplexeléssel tudjuk megoldani. Vegyünk egy 4x4 es LED mátrixot, ha multiplexelve vezéreljük, az azt jelenti, hogy az egyes sorokat, sorban aktiváljuk és mindig az adott sorban megfelelő adatot írjuk ki. Ezt olyan gyorsan kell ismételnünk, hogy a szemünk ne legyen képes érzékelni a váltásokat, amit körülbelül 100Hz en vagy a fölött kell tennünk. Ennek a mátrixnak a vezérléséhez összesen 8 db láb szükséges, 4 sor és 4 oszlop, ennyi lába még van egy mikrovezérlőnek, viszont ha egy 16x16-os mátrixot szeretnénk vezérelni, akkor, ki kell bővítenünk valamilyen módszerrel a mikrovezérlő IO számát. Erről a harmadik részben lesz szó.
8
3
A kijelzők vezérlése leghatékonyabban
3.1 Bevezetés A hatékonyság relatív fogalom, ahhoz hogy meg tudjuk határozni a számunkra leghatékonyabb megoldást, előbb azokat a jellemzőket kell meghatározni, amelyekre optimalizálni szeretnénk a tervet. Ilyen jellemző lehet az áramkör sebessége, mérete, vagy épp a szoftver megírásának egyszerűsítése, és még sok minden más. Egy egyszerűbb 8x8x8-as LED-kockát fogok megvizsgálni több féle megoldással, mert annak működése nagyvonalakban megegyezik a többi kijelző működésével, azonban könnyebb megérteni. A LED-kocka egy háromdimenziós kijelző, amin a pixelek LED-ek, és ezek mátrix elrendezésben vannak összeillesztve, lehetőleg távol egymástól hogy minél könnyebben át lehessen látni a kijelzőt. A meghajtásról általában egy egyszerű mikrovezérlő gondoskodik. Az alábbi példákban csak az oszlopok értékeinek beírásáról lesz szó mivel ez a legkritikusabb része a kapcsolásnak, sebesség és méret szempontjából.
3.2 Tárolós vezérlés [3] Az alábbi összeállítással találkoztam legtöbbször az interneten -
8 bites adatbuszon keresztül íródnak az adatok a 8 db 74HC574 es tároló regiszterekbe.
-
az összes tároló regiszter közös órajellel működik, amit a mikrovezérlő szolgáltat
-
egy 74HC138N demultiplexer gondoskodik a tárolók címzéséről, aminek a bemenetét szintén a mikrovezérlő vezérli így mindig csak egy tárolóba írunk adatot
9
6. ábra Tárolós vezérlés kapcsolása [3]
A 8 bites busz miatt ez gyorsabb adatírást tesz lehetővé, viszont mivel a 8 darab vezetéket minden egyes mikrovezérlő adatbemeneteihez el kell vezetni, az áramkör mérete nagyobb lesz és bonyolultabb.
3.3 Shift regiszteres vezérlés Ennél a vezérlésnél 8 db 74HC595-ös shift regiszter és tároló regiszter van sorba kapcsolva. Ez egy olyan chip, ami a betöltött adatot el is tudja tárolni. A sorba kapcsolás úgy történik, hogy az első shiftregiszter soros kimenetét, a második shift regiszter adatbemenetére kötjük, ugyan így a többit is, az egyes chipek azonos vezérlő bemeneteit pedig összekötjük, így egyszerre vezéreljük az összest.
10
Ez a kapcsolás sokkal egyszerűbb, kevesebb vezetékezést igényel, és a mikrovezérlőn is spóroltunk a lábakkal. Hátránya viszont hogy sebessége, nyolcada az előző kapcsolásnak. Ezen kapcsolások lassúságát a soros adatírás okozza, egyszerű mikrovezérlővel nem tudunk jobb megoldást, viszont az egész vezérlő áramkör FPGA-ba helyezése a párhuzamos működés miatt nagyságrendekkel gyorsabb megoldás lenne. Az összes kapcsolás, amit találtam, csak egy mikrovezérlőt tartalmazott, aminek így két feladatot is el kell látnia, ami a program megírását nagyban megnehezíti. -
el kell végeznie a multiplexelést
-
generálnia kell az animációt
Ezt a problémát megoldhatjuk úgy, hogy a multiplexelést automatizáljuk, erre három módot találtam. -
TTL vagy CMOS alkatrészek felhasználásával
-
második mikrovezérlővel
-
FPGA val
TTL vagy CMOS alkatrészek felhasználásával tervezhetünk olyan hálózatot, ami automatikusan frissíti és multiplexeli a képet egy tárolóból ahova a mikrovezérlő írja az új képkocka adatát ezzel frissítve a képet. Ennek hátránya a nagy méret. Második mikrovezérlővel ugyan azt a feladatot látjuk el, amiről az előbb szó volt, csak még ott hardveresen valósítottuk meg, itt szoftveresen. Ennek előnye a nagyon kis méret. FPGA-val lényegében a TTL vagy CMOS alkatrészekkel megtervezett kapcsolást van lehetőségünk kompaktabb formában megvalósítani.
3.4 FPGA vezérlés Egy kellő kapacitással és lábszámmal rendelkező FPGA-val könnyen megvalósíthatunk olyan nagy áramköröket, amiket ha külön alkatrészekkel akarnánk megvalósítani, hatalmas panelt kapnánk.
11
Előnyei: -
rendkívül gyors a párhuzamos futásnak köszönhetően
-
ha elég lábszámmal és kapacitással rendelkezik, akkor bele lehet tervezni az egész vezérlést
-
helytakarékos
Hátrányai: -
drágább
-
a program és hardver megírásához a C nyelvtől nagyban eltérő nyelvet kell megismernünk és elsajátítanunk a VHDL-t vagy a Verilog-ot.
7. ábra Altera Cyclone 4 es FPGA [4]
12
4
LED-kocka hardware tervezése és építése [3]
A tervezést kutatással kezdtem, tanulmányoztam mások által készített LED-kockákat, hogy megértsem a működésüket. Ezek után a tervezésem szempontjai a következők voltak: -
olyan tervet megvalósítani, amit máshol még nem láttam
-
a lehető legkevesebb pénzből
-
a lehető legegyszerűbb kapcsolást tervezni, hogy minél kisebb legyen az áramkör.
Mindezen szempontokat figyelembe véve megszületett a tervem. A főbb változtatást az jelenti az interneten található többi kockához képest, hogy az enyémben kettő darab mikrovezérlő
végzi
a
vezérlést.
Egy
PIC16F628A
gondoskodik
a
kijelző
multiplexálásáról, és egy PIC18F4550 az animációkat generálja. A két vezérlő UART kommunikáción keresztül kommunikál egymással. Ezen felül, ahol mások nyolc vezetékes buszt használtak a 64 bit kiírására, egyszerű tárolókba, ott én 8 db SN74HC595-ös (shift regiszter és tároló) chipet kötöttem sorba. Ami azért előnyös, mert így sokkal kevesebb vezetékre van szükség, mint az előbbi példánál. Hátránya viszont, hogy 8-ad akkora sebességre képes, ám a gyakorlatban ez a sebesség is tökéletesen elegendő a kijelzéshez.
8. ábra Általam készített LED-kocka
13
4.1 Beszerzés Amint a tervem összeállt a fejemben megrendeltem minden alkatrészt hozzá. Amit csak tudtam ebay-en rendeltem meg mivel ott lehet a legolcsóbban hozzájutni elektronikai alkatrészekhez, ráadásul legtöbbször ingyen szállítják. Ennek a hátránya, hogy sokat kellett várni mire megérkeztek. 1. táblázat Alkatrészlista Sorszám
Név
Érték/tulajdonság
Darabszám
1
Kerámia kondenzátor
100nF
14
2
Kerámia kondenzátor
330nF
1
3
Kerámia kondenzátor
22pF
4
4
Elektrolit kondenzátor
100uF
2
5
Tüskesor csatlakozó anya
20pin
4
6
Tüskesor csatlakozó anya
8pin
6
7
Tüskesor csatlakozó apa
6pin
2
8
Tüskesor csatlakozó apa
20pin
4
9
Tüskesor csatlakozó apa
8pin
6
10
DC tápcsatlakozó
5.5x2.1mm
1
11
BS170 FET
-
8
12
Ellenállás
10k
10
13
Ellenállás
330Ω
64
14
SN74HC595
-
9
15
PIC18F4550
-
1
16
PIC16F628A
-
1
17
LM7805CT
-
1
18
Kvarc
20Mhz
2
19
LED
3mm kék diffúz
512
20
IC foglalat
16pin
9
21
IC foglalat
18pin
1
22
IC foglalat
40pin
1
23
Próbapanel
60*40 furat
1
24
Próbapanel
24*18 furat
2
25
Próbapanel
24*10 furat
3
26
USB B csatlakozó
-
1
27
Toló kapcsoló
-
1
14
Amint látszik rengeteg tüskesor és próbapanel van az alkatrészlistában. Ezekre azért van szükség, mert modulárisra terveztem az eszközt, tehát külön panelekből állítható össze. Ennek legfőbb oka, hogy ez egy prototípus, aminél fontos, hogy egyszerűen módosítható legyen az esetleges fejlesztések miatt. Az alaplapra (60*40 lyukat tartalmazó panelre) vannak forrasztva a LED-ek, az apa tüskesor csatlakozók (kivéve a kettő db 6 pin es csatlakozót, ezek a programozó lábak), az előtét ellenállásokat és az egyes paneleknek a kapcsolatai itt vannak megvalósítva. Panelek: -
Alaplap (60*40)
-
4db Shift regisztert tartalmazó panel (24*18)
-
4db Shift regisztert tartalmazó panel (24*18)
-
Multiplexálást végző panel (24*10)
-
Animáció generáló panel (24*10)
-
Táp panel (24*10)
9. ábra A LED-kocka alulról, láthatók a panelek
4.2 A LED Mátrix [3] A LED mátrixban definiálhatunk oszlopokat és szinteket, 64 db oszlop és 8 db szint van egy 8x8x8-as mátrixban. A multiplex vezérlésnek megfelelően az egy oszlopban lévő LED-ek anódjai csatlakoznak egymáshoz, a katódokat viszont szintenként forrasztottam össze, tehát az egy szinten lévő LED-ek katódjai csatlakoznak egymáshoz.
15
A beszerzés során figyelni kell, hogy milyen LED-et veszünk, mivel sokformájú és fényű van a piacon. A legoptimálisabbak a Straw Hat, Diffúz, 3mmesek. -
A Straw Hat arra utal, hogy lapos LED-ről van szó, aminek a jellemzője, hogy nagyobb, 120°os szögben sugározza a fényt, ami jobb láthatóságot biztosít és maga a LED is pontszerűbb, mint a hagyományos csúcsosabb, ami egy LEDkocka esetében előnyösebb.
-
Diffúznak pedig azokat nevezzük, amiknek a tokozása nem tiszta, átlátszó, hanem anyagában homályosított, így jobban szórja a fényt, ami szintén javíthatja a láthatóságot.
-
3mm es LED-ek pedig azért előnyösek az 5 vagy 10mm es társaikkal szemben, mert kisebbek így a mátrixot jobban át lehet látni, ami nagyon fontos, mivel a LED-kocka lényege, hogy egy térbeli kijelző.
10. ábra Round top 5mm
11. ábra Straw Hat 5mm LED
12. ábra Diffúz 3mm LED
LED
Mind ezek mellett célszerű szuper erős LED-et vásárolni, mert a multiplexálás miatt, a fényerejük, csak a nyolcada lesz az eredeti fényerejüknek.
4.3 LED előtét ellenállás Az előtét ellenállásokat az oszlopokkal kell sorosan kötni, mivel az időben egyszerre csak egy szint világít tehát oszloponként mindig csak egy LED. Az ellenállás értékét a shift regiszterek áram terhelhetősége szabta meg, ami 70mA. 330Ω-os ellenállás választottam, mert ennél az ellenállásnál, 5V-nál egy LED-en 6,5mA áram folyik, ami azt jelenti, hogy egy db shift regiszter 8db kimenetén, ha mindegyik LED világít, akkor 52mA folyik a chipen keresztül, ami a határértéken belül van. 16
4.4 Az egyes panelek kapcsolási rajza 4.4.1 4db shift regisztert tartalmazó panelek
13. ábra 4db shift regisztert tartalmazó panel
Ezekből kettőt készítettem, amik sorba vannak kötve, mivel 8db shift regiszter kellett.
14. ábra 4db shift regisztert tartalmazó panel kapcsolási rajza 17
A másik panelen levő csatlakozók, a J3 és a J4. Amint látszik a kapcsolásokon is, sorba kapcsolásról van szó, vagyis az első chip QH_ kimenete, a második chip SER bemenetére kapcsolódik és így tovább. A SER bemeneteken kívül a többi bemenetek közül az azonosak össze vannak kötve és ki vannak vezetve a J1 J2 J3 és J4 csatlakozókra. A Q kimenetek a LED oszlopokhoz csatlakoznak, közvetlenül szolgáltatják az áramot a LED-eknek. Ezeken kívül találhatók még kondenzátorok a kapcsoláson, amik közvetlenül a VCC és a GND lábak között vannak, hogy kiszűrjék a chipekre káros, hirtelen feszültség ingadozásokat.
4.4.2 Táp panel
15. ábra Táp panel
A Táp panelen egy egyszerű LM7805CT feszültségszabályzó kapcsolás van, ami két 100uF-os kondenzátor a bemeneti és a kimeneti oldalon, és egy 100nF-os kondenzátor a kimeneti oldalon. A feszültségszabályzó bementére 6-15V-ig terjedő tartományban kapcsolhatunk
feszültséget,
ezt
5V-ra
szabályozza
az
eszköz
számára.
A
Tápfeszültséget egy kapcsolón keresztül ki-be kapcsolhatjuk. Végül itt kapott helyt az USB B csatlakozó, mivel itt fért el, ennek a D- és D+ lábát a 18f4550 es mikrovezérlő D- és D+ lábára csatlakoztatjuk a GND lábát pedig a földre kötjük.
18
16. ábra Táp panel kapcsolási rajza
4.4.3 Multiplexálást végző panel
17. ábra Multiplexálást végző panel kapcsolási rajza 19
Ezen a panelen egy PIC16F628A mikrovezérlő dolgozik, ehhez egy alapkapcsolásra van szükség, ami 3 dologból áll: -
az órajelet generáló 20Mhz-es kristály kapcsolásából, aminek a lábai az RA6 és RA7 lábakra kapcsolódnak, és ezen kívül egy-egy 22pF-os kondenzátorokon keresztül a fölre vannak kötve,
-
az MCLR vagyis reset láb 10kΩ-os felhúzó ellenállásából és egy 100nF-os szűrő kondenzátorából áll, ami a földhöz kapcsolódik
-
és egy 100nF-os szűrő kondenzátorból, ami a chip VCC és GND lábához kapcsolódik közvetlenül, hogy kiszűrje a chipekre káros, hirtelen feszültség ingadozásokat.
18. ábra Multiplexálást végző panel
A C11 szintén szűrő kondenzátor, ami a shiftregiszteré. A mikrovezérlőhöz csatlakozik egy shift regiszter, ami az egyes szinteket képes aktiválni azzal, hogy a FET-ek segítségével a földre köti a megfelelő szint LED-jeinek katódjait. -
a szintek a J7 csatlakozón keresztül érkeznek be
-
a PIC programozó lábak, vagyis az MCLR, VCC, GND, PGD, PGC az alaplapon keresztül az Animációt generáló panelbe megy, ahol lehet csatlakoztatni a programozóhoz, erre azért volt szükség, mert a Multiplexálást végző panel középen van
-
A TX és RX lábakon kommunikál a két mikrovezérlő egymással, az egyik chip TX lába a másik chip RX lábához csatlakozik és ugyan így fordítva is
-
A mikrovezérlő CCP lába, azaz a PWM kimenete a 8 db sorba kötött shift regiszterek OE engedélyező bemeneteire csatlakozik, amivel a kocka fényerejét lehet vezérelni
-
A SER RCLK és SRCLK a 8db sorba kapcsolt shiftregiszter vezérlő lábai
20
4.4.4 Animáció generáló panel
19. ábra Animációt generáló panel
Ezen a panelen is megtalálhatók a mikrovezérlő 3 alapkapcsolása: -
az órajel generáló kapcsolás a 20Mhz es kristállyal és a 22pF-os kondenzátorokkal
-
az MCLR láb felhúzó ellenállásával és a szűrő kondenzátorával
-
és a VCC és GND lábak körötti szűrő kondenzátorral.
20. ábra Animációt generáló panel kapcsolási rajza Egyéb kapcsolatok: 21
-
a J9 csatlakozó a PIC18F4550-nek a programozó csatlakozója, az MCRL, VCC, GND, PGD és PGC láb kivezetésekkel
-
a J8 csatlakozó a PIC16F628A-nak a programozó csatlakozója
-
a J12 csatlakozón ki vannak vezetve az analóg bemenetek későbbi fejlesztési célból
-
a J10 es csatlakozón pedig a TX és RX lábak vannak kivezetve, amin keresztül kommunikál a két mikrovezérlő.
-
az USB hardvernek szüksége van egy 330nF-os kondenzátorra a VUSB láb és a föld között
22
5
LED-kocka software készítése
A hardver kialakítása miatt a program megírása három részre tagolódik: -
a PIC16F628A programja, ami a multiplexálásért felel
-
a PIC18F4550 programja, ami az animáció generálásáért felelős, ez tartalmazza az USB firmwaret is, ami a számítógéppel való kommunikálást valósítja meg
-
és a PC n futó program, ami kommunikál a PIC18F4550-es chip-el USB-n keresztül így vezérelve a LED-kocka működését.
5.1 A PIC16F628A mikrovezérlő [5] A 16F628A egy 8 bites mikrovezérlő, RISC utasításkészletű CPU-val, ami maximum 20MHz es külső forrásból származó órajellel képes működni. 18 lába van, néhány ezek közül több funkciót is elláthat, persze egyszerre csak egyet. Kettő darab IO port található rajta a PORTA és a PORTB, mind a kettő 8 bites, ezek lefoglalnak 16 lábat, a maradék kettő a VDD és a GND. A mikrovezérlő rendelkezik: -
analóg-digitális
konverterrel,
aminek
4db
bemenet
áll
rendelkezésére
multiplexelve, -
2 db 8 bites időzítő/számlálóval: Timer0 és Timer2, és 1 db 16 bites időzítő/számlálóval: Timer1,
-
külső események vagy belső periféria események kezelésével, megszakításos módszerrel,
-
CCP modullal (Capture Compare PWM)
-
USART modullal
-
Eeprom memóriával
-
és még egyéb dolgokkal, de azok nem relevánsak a projektem szempontjából.
23
5.2 A PIC16F628A programja, multiplexálás
A PIC-ek programjait a Microchip saját fejlesztő környezetében írtam, C nyelven, aminek a neve MPLAB X IDE. A kód 16F628A-ra fordításra, az XC8-as fordítót használtam.
5.2.1 Konfigurációs bitek beállítása Az első lépésként a konfigurációs bitek beállítását kell elvégezni. Nagy odafigyeléssel kell kiválasztani, hogy melyik konfiguráció felel meg a mi elképzeléseinknek, mivel sokszor előfordult a PIC-ekkel való foglalkozásom során, hogy egy rossz beállítás miatt nem indult el vagy folyamatosan újraindult a program. A fejlesztőkörnyezetben kapunk leírást is az egyes bitek beállításaihoz, nekünk csak ki kell választani azokat és a program legenerálja a megfelelő C-kódot, amit nekünk csak be kell másolni a programunkba. Ez a kód tartalmazza az „xc.h” header file behívását is, amire szüksége van a fordítónak.
21. ábra 16F628A konfigurációs bitjei
24
Néhány fontosabb konfigurációs beállítás: -
Az oszcillátor típusát HS re azaz high speed-re állítottam mivel 20MHz-es kristályt használok órajel forrásnak.
-
WDT (Watch Dog Timer): ez egy védelmi áramkör, számláló, ha a túlcsordulás előtt nem indítjuk újra, megállítja a program futását. Kikapcsoltam mivel nincs rá szükségem.
-
PWRT (Power Up Timer): késleltető áramkör, lényege, hogy elegendő időt kapjon a tápfeszültség a megfelelő érték beállására, induláskor. Engedélyeztem.
-
MCLRE (MCLR Enable): Reset láb aktiválása. Engedélyeztem.
-
BOR (Brown Out Reset): a tápfeszültség egy meghatározott szint alá csökkenésekor aktiválódik. Engedélyeztem.
-
LVP (Low Voltage Programing): alacsony feszültségű programozáshoz szükséges. Kikapcsoltam.
-
CPD: adat memória kódvédelme. Kikapcsoltam.
-
CP: flash memória kódvédelme. Kikapcsoltam.
5.2.2 Inicializálások Ez után megadtam a beépített kristály órajelét hertzben (20000000Hz), hogy az XC8-as fordító beépített késleltető függvényei megfelelően működjenek. A chip használt lábainak neveket definiáltam a kód átláthatósága és könnyebb változtathatósága miatt, így ha a lábkiosztást a hardware-en megváltoztatom, elég csak a definícióban átírni a változást.
22. ábra 16F628A definiált nevei és órajele
25
Utána jönnek a függvények és a main függvény. A main függvényben az első dolgom az inicializálásokat elvégezni. A program átláthatósága érdekben külön függvényekbe helyeztem az egyes modulok inicializálásához szükséges műveleteket. A main_init() függvény meghívásakor: -
A CMCON regiszterbe 7 et írtam, ezzel digitálisra állítva az összes IO-t.
-
A TRISA és TRISB regiszterek nullázásával beállítom, hogy az összes IO kimenet legyen.
-
A PORTA és PORTB regiszterek nullázásával pedig nulla kezdőértéket állítok be az összes IO-nak.
23. ábra 16F628A main_init() függvénye
Mostantól ha egy bit beállításáról illetve törléséről beszélek, akkor annak a bitnek az értékének az 1-re illetve 0-ra való állításáról van szó! Az UART_init() függvény meghívásakor beállítom az USART modult, hogy a nekem megfelelő módon működjön. -
SPEN bit beállításával bekapcsoljuk a modult,
-
TRISB1 és TRISB2 beállításával az RB1 és RB2 lábakat RX és TX lábakká definiálom
-
SYNC bit törlésével az aszinkron kommunikációt választom ki
-
CREN bit beállításával engedélyezem az adatok folyamatos fogadását
-
TXEN bit törlésével nem engedélyezem az adatok küldését
-
RX9 bit beállításával a 9 bites adatfogadást állítom be
-
végül a BRGH bit beállításával és az SPBRG regiszter 4 re való állításával beállítjuk az UART kommunikáció Baud rate-jét 250000Hz-re 26
A Baud rate kiszámításához a PIC adatlapjában lehet találni képletet, és különböző kristályoknál előre kiszámolt értékeket is. A képlet aszinkron kommunikációnál és beállított BRGH bittel (tehát magas baud rate módban): Br = FOSC/(16*(X+1)) Ahol X az SPBRG regiszter értéke, FOSC a kristály frekvenciája és Br a Baud rate. Rendezés után azt kapjuk, hogy: X = (FOSC/(Br*16)) – 1 és ha behelyettesítjük a 20MHz es kristályt és 250000 es Br-t akkor 4 et kapunk X-re.
24. ábra 16F628A UART_init() függvénye
Az interrupt_init() függvény meghívásakor az UART kommunikáció miatt állítom be az magszakítás kezelést az RCIF jelzőbitre, ami akkor aktiválódik, ha adat érkezett. -
GIE bit beállításakor a Globálisan engedélyezem a megszakításkezelést,
-
PEIE bit beállításakor a Periféria megszakításokat engedélyezem
-
RCIE bit beállításakor az UART kommunikáció adatfogadó megszakítását engedélyezem
Az UART megszakítása csak akkor lép érvénybe, ha mind a három bitet beállítottuk.
25. ábra 16F628A interrupt_init() függvénye 27
Az Timer2_init() függvény meghívásakor alaphelyzetben hagytam mindent csak annyit csináltam, hogy bekapcsoltam a kettes időzítőt a TMR2ON bit beállításával, erre a PWM miatt van szükség mivel ezt az időzítőt használja.
26. ábra 16F628A Timer2_init() függvénye
Az PWM_init() függvény meghívásakor a PWM funkciót állítjuk be, ami a kocka fényerejének szabályzásához kell. A CCP1M négy darab bitjével a PWM módot választjuk ki: CCP1M0=0, CCP1M1=0, CCP1M2=1, CCP1M3=1. A PR2 regiszter felel a periódusidő beállítására, 200-at adtam meg neki. Aztán töröljük a TRISB3 bitet, hogy a PWM kimeneti lába kimenet legyen. Majd a kitöltési tényező beállításáért felelős regisztereknek nulla kezdőértéket állítunk be: CCP1X=0, CCP1Y=0, CCPR1H=0, CCPR1L=0. A CCPR1L értékét fogom csak állítgatni az egyszerűség kedvéért, 0 és 200 között, 0-nál lesz 100%os és 200-nál lesz 0%os a kitöltési tényező.
27. ábra 16F628A PWM_init() függvénye
5.2.3 Függvények Mivel 8 bites mikrovezérlőről van szó a LED-ek és a fényerő értékeit egy unsigned char típusú 65 elemű tömbben tárolom, aminek a neve „sz”. Azért char típust választottam, mert az XC8-as fordítónál ez a típus 8 bites, így tökéletes a LED-kocka aktuális képének tárolására. A hardware kialakítás miatt ennek a mikrovezérlőnek kettő darab shiftregisztert illetve shiftregiszter láncot kell vezérelnie, az oszlopokét és a szintekét. Ezek kezelésére külön függvényeket írtam, a write_data1() az oszlopokat vezérli a write_data2() pedig a 28
szinteket. Ezekben a függvényekben sokszor fordul elő, hogy léptetni kell a shiftregisztereket, azaz pulzálni kell a lábakat ezért írtam egy-egy függvényt az összes ilyen lábhoz: SRCLK1, RCLK1, SRCLK2, RCLK2. Ezek annyit tartalmaznak, hogy az adott lábat 1-re állítják majd vissza 0-ra. Mindezt hozzáadott késleltetés nélkül teszik, hogy minél nagyobb sebességet érjünk el.
28. ábra 16F628A write_cube() függvény részlete
A main függvényben az inicalizálások után csak egy végtelen for ciklus van, amiben a write_cube() fut folyamatosan. A write_cube() végzi a ledkocka képének folyamatos frissítését, sorra írja ki az „sz” tömbben lévő adatokat a megfelelő sorrendben. A multiplexálásnak megfelelően először kilépteti a shiftregiszterekbe az első szint adatait, az OE lábbal letiltja a kijelzést, kiírja a beléptetett adatokat a tároló regiszterekbe, aktiválja az első szintet, végül engedélyezi a kijelzést az OE láb 0-ra állításával és ezt folyatatja sorba az összes szinttel, majd kezdi elölről, és így tovább. 5.2.4 A multiplexálás sebessége A programban nincs beiktatva késleltetés, minden a lehető leggyorsabbra van állítva, hogy a multiplexálási frekvencia elég nagy legyen ahhoz, hogy ne lehessen észrevenni. Ennek a frekvenciának a meghatározására elvégeztem egy mérést. Beállítottam egy időzítőt hogy a write_cube() függvény előtt kezdjen el számolni és miután egyszer lefutott, az után hagyja abba a számolást. Majd kiolvastam az mért adatot és kijeleztem két sor LED-re ugyanis 16 bites számlálóról van szó. A leolvasás és a binárisból 29
decimálisba váltás után 3031-et kaptam. Az időzítő a beállítások miatt a kristály frekvenciájának a 32-ttedével üzemel, ami azt jelenti, hogy a periódus idő = 1,6us. Ahhoz hogy megkapjuk a multiplexálás periódusidejét, össze kell szoroznunk az időzítő periódus idejét a kapott értékkel. A multiplexálás periódus ideje = 4,85ms, ami frekvenciába átszámolva 206,2Hz-et kapunk, ami tökéletesen megfelel ahhoz, hogy ne lássunk zavaró villogást a kijelzőn. 5.2.5 Adatok fogadása UART-on Eddig szó volt az adatok kijelzéséről, de arról nem, hogy hogyan frissülnek ezek az adatok. A 18F4550 es PIC UART kommunikáción keresztül küldi el az új kép adatait, ami 65 darab bájtból áll. 64 a kép adatai az utolsó pedig a fényerőé. Sokat gondolkoztam, hogy tudnám egyszerűen átvinni az adatokat úgy, hogy azok a megfelelő helyre kerüljenek. Arra a megoldásra jutottam, hogy 9 bites adatátvitelt használok és az első bájtnál a 9. bitet 1-re állítom, míg a többinél 0-ra, így a program tudni fogja, hogy melyik az első bájt és a következőket a megfelelő helyre fogja tenni.
29. ábra 16F628A megszakítás kezelő függvénye
Ha adat érkezik, az RCIF jelzőbit aktiválja a megszakítást, és elindítja a myIsr() függvényt. Első lépésként megvizsgáljuk a kilencedik bitet, ha 1 akkor 0-ra állítjuk a számláló értékét, amit arra hoztam létre globálisan, hogy számolja hogy épp hányadik bájt érkezett meg. Aztán az „sz” tömbben a számláló értékének megfelelő helyre másoljuk a beérkezett bájtot, végül növeljük a számláló értékét egyel. Ekkor lekezeltük a beérkező adatokat, az összes a beérkezési sorrendben, az „sz” tömbben van, így ha legközelebb lefut a write_cube() függvény már az új adatokkal fogja frissíteni a kockát. 30
Már csak a fényerő adatát kell értékül adni a PWM modulnak, vagyis a CCPR1L regiszternek. Mivel csak egyszer szeretném, hogy frissüljön a fényerő egy képfrissítés alkalmával, ezért akkor történik az értékadás, amikor a következő bájt kilencedik bitje egyenlő 1-el. Ez azt jelenti, hogy a fényerő egy képkockát csúszik, de mivel a fényerőállítást ritkán használom, ez nem okoz gondot.
5.3 A PIC18F4550-es mikrovezérlő [6] A 18F4550-es szintén egy 8 bites mikrovezérlő, RISC utasításkészletű CPU-val, 4 féle kristály móddal, amikkel az USB működéséhez szükséges 48MHz ez is elérhetjük, és egy belső oszcillátort is tartalmaz, amit 31kHz-től 8MHz-ig lehet állítani. 40 lába van, néhány ezek közül több funkciót is elláthat, persze egyszerre csak egyet. Öt darab IO port található rajta a PORTA, PORTB, PORTC, PORTD, és a PORTE. A mikrovezérlő rendelkezik: -
10 bites analóg-digitális konverterrel, aminek 8db bemenet áll rendelkezésére multiplexelve,
-
4 db időzítővel/számlálóval: Timer0, Timer1, Timer2 és Timer3,
-
külső események vagy belső periféria események kezelésével, megszakításos módszerrel,
-
CCP modullal (Capture Compare PWM),
-
USART modullal,
-
MSSP modullal, ami az SPI és az I2C kommunikációt képes megvalósítani
-
Eeprom memóriával,
-
USB 2.0 Hardverrel
-
és még egyéb dolgokkal, de azok nem relevánsak a projektem szempontjából.
5.4 A PIC18F4550 programja [7] Először a programot USB vezérlés nélkül írtam meg, mivel animációkat akartam rá írni, és csak ezek után néztem utána az USB firmware-nek. A programot XC8-ba írtam meg aztán később át kellett írnom C18-ra mivel az USB firmware amit találtam a neten C18-ban íródott. A PIC-ek programozását XC8-as 31
fordítóval tanultam meg, ami szintén C nyelvet használ, mint a másik C18-as fordító, a kettő között csak szintaktikai különbségek vannak így nem volt nehéz átírni. A gyártó (Microchip) gondoskodott az USB firmware-ekről. Létezik egy könyvtár, amit ők készítettek Microchip Solutions névvel 2011-ben. Sajnos ez a legfrissebb verzió, éppen ezért nem XC8-ban íródott. Ez a könyvtár tartalmaz példaprogramokat is különböző típusú chipekre és a PC re is, azonban sajnos az általam választott eszközre nem. Próbálkoztam átírni az egyik példaprogramot, eljutottam odáig hogy sikeresen lefordult és feltöltődött a mikrovezérlőmre viszont a hozzá tartozó PC oldali program nem tudott vele kommunikálni. Egy kis keresgélés után a neten rátaláltam egy programpárra, amit teszteltem és működött, ezeket a programokat írtam át a saját elképzelésemre. 5.4.1 USB firmware [7] Az USB firmware egy általános HID eszközt valósít meg, ami egy szabvány, a Windows automatikusan felismeri és tudja kezelni. A talált eszköz egy LED ki-be kapcsolását tudta végrehajtani PC-ről, és ki tudta jelezni a LED és egy nyomógomb állapotát, mindezt egy C Sharp programmal. Ahhoz hogy le tudjam fordítani a programot, a könyvtárat tartalmazó Microchip Solution mappát és a firmwaret tartalmazó mappát egy közös mappába kellett helyezni, hogy a projekt el tudja érni a könyvtárakban lévő függvényeket. Ez után meg nyitottam a projektet MPLAB-ban és innentől már lefordult a program, írhattam a saját verziómat. Az egész projekt több fájlból áll, a fontosabbak közülük: -
main.c
-
debug.c
-
debug.h
-
usb_device.c
-
usb_function_hid.c
-
usb_descriptors.c
-
usb_config.h
-
HardwareProfile.h
-
program_functions.h
-
programs.h 32
5.4.1.1 Debug funkciók A debug.c és a debug.h ahogy azt a neve is mutatja olyan függvényeket tartalmaz amik a hibaelhárítást segítik. Három függvényt tartalmaz.
30. ábra 18F4550 debug függvényei A debugInitialise() inicializálja a szükséges változókat, nulla kezdőértéket állít be nekik. A debugOut() bemásolja a megadott szöveget egy maximum 128 bájt hosszú tömbbe. A copyDebugToSendBuffer() végül kiírja az elküldésre váró szöveget az USB küldő-adattömbjébe, hogy innentől egy parancs segítségével kiküldje az eszköz a szöveget. Így tud visszajelzést küldeni a PC-re.
5.4.1.2 USB konfiguráló fájlok Az usb_device.c tartalmazza az USBDeviceInit() függvényt, ami inicializálja az eszközt általános HID eszköznek, ezen kívül tartalmaz még egyéb beállításokat az USB hardverrel kapcsolatban. Az usb_function_hid.c tartalmaz minden függvényt, deklarációt, definíciót, ami a HID diverrel kapcsolatos. Az usb_discriptors.c az USB eszközről tartalmaz információkat, azonosítókat. Az usb_config.h tartalmazza az egyes USB funkciók ki-be kapcsolását, például hogy az USBDeviceTasks(); függvény rendszeres meghívását megszakítással, vagy pollingal akarjuk megvalósítani.
33
5.4.1.3 Hardverleírások A HardwareProfile.h tartalmaz minden hardverrel kapcsolatos beállítást: -
a kompatibilis Bootloader beállítása, HID-el vagy MCHPUSB-vel, a HID et állítottam be
-
beállíthatjuk az órajel frekvenciáját, itt 48MHz re állítottuk
-
VID azonosító beállítása: 0x04D8, a Vendor ID a fejlesztő cég azonosítója.
-
PID azonosító beállítása: 0x0042, a Product ID a termék azonosítója
-
a gyártó neve: Brogli Péter
-
a termék neve: Ledkocka
-
a termék sorozatszáma: LC8_3.0
-
Kikapcsolhatjuk
a
debug
funkciót
a
#define
DEBUGON
sor
ki
kommentelésével, ha úgy hagyjuk, akkor bekapcsolva marad -
az eredeti programban használt lednek és gombnak a helyét is itt adhatjuk meg és az azokat vezérlő függvények is itt vannak megadva
5.4.1.4 Animációt generáló függvények A programs.h header fájl tartalmazza az animációkat generáló függvényeket, a program_functions.h pedig a segédfüggvényeket. Jelenleg 4 db animáció van megírva. Példaként bemutatok egyet, de a többit nem, mert nagyon hosszú lenne. Az első program, eső-animációt valósít meg, legfelső szinten véletlenszerűen felvillan 4 db LED, amik a következő képkockánál egy szinttel lejjebb esnek és a legfelső szintre újabb 4 db LED generálódik és így tovább. Függvények magyarázata: -
az es() függvény az aktuális képkockát lejjebb tolja egy szinttel.
-
a write_led_sz(int i, int j, int k) függvény az i. szint j. sorának a k. LED-jét állítja be
-
a write_cube pedig kiírja a képet a kockára
Egy számláló határolja be a program futását, amint eléri az 500-at, kilép. és van még egy megszakítást megvalósító változó az intflag, ennek a beállítása estén szintén kilép a program. Ezt a processUsbCommands() függvénynél fogjuk használni
34
31. ábra 18F4550 első animációjának függvénye
5.4.1.5 Main fájl A main.c a fő fájl itt kezdődik a program futása. Ugyan úgy mint az előző mikrokontrollernél itt is a szükséges header fájlok behívásával kezdünk.
32. ábra 18F4550 main.c fájljának behívott header fájljai
A string.h a debug funkció miatt szükséges. A delays.h tartalmazza a késleltető függvényeket. A többi pedig az USB hardver beüzemeléséért felelős. A következő sorokban deklaráljuk a két adattömböt, amibe az adatok fognak érkezni, és amiből az adatokat fogjuk küldeni. A RecieveDataBuffer a fogadó tömb a ToSendDataBuffer pedig a küldő tömb. Ez után az USBOutHandle és az USBInHandle deklarálása történik, ezek kezelik a kimenő és bejövő adatforgalmat. 35
33. ábra 18F4550 adatküldő és fogadó tömbjeinek a deklarálása Következik a konfigurációs bitek beállítása. Azok a bitek, amik az előző mikrokontrollernél megtalálhatóak voltak itt is megvannak, csak némelyik több beállítási lehetőséget kapott, ezen kívül vannak újak is. Az órajel beállításánál most kicsit bonyolultabb dolgunk van, mert 48MHz re van szükségünk az USB miatt, de csak 20MHz es kristály van csatlakoztatva. PLL segítségével a 20Mhzből 48MHzet tudunk csinálni. A PLL (Phase Lock Loop) egy frekvenciaszorzó áramkör. A bitek beállítása a következő:
34. ábra 18F4550 órajel konfigurációs bitjei
Majd jönnek a már ismert bitek, a WDT, PWRT, LVP, CPD és CP amik itt is ki van kapcsolva, az MCLRE és a BOR pedig be vannak kapcsolva és a BOR feszültség értéke 3V-ra van állítva. Ezeken kívül van még pár bit nagyrészt védelmi szerepet betöltők, de ezek mind ki vannak kapcsolva. A programban egyéb USB-vel kapcsolatos beállítások következnek. Majd innentől kezdődnek az általam írt függvények. Saját késleltető függvényeket írtam, amik a 48MHz es órajelnek megfelelően működnek. Létezik egy függvény az USBDeviceTasks() amit a PC-vel való kapcsolat fenntartásához minden 1,8dik milliszekundumban, vagy gyorsabban, meg kell hívni. Ezt a függvényt a delay_ms() függvényembe tettem, hogy minden milliszekundumban meghívódjon és késleltetésre 36
mindenhol csak ezt a késleltető függvényt használom. Szerencsére ennek a futási ideje nem hosszú, 100 utasítás ciklus alatt van, így nem akadályozza a program futását.
35. ábra 18F4550 késleltető függvénye A következő lépésben deklarálom a képgeneráláskor használt változókat. A képet itt is, ahogy a másik PIC-nél is, 8 bites tömbben tárolom, annyi különbséggel, hogy itt kétdimenziós tömböket használok az egyes szintek és sorok indexelhetősége miatt. Sőt írtam olyan függvényt is, amivel a sorokban lévő LED-ek értékeit tudom külön írni, vagy olvasni, ugyanis olyan rendszert használok, hogy az egyes LED-ekre úgy tudok hivatkozni, hogy három koordinátát adok meg, a szintet, a sort és hogy a sorban hányadik. Ennek segítségével egyszerűbben tudtam felírni az animációt generáló függvényeket. Az UART_init() függvényben beállítom az UART modult 250kHz es baud rate-re hogy az adatátvitelt az emberi szem nem legyen képes folyamatában látni, hanem villanásszerűen érzékeljük.
36. ábra 18F4550 UART_init() függvénye
37
Az SPBRG értékét a PIC adatlapjában található képlet segítségével számoltam ki. A képlet aszinkron kommunikációnál és beállított BRGH bittel (tehát magas baud rate módban) és 8 bites felbontással: Br = FOSC/(16*(X+1)) Ahol X az SPBRG regiszter értéke, FOSC a kristály frekvenciája és Br a Baud rate. Rendezés után azt kapjuk, hogy: X = (FOSC/(Br*16)) – 1 és ha behelyettesítjük a 48MHz es jelet és 250000 es Br-t akkor 11 et kapunk X-re. A wirte_cube() függvény ugyan azt a feladatot látja el, mint az előző PIC-nél csak más megvalósítással. Meghívásakor egy új kép kerül ki a kockára, animációtól függően kb 200 milliszekundumonként hívom meg. UART-on küldöm át a 65 db bájtot. Az első 64 db a LED-ek állapotát tartalmazzák, a 65. bájtban a kocka fényerejét állítjuk be. Kilencbites kommunikációt használok, hogy a kilencedik bittel jelezzem a fogadó félnek, hogy melyik az első bájt. Az UART-on való adatküldéshez csak annyi a teendő hogy a TXREG regiszterbe másolom a küldendő bájtot, viszont ha kilencbites kommunikációt használok, előbb be kell állítanunk a kilencedik bitet a TX9D bit írásával. Miután egy bájtot a küldő regiszterbe másoltam, 100uset késleltetek, hogy az adatátvitelnek legyen ideje befejeződni.
37. ábra 18F4550 write_cube() függvényének 1. részlete
Az első nyolc bájt küldését kiírtam a fent látható módon mivel itt az elsőnek más a kilencedik bitje, viszont a többi bájtot a 9.-től a 64.-ig két egymásba ágyazott for ciklussal oldottam meg, indexelve. Majd a végén hozzátettem még 65. bájtnak a fényerő értékét.
38
38. ábra 18F4550 write_cube() függvényének 2. részlete
Minden egyes 8. bájt elküldése után meghívtam az USBDeviceTask() függvényt, hogy biztosan ne teljen el 1,8ms a meghívása nélkül, és az adatok küldése után meghívtam a processUsbCommands() függvényt, ami a PC felől érkező parancsokat hajtja végre. Azért tettem ide, mert így 200ms-onként fut le, ami elegendő gyakoriság, és így nem terheli túlságosan a programot. Ezek után behívom az általam írt programs.h header fájlt, ami tartalmazza az animációkat generáló függvényeket és segédfüggvényeket. Következik a main() függvény: -
az initialisePic() függvénnyel nulla kezdőértéket állítunk be a TRIS és a PORT regisztereknek, valamint az összes lábat digitálisra állítjuk be az ADCON1 regiszter megfelelő írásával. Továbbá itt hívódik meg az applicationInit() függvény, ami az eredeti programban a LED-et és a kapcsolókat inicializálta és az USBDeviceInit() függvény, ami az USB hardver inicializálását végzi.
-
a debugInitialise() függvény a debug funkciókat állítja be.
-
az UART_init() függvénnyel az UART kommunikációt állítjuk be
-
majd egy végtelen ciklusban található egy switch-case struktúra, ami az aktuális programszámnak megfelelő programot indítja el
Az egyik legfontosabb függvény pedig a processUsbCommands(), mert itt hajtódnak végre a PC által küldött parancsok. A 64 bájtnyi adat a RecievedDataBuffer-be érkezik. Az első bájt a parancs kódját tartalmazza, ezt vizsgálja egy switch-case struktúra. Az eredeti program parancsait meghagytam, új kódokat vezettem be a saját parancsaimnak. 39
Eredeti parancsok: -
0x10 elküldi a küldésre várakozó debug információkat
-
0x80 váltja a LED állapotát
-
0x81 kiolvassa és elküldi a kapcsoló állapotát
-
0x82 kiolvassa és elküldi a LED állapotát
Saját parancsok -
0x83 a fényerőt lehet vele beállítani
-
0x84 az általunk kiválasztott animációt lehet vele elindítani
A fényerő beállításnál mindössze annyi történik, hogy fényerő értékét tartalmazó változóba, a ccp_inv_duty-ba beírjuk a beérkező bájtok közül a másodikat. Végül visszajelzést küldünk a PC-re a debug függvényeken keresztül.
39. ábra 18F4550 fényerő beállító parancskódja
Az animáció kiválasztó parancsnál először beleírjuk a beérkező bájtok közül a másodikat a program kiválasztó változóba. Majd az intflag-et beállítjuk ami hatására az aktuálisan futó program megszakítja futását és az általunk beállított program indul el. Végül itt is visszajelzést küldünk a PC-re a debug függvényeken keresztül.
40. ábra 18F4550 program beállító parancskódja
40
5.5 PC-n futó szoftver [7] A PC programja Visual Stúdióban C Sharp nyelven íródott. A megoldás tartalmazza az USB Generic HID kommunikációhoz szükséges könyvtárat, és magagát a LED-kocka vezérlő projektet. Három fájlt fogok bemutatni, amik tartalmazzák a projekt megvalósítását: -
Program.cs
-
Form1.cs
-
usbDemoDevice.cs
5.5.1 Program.cs A Program.cs csak annyit tesz, hogy meghívja a Form1 ablakot 5.5.2 Form1.cs A Form1.cs a LED-kockát vezérlő ablak működését határozza meg. Az ablakban elhelyeztem négy darab gombot „Program 1”-től „Program 4”-ig amiknek a megnyomásakor az adott animáció indul el a kockán. Középen egy „Debug output:” nevű szövegdoboz található ahová az eszköz felöl érkező információkat jelenítem meg. Felül pedig egy fényerő szabályzó csúszka található, amit 10 részre osztottam. A legalján az ablaknak egy információs sáv található, ami azt jelzi ki, hogy csatlakoztatva van-e az eszköz.
41. ábra A futó program kezelőfelülete 41
A program legelőször inicializálja az ablak komponenseit, majd létrehozza az usbDemoDevice objektumot az eszköznek megfelelő VID és PID értékekkel és hozzáad egy figyelőt az USB eseményekhez. Végül a findTargetDevice() függvénnyel keresi meg az eszközünket.
42. ábra A C Sharp program részlete
A figyelő folyamatosan figyeli, hogy csatlakoztatva van-e már az eszköz. Ha csatlakoztatva van, akkor azt írja ki az alsó sávba, hogy "USB Device is attached" ha pedig nincs akkor "USB Device is detached". Az ablak tartalmaz egy 250ms-ra állított időzítőt, ami a debug információk lekérését rendszeresíti a 0x10 es paranccsal, amit itt a collectDebug() függvény hajt végre. A fényerő beállító csúszka változására meghívódik a setLedLight() függvény, aminek a csúszka értékét adjuk meg megszorozva 20-al, így érhetjük el a 0-tól 200-ig terjedő skálát, ami szükséges a fényerő szabályzásához.
43. ábra C Sharp program csúszkájának kódja
A nyomógombok függvényei is hasonlóak a csúszkáéhoz, azonban itt a setProgram() függvényt hívjuk meg az adott gombnak megfelelő értékkel.
42
44. ábra C Sharp program nyomógombjainak kódja
5.5.3 usbDemoDevice.cs Az usbDemoDevice.cs fájl tartalmazza a setLedLight(), setProgram() és collectDebug() függvényeket. A setLedLight() függvényben elsőnek létrehozunk egy outputBuffer nevű 65 elemből álló byte típusú tömböt, aminek az első bájtját nullára kell állítani. A második bájtba kerül a parancs kód, ami ebben az esetben 0x83, a harmadik bájtba pedig a fényerő értékét írjuk. Végül a writeRawReportToDevice függvénnyel elküldjük a parancsot az eszköznek. A setProgram() függvény szinte teljesen megegyezik az előzővel az egyik eltérés a parancs kódja, ami itt 0x84, a másik pedig hogy itt a harmadik bájtba az elindítani kívánt animáció sorszáma kerül. A collectDebug() függvényben egy 65bájtos outputBuffert és egy inputBuffert is létrehozunk. Majd elküldjük az előzőekhez hasonlóan az outputbufferbe írt adatokat, jelen esetben a
0x10 parancskódot. Aztán a readSingleReportFromDevice()
függvénnyel kiolvassuk az inputBufferbe az eszközön várakozó degug információkat.
5.6 USB vezérlés, USB-UART átalakítóval
45. ábra USB-UART átalakító [8] 43
Mivel a hardver úgy van kialakítva, hogy a kockára UART kommunikációval lehet képet küldeni, a második programgeneráló mikrokontrollert a 18F4550-est ki is hagyhatjuk és közvetlenül USB-UART átalakító kártyán keresztül tudjuk vezérelni a kockát. Ez egy olyan kisméretű kártya, ami segítségével PC-ről közvetlenül kommunikálhatunk UART-on keresztül egy eszközzel. Ezzel a módszerrel a számítógép válik a programgeneráló vezérlővé, így azon kell megírni az animációk generálásához szükséges függvényeket. A programot szintén Visual Stúdióban írtam C Sharp nyelven. Megírtam azokat az animációkat itt is, amiket a firmwarebe is. Ezek szerkezetüket tekintve egyformák így nem fogom bemutatni, a különbség az, hogy a másfajta programnyelv miatt más szintaktikát kellett alkalmazni. A legfontosabb eleme a programnak a writecube() függvény. A kommunikációt a beépített soros port-i függvényekkel valósítottam meg. Először be kellett állítani, hogy melyik COM portra küldjem az adatokat. Én a kártyát az COM3 porton érem el, ez attól függ, hogy a számítógép melyikre osztotta az eszközünket. Következő lépésben beállítottam a 250000-res Baud rate-et és hogy 8 bitet küldök egyszerre. Majd itt is ugyanúgy, mint a mikrokontroller write_cube() függvényénél először a 64 db bájtot küldöm el majd a fényerő értékét. A kilencedik bitet itt is 1 re állítom az első bájt küldésénél, hogy ezzel egyértelmű legyen, hogy melyik az első bájt. Ezzel a módszerrel bonyolultabb animációkat tudunk a készíteni mivel egy számítógép erőforrásai sokkal nagyobbak egy 8 bites mikrokontrolleréhez képest.
44
46. ábra A működő rendszer
45
6
Összefoglalás
A szakdolgozatom egy LED-kocka tervezéséről szól. Az második fejezetben irodalomkutatást végeztem különböző típusú kijelzők területén. Kitértem a különböző kijelző technológiákra, és leírtam a multiplexálás menetét. A harmadik fejezetben megvizsgáltam minként lehet hatékonyan vezérelni egy kijelzőt. Elemeztem egy tároló regiszteres, egy léptető regiszteres és egy FPGA megvalósítás lehetőségeit A negyedik fejezetben a LED-kocka hardver tervezésének menetén mutattam be az én szempontjaim alapján: -
olyan tervet megvalósítani, amit máshol még nem láttam
-
a lehető legkevesebb pénzből
-
a lehető legegyszerűbb kapcsolást tervezni, hogy minél kisebb legyen az áramkör.
Az ötödik fejezetben a két mikrovezérlő programját és a PC-n futó programot elemeztem lépésről lépésre. Először bemutattam, hogy hogyan lehet USB porton keresztül 18F4550-es mikrovezérlővel konfigurálni egy LED-kockát a beépített USB hardveren keresztül. Majd egy alternatív lehetőséget is elemeztem ahol egy USB-UART átalakítóval létesítek kapcsolatot az eszközzel. A kijelzők kutatása folyamatosan zajlik a piaci versengésnek köszönhetően épp ezért nagyon nagy ütemű a fejlődés. A közeljövőben hajlítható kijelzőket fognak piacra dobni, ami egy új kategóriájú okos telefonok megjelenésével járhat. Ez is mutatja, hogy a technológiai fejlődés előrehaladásával olyan készülékeket fognak létrehozni, amikről nem is álmodnánk. A 3D-s megjelenítők lehetnek az új generációs kijelzők, amik rengeteg új felhasználási lehetőséget fognak nyújtani. Kíváncsian várom, hogy mikor jutunk el arra a szintre, mikor a TV-t már nem síkképernyős monitoron nézzük, hanem háromdimenziós megjelenítőn.
46
7
Summary
In my thesis I describe how to make a 8x8x8 LED-cube. In chapter 2, I researched about the different kind of displays like LCD and LED. I mentioned the different technologies than I described how multiplexing works. In the next chapter I examined how to drive a display efficiently. Chapter four, I described the hardver of the LED-cube by my point of view. In chapter 5 I analyzed the softwares of the microcontrollers and the programs on the PC step by step. First I described how to configurate the 18F4550 microcontroller via USB port, than I showed an alternative solution of the USB configuration with a USBUART converter device. Nowadays, the research of the displays are growing fast because of the economical rush. In the near future, we will find curved displays at markets that create a new type of smart phone generation. This is also shows that we will create devices what we can not imagine, by the growing of the technological development. The new generation of displays could be the 3D displays that will give us a bunch of new possibilities. I am very curious about when we will watch television via 3D instead of 2D displays.
47
8
Irodalom jegyzék
[1] http://mogi.bme.hu/TAMOP/3d_megjelenitesi_technikak/ch05.html [ellenőrizve 2016.11.25] [2] http://uni-nke.hu/downloads/bsz/bszemle2010/4/14.pdf [ellenőrizve 2016.11.25] [3] http://www.instructables.com/id/Led-Cube-8x8x8/?ALLSTEPS [ellenőrizve 2016.11.25] [4] http://www.ebay.com/itm/ALTERA-FPGA-EP4CE6-EP4CE6E22C8N-Cyclone-IVDevelopment-Evaluation-Board-Core-Kit-/251194080650?hash=item3a7c557d8a [ellenőrizve 2016.11.25] [5] http://ww1.microchip.com/downloads/en/DeviceDoc/40044F.pdf [ellenőrizve 2016.11.25] [6] http://ww1.microchip.com/downloads/en/DeviceDoc/39632e.pdf [ellenőrizve 2016.11.25] [7] http://www.waitingforfriday.com/index.php/Building_a_PIC18F_USB_device [ellenőrizve 2016.11.25] [8]
http://www.ebay.com/itm/K9-USB-2-0-to-TTL-UART-Module-Serial-Converter-
CP2102-STC-Replace-Ft232Module/252625237948?_trksid=p2047675.c100005.m1851&_trkparms=aid%3D22200 71%26algo%3DSIC.MBE%26ao%3D2%26asc%3D38530%26meid%3D28e7dd438281 461eaf544acc7c49ccc8%26pid%3D100005%26rk%3D6%26rkt%3D6%26sd%3D4010 92508083 [ellenőrizve 2016.11.25]
48
9
Ábra jegyzék
1. ábra Flip-disc kijelző [1] ............................................................................................... 4 2. ábra - VFD - vákuum fluoreszcens kijelző [1] ............................................................. 5 3. ábra Folyadék kristály [1] ............................................................................................. 5 4. ábra EP - Elektronikus papír kijelző [1] ....................................................................... 6 5. ábra PDP - Plazma kijelző [1]....................................................................................... 7 6. ábra Tárolós vezérlés kapcsolása [3] .......................................................................... 10 7. ábra Altera Cyclone 4 es FPGA [4] ............................................................................ 12 8. ábra Általam készített LED-kocka .............................................................................. 13 9. ábra A LED-kocka alulról, láthatók a panelek ........................................................... 15 10. ábra Round top 5mm LED ........................................................................................ 16 11. ábra Straw Hat 5mm LED ........................................................................................ 16 12. ábra Diffúz 3mm LED .............................................................................................. 16 13. ábra 4db shift regisztert tartalmazó panel ................................................................. 17 14. ábra 4db shift regisztert tartalmazó panel kapcsolási rajza ....................................... 17 15. ábra Táp panel ........................................................................................................... 18 16. ábra Táp panel kapcsolási rajza ................................................................................ 19 17. ábra Multiplexálást végző panel kapcsolási rajza ..................................................... 19 18. ábra Multiplexálást végző panel ............................................................................... 20 19. ábra Animációt generáló panel ................................................................................. 21 20. ábra Animációt generáló panel kapcsolási rajza ....................................................... 21 21. ábra 16F628A konfigurációs bitjei ........................................................................... 24 22. ábra 16F628A definiált nevei és órajele ................................................................... 25 23. ábra 16F628A main_init() függvénye....................................................................... 26 24. ábra 16F628A UART_init() függvénye .................................................................... 27 25. ábra 16F628A interrupt_init() függvénye ................................................................. 27 26. ábra 16F628A Timer2_init() függvénye ................................................................... 28 27. ábra 16F628A PWM_init() függvénye ..................................................................... 28 28. ábra 16F628A write_cube() függvény részlete ......................................................... 29 29. ábra 16F628A megszakítás kezelő függvénye .......................................................... 30 30. ábra 18F4550 debug függvényei............................................................................... 33 31. ábra 18F4550 első animációjának függvénye ........................................................... 35 32. ábra 18F4550 main.c fájljának behívott header fájljai ............................................. 35
49
33. ábra 18F4550 adatküldő és fogadó tömbjeinek a deklarálása .................................. 36 34. ábra 18F4550 órajel konfigurációs bitjei .................................................................. 36 35. ábra 18F4550 késleltető függvénye .......................................................................... 37 36. ábra 18F4550 UART_init() függvénye..................................................................... 37 37. ábra 18F4550 write_cube() függvényének 1. részlete .............................................. 38 38. ábra 18F4550 write_cube() függvényének 2. részlete .............................................. 39 39. ábra 18F4550 fényerő beállító parancskódja ............................................................ 40 40. ábra 18F4550 program beállító parancskódja ........................................................... 40 41. ábra A futó program kezelőfelülete .......................................................................... 41 42. ábra A C Sharp program részlete .............................................................................. 42 43. ábra C Sharp program csúszkájának kódja ............................................................... 42 44. ábra C Sharp program nyomógombjainak kódja ...................................................... 43 45. ábra USB-UART átalakító [8] .................................................................................. 43 46. ábra A működő rendszer ........................................................................................... 45
50
10 Mellékletek 10.1 PIC16F628A // PIC16F628A Configuration Bit Settings // 'C' source line config statements #include <xc.h> // CONFIG #pragma config FOSC = HS // Oscillator Selection bits (HS oscillator: High-speed crystal/resonator on RA6/OSC2/CLKOUT and RA7/OSC1/CLKIN) #pragma config WDTE = OFF disabled)
// Watchdog Timer Enable bit
(WDT
#pragma config PWRTE = ON disabled)
// Power-up Timer Enable bit
(PWRT
#pragma config MCLRE = ON // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is MCLR) #pragma config BOREN = ON disabled)
// Brown-out Detect Enable bit
(BOD
#pragma config LVP = OFF // Low-Voltage Programming Enable bit (RB4/PGM pin has digital I/O function, HV on MCLR must be used for programming) #pragma config CPD = OFF memory code protection off) #pragma config CP = OFF protection off)
// Data EE Memory Code Protection bit // Flash Program Memory Code Protection bit
#define _XTAL_FREQ 20000000 #define RCLK1
RB5
#define SRCLK1
RB4
#define SER1 #define RCLK2 #define SRCLK2 #define SER2 #define OE
RB0 RA1 RA2 RA0 RA3
void pulse_SRCLK1(){ SRCLK1 = 1; 51
(Data (Code
SRCLK1 = 0; } void pulse_RCLK1(){ RCLK1 = 1; RCLK1 = 0; } void pulse_SRCLK2(){ SRCLK2 = 1; SRCLK2 = 0; } void pulse_RCLK2(){ RCLK2 = 1; RCLK2 = 0; } void write_data1(char data){ for(int i=0;i<8;i++) { SER1 = (data & 1); data = data >> 1; pulse_SRCLK1(); } } void write_data2(unsigned char data){ for(int i=0;i<8;i++) { SER2 = (data & 1); data = data >> 1; SRCLK2 = 1; SRCLK2 = 0;
52
} pulse_RCLK2(); } char sz[65]; void write_cube(){ write_data1(sz[0]); write_data1(sz[1]); write_data1(sz[2]); write_data1(sz[3]); write_data1(sz[5]); write_data1(sz[4]); write_data1(sz[6]); write_data1(sz[7]); OE = 1; pulse_RCLK1(); SER2 = 1;pulse_SRCLK2();pulse_RCLK2(); OE = 0; write_data1(sz[8]); write_data1(sz[9]); write_data1(sz[10]);write_data1(sz[11]); write_data1(sz[13]);write_data1(sz[12]);write_data1(sz[14]);write_data1(sz[15]); OE = 1; pulse_RCLK1(); SER2 = 0;pulse_SRCLK2();pulse_RCLK2(); OE = 0; write_data1(sz[16]);write_data1(sz[17]);write_data1(sz[18]);write_data1(sz[19]);write_ data1(sz[21]);write_data1(sz[20]);write_data1(sz[22]);write_data1(sz[23]); OE = 1; pulse_RCLK1(); pulse_SRCLK2();pulse_RCLK2(); OE = 0; write_data1(sz[24]);write_data1(sz[25]);write_data1(sz[26]);write_data1(sz[27]);write_ data1(sz[29]);write_data1(sz[28]);write_data1(sz[30]);write_data1(sz[31]); OE = 1; pulse_RCLK1(); pulse_SRCLK2();pulse_RCLK2(); OE = 0; write_data1(sz[32]);write_data1(sz[33]);write_data1(sz[34]);write_data1(sz[35]);write_ data1(sz[37]);write_data1(sz[36]);write_data1(sz[38]);write_data1(sz[39]); 53
OE = 1; pulse_RCLK1(); pulse_SRCLK2();pulse_RCLK2(); OE = 0; write_data1(sz[40]);write_data1(sz[41]);write_data1(sz[42]);write_data1(sz[43]);write_ data1(sz[45]);write_data1(sz[44]);write_data1(sz[46]);write_data1(sz[47]); OE = 1; pulse_RCLK1(); pulse_SRCLK2();pulse_RCLK2(); OE = 0; write_data1(sz[48]);write_data1(sz[49]);write_data1(sz[50]);write_data1(sz[51]);write_ data1(sz[53]);write_data1(sz[52]);write_data1(sz[54]);write_data1(sz[55]); OE = 1; pulse_RCLK1(); pulse_SRCLK2();pulse_RCLK2(); OE = 0; write_data1(sz[56]);write_data1(sz[57]);write_data1(sz[58]);write_data1(sz[59]);write_ data1(sz[61]);write_data1(sz[60]);write_data1(sz[62]);write_data1(sz[63]); OE = 1; pulse_RCLK1(); pulse_SRCLK2();pulse_RCLK2(); OE = 0; } char ninth = 0; char szamlalo = 0; void interrupt myIsr(void){ if(RCIE && RCIF) { ninth = RX9D; if(ninth){ szamlalo=0; CCPR1L = sz[64];} 54
sz[szamlalo] = RCREG; szamlalo++; } } void clear_sz() { for(char i=0;i<64;i++) { sz[i] = 0; } } void main_init() { CMCON = 0b00000111; TRISB = 0b00000000; TRISA = 0b00000000; PORTB = 0b00000000; PORTA = 0b00000000; } void interrupt_init(){ GIE = 1; PEIE = 1; RCIE = 1; } void UART_init(){ TRISB1 = 1; TRISB2 = 1; SPEN = 1; SYNC = 0;
55
SPBRG = 4; BRGH = 1; CREN = 1; TXEN = 0; RX9 = 1; } void Timer2_init(){ TMR2ON = 1; } void PWM_init(){ CCP1M0 = 0;CCP1M1 = 0;CCP1M2 = 1;CCP1M3 = 1; PR2 = 200; TRISB3 = 0; CCP1X = 0; CCP1Y = 0; CCPR1H = 0; CCPR1L = 0; }
int main(void){ main_init(); interrupt_init(); UART_init(); Timer2_init(); PWM_init(); SER1 = 0; SRCLK1 = 0; RCLK1 = 0; SER2 = 0; SRCLK2 = 0;
56
RCLK2 = 0; clear_sz(); sz[0]=0b11111111; sz[8]=0b10000001; sz[16]=0b10000001; sz[24]=0b10000001; sz[32]=0b10000001; sz[40]=0b10000001; sz[48]=0b10000001; sz[56]=0b11111111; sz[1]=0b10000001; sz[9]=0b00000000; sz[17]=0b00000000; sz[25]=0b00000000; sz[33]=0b00000000; sz[41]=0b00000000; sz[49]=0b00000000; sz[57]=0b10000001; sz[2]=0b10000001; sz[10]=0b00000000; sz[18]=0b00000000; sz[26]=0b00000000; sz[34]=0b00000000; sz[42]=0b00000000; sz[50]=0b00000000; sz[58]=0b10000001; sz[3]=0b10000001; sz[11]=0b00000000; sz[19]=0b00000000; sz[27]=0b00000000; sz[35]=0b00000000; sz[43]=0b00000000; sz[51]=0b00000000; sz[59]=0b10000001; sz[4]=0b10000001; sz[12]=0b00000000; sz[20]=0b00000000; sz[28]=0b00000000; sz[36]=0b00000000; sz[44]=0b00000000; sz[52]=0b00000000; sz[60]=0b10000001; sz[5]=0b10000001; sz[13]=0b00000000; sz[21]=0b00000000; sz[29]=0b00000000; sz[37]=0b00000000; sz[45]=0b00000000; sz[53]=0b00000000; sz[61]=0b10000001; sz[6]=0b10000001; sz[14]=0b00000000; sz[22]=0b00000000; sz[30]=0b00000000; sz[38]=0b00000000; sz[46]=0b00000000; sz[54]=0b00000000; sz[62]=0b10000001; sz[7]=0b11111111; sz[15]=0b10000001; sz[23]=0b10000001; sz[31]=0b10000001; sz[39]=0b10000001; sz[47]=0b10000001; sz[55]=0b10000001; sz[63]=0b11111111; for(;;) { write_cube(); } }
57
10.2 PIC18F4550 Általam írt programrészek: #define ledszam 4 #define ledszam2 5 void delay_ms(int ms) { int i; for(i=0;i<ms;i++) { Delay1KTCYx(12); //1ms USBDeviceTasks(); processUsbCommands(); } } void delay_us(int us) { int i; us = us/10; for(i=0;i<us;i++) { Delay10TCYx(12); //10us } } #pragma udata my_section_1 unsigned char sz[8][8]; #pragma udata my_section_2 unsigned char vsz0[8][8]; #pragma udata my_section_3 58
unsigned char vsz[8][8]; unsigned char ccp_inv_duty = 0; unsigned char program = 1; unsigned char intflag = 0; void write_cube(void) { char i; char j; TXSTAbits.TX9D = 1;TXREG = sz[0][0];delay_us(100); TXSTAbits.TX9D = 0;TXREG = sz[0][1];delay_us(100); TXSTAbits.TX9D = 0;TXREG = sz[0][2];delay_us(100); TXSTAbits.TX9D = 0;TXREG = sz[0][3];delay_us(100); TXSTAbits.TX9D = 0;TXREG = sz[0][4];delay_us(100); TXSTAbits.TX9D = 0;TXREG = sz[0][5];delay_us(100); TXSTAbits.TX9D = 0;TXREG = sz[0][6];delay_us(100); TXSTAbits.TX9D = 0;TXREG = sz[0][7];delay_us(100);
USBDeviceTasks();
for(i=1;i<8;i++) { for(j=0;j<8;j++) { TXSTAbits.TX9D = 0;TXREG = sz[i][j];delay_us(100); } USBDeviceTasks(); } TXSTAbits.TX9D = 0;TXREG = ccp_inv_duty;delay_us(100); processUsbCommands();
59
} void UART_init(void) { SPBRG = 11; SPBRGH = 0;
TXSTAbits.SYNC = 0;
BAUDCONbits.BRG16 = 0; TXSTAbits.BRGH = 1; RCSTAbits.SPEN = 1;
RCSTAbits.CREN = 0;
TXSTAbits.TXEN = 1;
TXSTAbits.TX9 = 1;
TRISCbits.TRISC6 = 1; TRISCbits.TRISC7 = 1; } #include "programs.h" // Main program entry point void main(void) { initialisePic(); debugInitialise();
sprintf(debugString, "Ledkocka program"); debugOut(debugString);
sprintf(debugString, "Brogli Peter"); debugOut(debugString);
sprintf(debugString, "USB Device Initialised."); debugOut(debugString);
UART_init();
ccp_inv_duty = 0;
60
// Main processing loop while(1) { #if defined(USB_POLLING) // If we are in polling mode the USB device tasks must be processed here // (otherwise the interrupt is performing this task) USBDeviceTasks(); #endif switch(program) { case 0: break; case 1: program1(); break; case 2: program2(); break; case 3: program3(); break; case 4: program4(); break; default: break; } // Process USB Commands 61
//USBDeviceTasks(); //processUsbCommands();
// Note: Other application specific actions can be placed here } }
Hely szűkében csak az első animációt helyeztem ide.
#ifndef PROGRAMS_H #define PROGRAMS_H
#include "program_functions.h"
#define ledszam 4 #define ledszam2 5
void program1(void) { int szamlalo=0; char i; intflag = 0;
for(;;) { es(); for(i=0;i
62
} szamlalo++; if(szamlalo>=500)break; if(intflag)break; write_cube(); delay_ms(100); } }
#endif #ifndef PROGRAM_FUNCTIONS_H #define PROGRAM_FUNCTIONS_H
void write_led_sz(char i,char j,char k,char data) { if(data == 1) sz[i][j] = sz[i][j] | (1 << k); else sz[i][j] = sz[i][j] & ((0b11111110 << k) | (0b11111110 >> (8-k))); }
char read_led_sz(char i,char j,char k) { char sz1; sz1 = sz[i][j]; sz1 = (sz1 & (1 << k)); if(sz1)return 1; else return 0; }
void reset_sz(void)
63
{ char i=0; char j=0; for(i=0;i<8;i++) { for(j=0;j<8;j++) { sz[i][j] = 0; } } } void es(void) { char i; char j; for(i=0;i<8;i++) { for(j=0;j<8;j++) { if(i==7)sz[i][j] = 0; else sz[i][j] = sz[i+1][j]; } } }
64
10.3 LED-kocka vezérlő using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace WFF_Generic_HID_Demo_3 { public partial class Form1 : Form { public Form1() { InitializeComponent(); // Create the USB reference device object (passing VID and PID) theUsbDemoDevice = new usbDemoDevice(0x04D8, 0x0042); // Add a listener for usb events theUsbDemoDevice.usbEvent += new usbDemoDevice.usbEventsHandler(usbEvent_receiver); // Perform an initial search for the target device theUsbDemoDevice.findTargetDevice(); } // Create an instance of the USB reference device private usbDemoDevice theUsbDemoDevice; // Listener for USB events private void usbEvent_receiver(object o, EventArgs e) { // Check the status of the USB device and update the form accordingly if (theUsbDemoDevice.isDeviceAttached) { // Device is currently attached // Update the status label this.toolStripStatusLabel1.Text = "USB Device is attached"; if (theUsbDemoDevice.isDeviceAttached) { theUsbDemoDevice.setLedLight(0); } } 65
else { // Device is currently unattached // Update the status label this.toolStripStatusLabel1.Text = "USB Device is detached"; } } // Collect debug timer has ticked private void debugCollectionTimer_Tick(object sender, EventArgs e) { String debugString; // Only collect debug if the device is attached if (theUsbDemoDevice.isDeviceAttached) { // Collect the debug information from the device debugString = theUsbDemoDevice.collectDebug(); // Display the debug information if (debugString != String.Empty) { this.debugTextBox.AppendText(debugString); } } else { // Clear the debug window this.debugTextBox.Clear(); } } private void trackBar1_Scroll(object sender, EventArgs e) { if (theUsbDemoDevice.isDeviceAttached) { theUsbDemoDevice.setLedLight((byte)(trackBar1.Value * 20)); } } private void programButton1_Click(object sender, EventArgs e) { if (theUsbDemoDevice.isDeviceAttached) { theUsbDemoDevice.setProgram(1); } }
66
private void programButton2_Click(object sender, EventArgs e) { if (theUsbDemoDevice.isDeviceAttached) { theUsbDemoDevice.setProgram(2); } } private void programButton3_Click(object sender, EventArgs e) { if (theUsbDemoDevice.isDeviceAttached) { theUsbDemoDevice.setProgram(3); } } private void programButton4_Click(object sender, EventArgs e) { if (theUsbDemoDevice.isDeviceAttached) { theUsbDemoDevice.setProgram(4); } } } }
public bool setLedLight(byte value) { // Command 0x83 - Toggle LED state // Declare our output buffer Byte[] outputBuffer = new Byte[65]; // Byte 0 must be set to 0 outputBuffer[0] = 0; // Byte 1 must be set to our command outputBuffer[1] = 0x83; outputBuffer[2] = value; // Perform the write command bool success; success = writeRawReportToDevice(outputBuffer); // We can't tell if the device receieved the data ok, we are // only indicating that the write was error free. return success; } 67
public bool setProgram(byte value) { // Command 0x84 - Toggle LED state // Declare our output buffer Byte[] outputBuffer = new Byte[65]; // Byte 0 must be set to 0 outputBuffer[0] = 0; // Byte 1 must be set to our command outputBuffer[1] = 0x84; outputBuffer[2] = value; // Perform the write command bool success; success = writeRawReportToDevice(outputBuffer); // We can't tell if the device receieved the data ok, we are // only indicating that the write was error free. return success; }
68
10.4 LED-kocka USB-UART átalakítóval using System; using System.IO.Ports; using System.Threading;
namespace ConsoleApplication2 { class writePort { static SerialPort _serialPort; public static void writecube(byte[,] byteBuffer) { _serialPort = new SerialPort(); _serialPort.PortName = "COM3"; _serialPort.BaudRate = 250000; _serialPort.DataBits = 8; _serialPort.Parity = (Parity)Enum.Parse(typeof(Parity), "Mark", true);
_serialPort.ReadTimeout = 5000; _serialPort.WriteTimeout = 5000; _serialPort.Open(); byte[] numbers ={ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; byte szam = 0; for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) { numbers[szam] = byteBuffer[i, j]; szam++; } } _serialPort.Parity = (Parity)Enum.Parse(typeof(Parity), "Mark", true); 69
_serialPort.Write(numbers, 0, 1); _serialPort.Parity = (Parity)Enum.Parse(typeof(Parity), "Space", true); _serialPort.Write(numbers, 1, 1); _serialPort.Write(numbers, 2, 1); _serialPort.Write(numbers, 3, 1); _serialPort.Write(numbers, 4, 1); _serialPort.Write(numbers, 5, 1); _serialPort.Write(numbers, 6, 1); _serialPort.Write(numbers, 7, 1); for (int i = 8; i < 64; i++) { _serialPort.Write(numbers, i, 1); } _serialPort.Close(); } } class Sz { public static byte[,] sz = new byte[,] { {0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0} }; public static byte get(int i, int j, int k) { byte sz1; sz1 = sz[i, j]; sz1 = (byte)(sz1 & (1 << k)); if (sz1>0) return 1; else return 0; } public static void set(int i, int j, int k, bool data) { byte sz1; if ((i > 7) || (i < 0)) { Console.Write("i: "); Console.WriteLine(i); Console.ReadKey(); } if ((j > 7) || (j < 0)) { Console.Write("j: "); Console.WriteLine(j); Console.ReadKey(); } if ((k > 7) || (k < 0)) { Console.Write("k: "); Console.WriteLine(); Console.ReadKey(); } 70
sz1 = sz[i, j]; if (data) sz[i,j] = (byte)(sz1 | (1 << k)); else sz[i,j] = (byte)(sz[i,j] & (((byte)254 << k) | ((byte)254 >> (8 - k)))); } public static byte get(int i, int j) { return sz[i, j]; } public static void set(int i, int j ,byte data) { sz[i, j] = data; } public static void reset() { for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) { Sz.set(i,j,0); } } } } class Programok { public static int specadd(int szam1,int szam2,int szam3) { return ((szam1 * 100) + (szam2 * 10) + (szam3)); } public static void es() { for (byte i = 0; i < 8; i++) { for (byte j = 0; j < 8; j++) { if (i == 7) Sz.set(i,j,0); else Sz.set(i,j, Sz.get(i+1,j)); } } } public static void program0() { } 71
public static void program1(int ledszam) { Sz.reset(); Random rnd = new Random(); int szam1 = rnd.Next(0, 8); int szam2 = rnd.Next(0, 8); int szamlalo = 0; for (int programIdo = 0; programIdo < 500; programIdo++) { es(); if ((szamlalo & 1)==1) { for (byte i = 0; i < ledszam; i++) { szam1 = rnd.Next(0, 8); szam2 = rnd.Next(0, 8); Sz.set(7,szam1,szam2,true); } } szamlalo++; writePort.writecube(Sz.sz); Thread.Sleep(50); } } public static void program2() { int ledszam = 5; Random rnd = new Random(); byte[,] led = new byte[,] { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } }; int szam1 = 0; int szam2 = 0; bool a = false; for (int i = 0; i < ledszam; i++) { for (int j = 0; j < 3; j++) { led[i,j] = 0; } }
72
for (int programIdo = 0; programIdo < 5000; programIdo++) { Sz.reset(); for (int i = (ledszam - 1); i > 0; i--) { for (int j = 0; j < 3; j++) { led[i,j] = led[i - 1,j]; } } for (;;) { for (int i = 0; i < 3; i++) { led[0,i] = led[1,i]; } szam1 = rnd.Next(0, 2); szam2 = rnd.Next(0, 3); if (szam1==1) if ((led[0, szam2]) == 0) led[0, szam2]++; else led[0, szam2]--; else if ((led[0, szam2]) == 7) led[0, szam2]--; else led[0, szam2]++; for (int i = 0; i < (ledszam - 1); i++) { if (specadd(led[0,0], led[0,1], led[0,2]) == specadd(led[i + 1,0], led[i + 1,1], led[i + 1,2])) { a = false; break; } else a = true; } if (a) break; } for (int i = 0; i < ledszam; i++) { Sz.set(led[i,0], led[i,1], led[i,2], true); } writePort.writecube(Sz.sz); Thread.Sleep(50); } } public static void program3() { 73
Random rnd = new Random(); int szam = rnd.Next(0, 256); for (int programIdo = 0; programIdo < 1000; programIdo++) { for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) { Sz.set(i, j, (byte)szam); szam = rnd.Next(0, 256); } } writePort.writecube(Sz.sz); Thread.Sleep(200); } }
} class Program { static void Main(string[] args) { Random rnd = new Random(); int program_ = 1; for (;;) { switch (program_) { case 0: Programok.program0(); int szam; for (int i = 0; i < 100; i++) { szam = rnd.Next(0, 3); Console.WriteLine(szam); Console.ReadKey(); } break; case 1: Programok.program1(4); program_ = 2; break; case 2: Programok.program2(); program_ = 3; break; case 3: Programok.program3(); 74
program_ = 1; break; default: break; } } } } }
75