Fórum témák

» Több friss téma
Cikkek » Elektromos dobókocka PIC 12F629-cel (Video pályázat)
Elektromos dobókocka PIC 12F629-cel (Video pályázat)
Szerző: hadnagyakos, idő: Nov 30, 2010, Olvasva: 31022, Oldal olvasási idő: kb. 9 perc
Lapozás: OK   3 / 8

Mivel mikrovezérlőről van szó, ezért kell egy program ami fut benne. Előre megjegyzem, hogy erre a PIC-re lehetett volna sokkal jobb programot is írni, de ez is nagyon jól működik. Nem spóroltam a hellyel, mivel van bőven a PIC-ben belőle.

A program Assembly nyelven íródott. A program 12F508-ra írt verzióját Skory készítette. A program átírása közben belekerült egy újabb funkció, a véletlenszerűen változó dobáshossz, továbbá a véletlenszámot nem a Timer modul segítségével generálja a program. A PIC programozást mindenképpen érdemes ezen a nyelven elkezdeni, mivel így lehet megérteni a legjobban a PIC-ek felépítését.

A program a következőket tudja:

- A dobott értéket a dobókocka pöttyeinek megfelelően rajzolja ki

- Körülbelül másfél perc tétlenség után automatikusan kikapcsol

- Két gombnyomással is (dupla kattintás ) kikapcsolható

- A dobókocka pergési (gurulási) ideje véletlenszerű

- A pergés közben változó hangmagasságú hangot hallat

- Áram alá helyezéskor felvillantja az összes LED-et és 6-ot csippan a hangszóró

A program bemutatása előtt nem árt néhány alapfogalmat tisztázni:

Bit: egyetlen logikai értéket takar. Értéke csak 0 vagy 1 lehet.
Byte
: ez egy szám típus. Egy bájt 256 értéket hete fel. Összesen 8 bitből áll. Értéke 0-255-ig terjedhet. 256=(28)
Regiszter: egy bájtot tárolni képes része a memóriának

A PIC ún. RISC processzor, tehát a fejlesztésénél arra törekedtek, hogy minél kevesebb parancsot kelljen használni a programozásnál. Ez nagyban megkönnyíti az Assembly nyelv tanulását, viszont a processzor alapból csak egyszerű feladatokat tud elvégezni. Ez azt takarja, hogy a processzornak nincs olyan utasítása, amellyel például osztani lehetne, ezt szoftveresen kell megoldani.

A következőkben kitárgyaljuk a program működését:

A programnak csak a gondolatmenet megértéséhez szükséges részeit mutatom be, a felépítés szempontjából lényegtelen részeket kihagyom.

Konfigurációs rész:

  1. list    P=PIC12F629
  2.     include  "P12F629.INC"
  3.  
  4.     __CONFIG  _CP_OFF & _BODEN_OFF & _MCLRE_ON & _PWRTE_ON  & _INTRC_OSC_NOCLKOUT

Itt adhatjuk meg a fordítónak, többek között, hogy milyen típusú PIC-el szeretnénk dolgozni:

A többi jelölés:

_CP_OFF : Kód védelem kikapcsolva. (ha ezt bekapcsoljuk és beégetjük a PIC-be a programot nem tudjuk majd kiolvasni belőle)

_BODEN_OFF: Brown Out Reset kikapcsolva. (ha be van kapcsolva és a tápfeszültség a megadott mérték alá csökken, akkor reseteli a processzort, alacsony feszültségű táplálásnál nem ajánlott)

_MCLRE_ON: az MCLR láb resetel

_WDT_OFF : Watch Dog Timer kikapcsolva (ez egy beépített időzítő a PIC-be, ha bekapcsoljuk és valami értelmetlen jel miatt lefagy a processzor akkor egy kis idő múlva újraindítja)

_INTRC_OSC_NOCLKOUT : A PIC belső oszcillátorát használjuk. Init=belső

  1. #define egyes b'00010000' ; középső 1-es pont - GP4-es láb
  2. #define kettes b'00000001' ; egyik kettes átló - GP0-ás láb
  3. #define kettesb b'00000100' ; másik kettes átló - GP2-es láb
  4. #define kettesc b'00000010' ; középső kettes vonal - GP1-es láb
  5. #define harmas (egyes  | kettes)
  6. #define harmasb (egyes | kettesb)
  7. #define negyes (kettes | kettesb)
  8. #define otos (egyes | kettes | kettesb)
  9. #define hatos (kettes | kettesb | kettesc)
  10. #define hetes (kettes | kettesb | kettesc | egyes)
  11. #define hangsz b'00100000' ; hangszóró a GP5-re kötve

Itt nevezzük el a program számára a különböző LED csoportokat. Látható, hogy itt vannak megadva az egyes csoportok kombinációi is. Például: ötös, hatos.

  1. ck   equ    20h            
  2. delay1 equ 21h
  3. delay2 equ 22h
  4. delay3 equ 23h
  5. szam_0 equ 24h
  6. kikapcsolo equ 25h
  7. on_count equ 26h
  8. periodusido equ 27h
  9. timer equ 28h
  10. random equ 29h
  11. random2 equ 30h
  12. szam_guritas equ 31h
  13. guritas_random equ 32h

Itt defináljuk a változókat egy-egy memóriaterületre. A szabad memóriaterületek elhelyezkedése megtekinthető a PIC adatlapjában a 2.2.2-es oldalon, vagy ITT. Látható, hogy a szabad memóriaterület 20h-nál kezdődik és 60h-nál ér véget. Mi a programban 20h-tól kezdjük a számozást.

  1. PROG CODE 0
  2.  
  3.     goto    start
  4. start:
  5.     bsf        STATUS, RP0    
  6.     call    3ffh        
  7.     movwf    OSCCAL        
  8.     movlw    b'11001000'
  9.     movwf    TRISIO
  10.     movlw    b'00000000'
  11.     movwf    OPTION_REG
  12.     movlw    b'00001000'    
  13.     movwf    IOC
  14.     bcf        STATUS, RP0    ;
  15.     clrf    GPIO
  16.     movlw    b'00000111'
  17.     movwf    CMCON        
  18.     movlw    b'00001000'    ;
  19.     movwf    INTCON        ;
  20.  
  21.     movlw b'11001000'
  22.     movwf OPTION_REG

Ebben a részben beállítgatjuk, hogy melyik láb legyen ki illetve bemenet illetve még pár dolgot.
Erre most nem térnék ki bővebben.

  1. btfsc STATUS,3 ; 0 a harmadik bit?
  2.      goto poweronreset ; ha bekapcsolás volt , akkor a reset rutinhoz ugrik
  3.  
  4.  
  5.      btfsc kikapcsolo,0 ; 0 a kikapcsoló alsó bit?
  6.      goto kikapcs ; ha bit 1-es, akkor kikapcsol
  7.  
  8.      call delay100ms  ; késleltetés a nyomógomb pergésének kiküszöbölésére
  9.      bsf kikapcsolo,0 ; ha a következő pár sorban jel érkezik a nyomógombtól, akkor kikapcsolás

Ez rész ellenőrzi, hogy az áramkör hogyan indult el. Tehát áram alá lett helyezve vagy resetelve lett az MCLR lábon.

  1. RLF     random,W ;
  2.        RLF     random,W ;
  3.        btfsc   random,4 ;
  4.        xorlw   1        ;
  5.        btfsc   random,5 ;  Véletlen számot generálunk a következő véletlen szám generátor kezdőértékéhez
  6.        xorlw   1        ;
  7.        btfsc   random,3 ;
  8.        xorlw   1        ;
  9.        movwf   random   ;
  10.  
  11.        RLF     random,W ;
  12.        RLF     random,W ;
  13.        btfsc   random,4 ;
  14.        xorlw   1        ;
  15.        btfsc   random,5 ;  Véletlen számot generálunk most már ténylegesen a játék számára
  16.        xorlw   1        ;
  17.        btfsc   random,3 ;
  18.        xorlw   1        ;
  19.        movwf   random   ;
  20.  
  21.    
  22.  
  23.     call  villogtat_1 ; LED-ek villogtatása, csak a játék kredvéért + késleltetés + hang
  24.     clrf  kikapcsolo  ; innentől a gombnyomás nem vált ki kikapcsolást
  25.     call  villogtat_1 ; LED-ek villogtatása, csak a játék kredvéért + késleltetés + hang
  26.  
  27.     movfw  random  ; előkészítés a véletlen szám osztásához
  28.     call osztas ; osztási maradék a szam_0 változóban
  29.     movfw szam_0 ; w-ban (0...11)
  30.     call  szamok ; konvertálás (egyes-hatos)
  31.     movwf GPIO ; a tárolt érték kijelzése, vagyis a LED-ek állapotának beállítása

Számunkra most ez a rész a legfontosabb. Először is véletlen számot generálunk a dobott érték számára. Hogy ne ismétlődjenek a számsorok feltűnően, ezért a véletlen szám generátor kezdőértékének is generálunk egy véletlen számot. Másodszor pedig meghívja a LED-ek villogtatásához szükséges szubrutint, majd ha az első villogás lefutott törli a kikapcsolo regisztert, ezzel megakadályozva, hogy a következő gombnyomásra kikapcsoljon. Tehát, ha a villogás első felében még egyszer megnyomjuk a gombot, a dobókocka kikapcsol. Majd, ha töröltük, még egyszer meghívjuk a villogtató szubrutint.
Ha ez mind lefutott betesszük a munkaregiszterbe a random (véletlen szám) regiszter értékét. A következő sorban pedig meghívjuk az osztás szubrutint. Erre azért van szükség, mert a véletlen szám értéke 0-255-ig terjedhet és elég problémás lenne kijelezni ilyen nagy számokat 7 LED-el. Az osztás rutin 12-vel fog osztani. A végén nem a hányadost fogjuk kiíratni, hanem a maradékot. 12-való osztásnál ez 0-11-ig terjedhet.
Ha leosztottuk a számot, akkor meghívjuk a "szamok" nevű szubrutint, ami az osztott értéket átkonvertálja a LED-ek szerinti formára. Végül a konvertált értéket kiírjuk a kimenetre (vagyis a GPIO portra)

  1. movlw d'6' ; várakozás
  2.     movwf ck ; ennyiszer fut le a ciklus
  3.     call delay20s ; késleltetés
  4.     decfsz ck,1 ; ck csökkentlése 0-ig
  5.     goto $-2 ; visszaugrás 2 sort, ha még nem nulla
  6.  
  7.     goto kikapcs ; elég hosszú idő telt el, kikapcsolás

Itt valósítjuk meg az időzített kikapcsolást, ha lefutott az időzítő ciklus, odaugrik a kikapcs programrészhez és SLEEP üzemmódba kerül a processzor. Ilyenkor a PIC adatlapja szerint 1nA (nano!) a fogyasztása. Ez nagyon kicsi! Ezért nem került a kapcsolásba áramtalanító kapcsoló. 2 darab AAA elemről kis fogyasztású LED-ekkel így is évekig elműködhet.

Most következzen a szubrutinok bemutatása:

  1. villogtat_1:
  2.        RLF     guritas_random,W ;
  3.        RLF     guritas_random,W ;
  4.        btfsc   guritas_random,4 ;
  5.        xorlw   1        ;
  6.        btfsc   guritas_random,5 ;  Véletlen számot generálunk a következő véletlen szám generátor kezdőértékéhez
  7.        xorlw   1        ;
  8.        btfsc   guritas_random,3 ;
  9.        xorlw   1        ;
  10.        movwf   guritas_random   ;
  11.  
  12.        RLF     guritas_random,W ;
  13.        RLF     guritas_random,W ;
  14.        btfsc   guritas_random,4 ;
  15.        xorlw   1        ;
  16.        btfsc   guritas_random,5 ;  Véletlenszámot generálunk a gurítás hosszának megállapítására
  17.        xorlw   1        ;
  18.        btfsc   guritas_random,3 ;
  19.        xorlw   1        ;
  20.        movwf   guritas_random   ;
  21.  
  22.     movfw guritas_random ; guritas_random érték a work-be
  23.     call osztas_guritas ; osztjuk a véletlenszámot
  24.     movlw d'6'
  25.     btfsc szam_guritas, 1 ; a ha a szam_guritas első bitjének értéke 0, akkor marad a 6 a workben
  26.     movfw szam_guritas ; ha nem nulla, akkor a workbe mozgatjuk
  27.     btfsc szam_guritas, 2 ; a ha a szam_guritas második bitjének értéke 0, akkor marad a 6 a workben
  28.     movfw szam_guritas ; ha nem nulla, akkor a workbe mozgatjuk
  29.     btfsc szam_guritas, 3 ; a ha a szam_guritas harmadik bitjének értéke 0, akkor marad a 6 a workben
  30.     ; és így tovább a 8. bit-ig....
  31.  
  32. jmp1:
  33.  
  34.     ; véletlenszám generálás (ez csak a villogás miatt kell)
  35.     call sorsol ; szám: 0...11 a szam_0 változóban
  36.     movfw szam_0 ; a dobott érték kijelzése
  37.      call szamok ; konvertálás a LED-ek portra kötése szerinti fotmára
  38.     movwf GPIO ; LED-ek bekapcsolása
  39.  
  40.     ;call delay100ms ; várakozás - ez volt korábban
  41.     call beep_1 ;most hangot is adunk ki
  42.     decfsz ck,1 ;ismétlés amíg a ciklusváltozó nullára csökken
  43.     goto jmp1 ; vissza a ciklus elejére
  44.  
  45.     retlw 0 ; visszatérés a függvényből

Ez a szubrutin felelős a LED-ek villogtatásáért és a közben hallható zajért ami a hangszóróból jön. Mint látható a kód elején lefuttatjuk ugyan azt a  véletlenszám generátort, amit a program elején. Ezzel a gurítás hosszát állapítjuk meg. Ha lefutott a véletlenszám generálás, meghívjuk az ide tartozó osztás rutint és osztjuk 4-gyel. Így maximum 3-szor fogja lefuttatni az egész ciklust. De van egy kis gond! Mi van, ha nincs maradék az osztásnál? Akkor a szam_guritas regiszter értéke nulla lesz és a program nagyon hosszú ciklusba kezd! Ezt kiküszöbölhetjuk egy nagyon leleményes módszerrel. Mielőtt bármit csinálnánk a munkaregiszterbe helyezzük mondjuk a 6-ot. (movlw d'6'). Ha ez kész elkezdjük a szam_guritas regisztert elkezdjük vizsgálni bitről-bitre. Ha az éppen vizsgálat alatt lévő bit értéke 0, akkor kihagyja a program a következő sort, ami a munkaregiszterben törölné a 6-ot és az osztott véletlenszámot írná a helyébe. De, ha valamelyik bit értéke 1, akkor nem ugorja át a következő sort és a munkaregiszterben a 6-ot felülírja az osztott véletlenszámmal. Ezzel kiküszöbölhető, hogy a szuibrutin számláló ciklusába 0 kerüljön, mivel ha a regiszter minden bitjének az értéke 0, akkor soha nem fogja átírni a munkaregiszter értékét, így marad benne a 6, tehát 6-ot gurul a kocka. Ha viszont a szam_guritas regiszter tartalmaz akár egy darab 1-est is, akkor az kerül bele a munkaregiszterbe, így a véletlenszámnak megfelelő hosszú időt "gurul" a kocka.

  1. beep_1:
  2.  
  3.     ; hang előállítási rutin
  4.      movlw d'200' ; 200 ciklusos lesz
  5.      movwf delay1
  6. bp1:
  7.     movlw d'80' ; ettől függ a periódusidő
  8.     addwf szam_0,w ; és persze a számtól is, hogy többféle hangmagasság legyen
  9.     movwf periodusido ; eltesszük a változóba az aktuális értéket
  10.  
  11.  
  12.     swapf  delay1,w ; kiszámolunk egy másik lehetséges frekvenciát is
  13.     andlw d'15' ; ez nem a számtól, hanem külső ciklustól függ
  14.     iorlw d'80'
  15.     ;btfsc on:count,0
  16.     btfsc timer,6 ; ez dönti el, hogy a két kiszámolt frekvencia közül melyik szóljon éppen
  17.  
  18.  
  19.     decfsz periodusido,1 ; periódusidő várakozó ciklusa
  20.     goto $-1
  21.     movlw hangsz ; a hanszóró bitje a GPIO porton
  22.     xorwf GPIO,1 ; hangszóró bit invertálása
  23.     decfsz delay1,1 ; 0-ig fogunk számolni
  24.     goto bp1 ; vissza a ciklus elejére
  25.  
  26.     bcf GPIO,hangszb ; a végén a hangszóró kikapcsp (biztos, ami biztos alapon )
  27.     retlw 0 ; visszatérés a függvényből

Ez a szubrutin a hang előállításért felelős. A "gurítás" közben ez adja a változó magasságú hangot. A hang magassága attól függ, hogy a PIC-be épített időzítőből milyen értéket olvas ki. A hangadást pedig nagyon egyszerűen csinálj, gyorsan kapcsolgatja ki-be azt a lábat, amire a hangszóró van kötve.

  1. poweronreset:
  2.  
  3.      ; ide ugrik, ha a program resettel kezdett (pl.: elemcsre)
  4.     clrf on_count ;bekapcsolásszámláló nullázás
  5.     movlw hetes ; összes LED bekapcsolás (hetest dobtam! )
  6.     movwf GPIO ; bekapcsoljuk a LED-eket
  7.     movlw d'6' ; várakozás
  8.     movwf ck ; enyiszer fut le a ciklus
  9.     call beep_1
  10.     call delay100ms ; 100ms késleltetés
  11.     decfsz ck,1 ; ck csökkentlése 0-ig
  12.     goto $-3

Ha azzal indul el a program, hogy áramot adunk az áramkörre, nem a gombot nyomjuk meg, akkor felvillantja az összes LED-et és 6-ot csippan a hangszóró.

  1. kikapcs:
  2.  
  3.     call delay100ms ; késleltestés a gombpergés és hasonlók miatt
  4.     call beep_1 ; hanszóró csippantás + még késleltetés
  5.     incf on_count,1 ;bekapcsolás számolás (valójában kikapcsolást számolunk, de mostmár mindegy)
  6.     clrf kikapcsolo ; kikapcsoló nullázása, hiszen mindjárt kikapcsolunk
  7.     clrf GPIO ; kimenetetk nullázása, LED-ek és a hangszóró kikapcsolása
  8.     sleep ; alvó üzemmód, kikapcsolás a következő reset-ig

Ha letelik az automatikus kikapcsolás ideje, vagy kétszer egymás után gyorsan megnyomjuk a nyomógombot, akkor ez a ciklus hívódik meg. Ez semmi mást nem csinál, csak késleltet egy kicsit, csippant egyet a hangszórón, majd nullázza az összes kimenetet (kikapcsol mindent) és SLEEP módba teszi a processzort.

  1. sorsol:
  2.            
  3.  
  4.     ; véletlenszám generálás
  5.     movfw TMR0 ; a beépített TIMER értékét olvassuk véletlenszámnak

A változó magasságú hang generálásához olvassa a belső időzítő értékét.

  1. osztas:
  2.  
  3.     movwf szam_0
  4.     movlw d'12' ;12-vel fogunk osztani
  5.     bcf STATUS,C ; C-biz nullázása, megint csak biztos, ami biztos alapon
  6.     subwf szam_0,w ; levonjuk az osztót
  7.     BTFSC STATUS,C ; addig amíg sz osztandó el nem fogy
  8.     goto osztas ; vissza a ciklus elejére, ha az osztandó még nem 0    
  9.     ; az osztási maradék a szam_0 változóba került    
  10.     retlw 0

Ezzel a szubrutinnal végezzük el a program elején az osztást. Tulajdonképpen a véletlenszámból, addig vonogatja ki az osztót, amíg a végeredmény nulla nem lesz. Az osztési maradék a szam_0 változóban marad, azt fogjuk kiírni.

  1. osztas_guritas:
  2.     movwf szam_guritas
  3.     movlw d'4' ; 4-gyel fogunk osztani
  4.     bcf STATUS,C ; C-biz nullázása, megint csak biztos, ami biztos alapon
  5.     subwf szam_guritas,w ; levonjuk az osztót
  6.     BTFSC STATUS,C ; addig amíg sz osztandó el nem fogy
  7.     goto osztas_guritas ; vissza a ciklus elejére, ha az osztandó még nem 0    
  8.     ; az osztási maradék a szam_guritas változóba került    
  9.     retlw 0

Ez az osztás rutin pedig a girítás hosszának megállapításához van. Ez ugyan azt csinálja, mint az előző, csak 4-gyel oszt és a maradék a szam_guritas regiszterbe kerül.

  1. szamok:
  2.  
  3.     ; itt valósítjuk a meg a szám- LED-ek állapota konverziót
  4.     addwf PCL,f
  5.     retlw egyes
  6.     retlw kettes
  7.     retlw harmas
  8.     retlw negyes
  9.     retlw otos
  10.     retlw hatos
  11.     retlw egyes
  12.     retlw kettesb
  13.     retlw harmasb
  14.     retlw negyes
  15.     retlw otos
  16.     retlw hatos

Itt konvertáljuk az osztott véletlenszámot a LED-ek kimenetre kötésének szerintire.

  1. delay20s:
  2.  
  3.      ; ez az egyik késleltető ciklus, semmi mást nem csinál, csak futnak a ciklusok és közbentelik az idő
  4.     clrf delay3
  5.     goto d2
  6.  
  7. delay100ms:
  8.  
  9.     ; 100ms késleltetés
  10.     movlw 1
  11.     movwf delay3
  12. d2:
  13.     movlw d'70'
  14.     movwf delay2
  15. d1:
  16.  
  17.     clrf delay1
  18.     decfsz delay1,f
  19.     goto $-1
  20.  
  21.     decfsz delay2,f
  22.     goto d1
  23.     decfsz delay3,f
  24.     goto d2
  25.  
  26.     retlw 0

Időzítő ciklusok. Semmi mást nem csinál, csak futnak a ciklusok és telik vele az idő.

  1. end

Vége a programnak!

A programot az MLAB nevű fejlesztőkörnyezettel fordítottam le, ami letölthető a Microchip honlapjáról: ITT

A lefordított .HEX fájlt letöltheted: ITT (jobb klikk: mentés másként) Ezt kell beégetni a PIC-be.


A cikk még nem ért véget, lapozz!
Következő: »»   3 / 8
Értékeléshez bejelentkezés szükséges!
Bejelentkezés

Belépés

Hirdetés
Lapoda.hu     XDT.hu     HEStore.hu
Az oldalon sütiket használunk a helyes működéshez. Bővebb információt az adatvédelmi szabályzatban olvashatsz. Megértettem