Novinka:Vianočná "reťaz"
(Kategorie: Mikroprocesory)
Napsal Kosta
07.12.2009 00:00

Sviatky už sú pomaly tu. Konštrukcia sa dá však použiť aj na iné sviatky alebo slávnostné príležitosti, napríklad narodeniny, alebo oslavy sviatku práce a navyše je reálny predpoklad, že Vianoce sa ešte budú opakovať... Jedná sa vlastne o klasického svetelného hada so 16 LED, riadeného mcu z rodiny '51.

Cieľom bolo pohrať sa s rôznymi efektami typu "behajúce svetielko" a "zúrivé blikanie". Zároveň sa mi nechcelo príliš zaoberať hardwarom, takže samotný "had" je tak trocha odfláknutý. Pozostáva z dvoch obvodov 74LS164, na ktoré je anódami pripojených 16 rôznofarebných 5mm LED (s difúznym puzdrom), ktorých katódy sú pripojené priamo na GND. Ušetril som takto takmer polovicu súčiastok (16 odporov), ako aj robotu s ich zapájaním... Vyzerá to možno nebezpečne, ale v skutočnosti je to pomerne korektné zapojenie - využíva sa zabudovaný odpor kladnej vetvy výstupného členu obvodu typu LS, ktorý má nominálnu hodnotu asi 120 Ohm.

Všimnite si prosím, že je dôležité pre toto zapojenie použiť práve obvod typu 74LS, pretože obvody napríklad typu 74HC alebo 74HCT tento odpor nemajú a aj keď MOS tranzistory v ich výstupných obvodoch v saturácii obmedzia prúd na "nejakú" hodnotu, následky takéhoto zapojenia by mohli byť fatálne pre LED alebo 74HC(T)xx prípadne oboje.

Keďže úbytok napätia na LED je približne 2V (a nejaká tá desatina voltu zostane aj na spínacom tranzistore, ktorý v 74LS obvodoch je tesne pod saturáciou), LEDkou takto tečie prúd okolo 25mA, čo dnešné LED bez problémov prežívajú a aj celkom pekne pri tom svietia. Software zabezpečuje, že nikdy nie sú zopnuté viac ako 4 LED na puzdro, takže celkový prúd napájacím pinom obvodu je okolo 100mA a maximálna výkonová strata na puzdro je okolo 300mW, čo tiež sú pomerne zdravé hodnoty. Samozrejme sa dá použiť aj "korektnejšie" zapojenie so sériovými odpormi a zapojením LED voči kladnému napájaniu pričom by sa použili "výkonovejšie" posuvné registre príp. ich kombinácia s nejakým budičom; vyžaduje si to žiadnu alebo len drobnú úpravu firmwaru (ktorá je opísaná v komentári v zdrojovom texte). Úplne ideálne je použiť obvod typu shift register + latch + prúdový zdroj, ktorý odstráni rozdielny prúd LEDkami v závislosti od ich rozdielneho úbytku napätia podľa farby a odstráni mierne poblikávanie počas vysúvania dát; toto riešenie však rozhodne nie je najlacnejšie. Úprava firmwaru je znova minimálna (doplnenie LATCH pulzu).

Z mechanickej stránky som zapojil LED priamo na kus "plochého" viacžilového kábla v asi 7 cm rozostupe, a 74LS164 som nabastlil metódou letmej montáže (známej aj ako metóda vrabčieho hniezda) rovno na kábel vždy doprostred osmice LEDiek, ktoré spínajú (pri tejto "konštrukcii" zvlášť vynikne výhoda nepoužitia sériových odporov). Použil som dva vodiče pre GND - jeden ako signálna zem pre 74LS164, druhý ako "výkonová" zem, na ktorú sú zapojené katódy LED, aby impulzné rušenie zo spínania LED nerušilo funkciu posuvného registra. Celok nepôsobí príliš esteticky a pre použitie napr. na stromčeku by bolo potrebné štandardný šedivý kábel nejako "zapuzdriť" do vhodnej (zelenej?) bužírky príp. nastriekať farbou, avšak pre zavesenie do okna paneláku na 7. poschodí nebola potrebná žiadna ďalšia povrchová úprava. V konečnom dôsledku bol "had" v okne len niekoľko večerov, keď som sa ním kochal pri pohľade od náprotivného paneláku (na našom sídlisku sú paneláky obzvlášť nahusto takže to nebolo priďaleko a aj svit obyčajných LED ešte bolo celkom dobre vidieť), zvyšok času mi visel pri PC...

Keďže na riadenie stačia dva signály (CLOCK, DATA), použil som "ľubovoľnú" dosku s '51 ktorú som mal poruke. Napokon na riadenie je možné použiť takmer čokoľvek - tento istý "had" fungoval na Vianoce pred tromi rokmi riadený z LPT PC (staršieho laptopu pohodeného na parapete); modernisti zaiste siahnu po nejakom nadupanom AVRku s vhodným RTOS; a dokonca si trúfnem tvrdiť že by sa had dal uriadiť aj z nejakého lepšieho PICka... Mnou použitá "ľubovoľná" doska bola osadená P89V51RD2 (v 12-taktovom režime a s kryštálom 22.1184 MHz), takže bolo možné použiť zabudovaný hardware SPI. Firmware je však napísaný a odladený aj pre "bežné" obvody bez hardwarového SPI, takže sa dá bez problémov použiť napríklad aj "drogériový" AT89C2051.

Firmware je "koncipovaný" tak, aby sa dali pomerne ľahko dopĺňať efekty, ktoré sa pravidelne striedajú. Momentálne je implementovaných 6 efektov: svetielko náhodne vznikajúce na jednom konci a bežiace na druhý koniec (v oboch smeroch, takže som to zarátal za 2 efekty, aby som splnil plán ); striedavo blikajúce párne a nepárne LED; "Knight Rider", t.j. dve svetielka vybehnú z oboch koncov, v strede sa stretnú, odrazia sa a bežia späť na začiatok; modifikovaný "Knight Rider", kde po odrazení sa v strede svetielka dojdú len po stred svojej vetvy, otočia sa, znova sa stretnú v strede a bežia až na koniec; a napokon pingpong, kedy svetielko lieta od kraja po kraj. Efekty "Knight Rider" sú implementované tabuľkou, takže môžu slúžiť ako vzor pre tvorbu komplikovanejších efektov. "Návod" pre pridanie efektu je uvedený v komentári na začiatku zdrojového textu.

Želám príjemnú zábavu a všetko dobré v novom roku!
wek


Doplněn odkaz na YT z komentáře


Na záver pripájam zdrojový text firmware:
;christmas chain
;(C)2005 by wek   <a href="http://www.efton.sk"  rel="external">odkaz</a>
;use freely; please let me know to xmas-at-efton.sk if you use it or modify it
;
;LED chain is driven by 2x74LS164 in a cascade,
;LEDs connected directly (no resistors) anodes to 74LS164 outputs,
;  cathodes to GND
;for "properly" connected LEDs to shift registers (cathodes to outputs,
;  anodes through resistor to VCC), invert data in the shiftout routine (IntT0)
;for latched shift registers, drive latch after shifting out all data
;  by end of IntT0
;CLOCK of 74LS164 connected to P1.7, DATA to P1.5
;XTAL=22.1184MHz, for cca 11MHz xtal reload 80h into th0 in IntT0
;$SET(SPI) to use hardware SPI on P89V51RD2
;
;for adding "effects":
;- insert jump to "effect" routine into AlgosTab
;- at the beginning of "effect" routine check IntTim1, return if nonzero
;- if IntTim1 is zero
;  - set IntTim1 to constant timing one "step" of the "effect"
;  - if effect initialisation is required, do it when AlgoTim=0FFh
;  - perform the "effect" by modifying Data0 and Data1
;  - decrement AlgoTim
;- return




        $SET(SPI)


T2CON   EQU 0c8h
T2MOD   EQU 0c9h
TH2     EQU 0CDh
TL2     EQU 0CCh
TR2     EQU 0CAh  ;SFR bit (in T2CON)
RCAP2L  EQU 0CAh
RCAP2H  EQU 0CBh



LED     EQU   P3.6   ;this LED flashes wildly indicating operation



Data0   EQU    20h
Data1   EQU    21h
IntFlag EQU    22h.0

Rnd     EQU    30h   ;8 bytes
IntTim1 EQU    38h
AlgoNo  EQU    39h
AlgoTim EQU    3Ah   ;2 bytes (?) ;counter for how many times an algo should be executed


Stack   EQU    40h


        USING 0

CSEG
        org 0
        ljmp Start

        org 0Bh
        ljmp IntT0


;------------------- INIT ---------------------
        org 30h
Start:
        mov  sp,#Stack-1
        mov  tmod,#20h        ; Timer1 autoreload 8bit (baud generator), Timer0 in 13bit mode
        mov  th1,#-1 ;#0feh       ; 115200 at 22.1184MHz
        mov  pcon,#80h
        mov  scon,#72h       ; 8 bit UART mode, but with the "no RI if no stop bit" feature activated
        mov  tcon,#30h       ; run timers
        mov  t2con,#0        ;autoreload mode, osc/12
;        mov  ie,#82h         ; only timer0 interrupt enabled

        mov  P1,#0F9h      
        mov  P3,#0DFh      



        mov  r3,#2*5
LampTX1:
        djnz r0,LampTX1
        djnz r1,LampTX1
        cpl  LED
        djnz r3,LampTX1



        mov  AlgoNo,#0
        mov  AlgoTim,#0FFh

        mov  Data0,#12h
        mov  Data1,#45h
;--- init SPI
        $IF(SPI)
        mov  0D5h,#01110001b
        $ENDIF

        setb tr0     ;hmmmm... this was already enabled in tcon...
        setb tr1
        setb et0
        setb ea




Loop:
        call Randomize

       
        jnb  ri,RIW1
        cpl  LED
        mov  Data0,sbuf
        clr  ri
RIW1:



;         call  Run1
        call  CallAlgos

;        call LongDelay

        jmp  Loop

       


Stop:   sjmp Stop


CallAlgos:
       mov   a,AlgoTim
       jnz   CAX1
       dec   AlgoTim
       inc   AlgoNo
       mov   a,AlgoNo
       add   a,#'0'
       jnb   ti,$
       clr   ti
       mov   sbuf,a
CAX1:
       mov   a,AlgoNo
       add   a,AlgoNo
       add   a,AlgoNo
       mov   dptr,#AlgosTab
       jmp   @a+dptr

AlgosTab:
       ljmp  Run1
       ljmp  Run2
       ljmp  Run3
       ljmp  Run4
       ljmp  Run4a
       ljmp  Run5
Restart:  ;the last in AlgosTab
       mov   AlgoNo,0
       ret




;---------- interrupt

IntT0:
;        mov  th0,#128   ;this constant determines the overall speed - uncomment if xtal<22MHz

        push psw
        push acc

        setb IntFlag
        mov  a,IntTim1
        jz   IntTX1
        dec  IntTim1
IntTX1:
        cpl  LED


        $IF(SPI)
        mov  a,Data0
        ;cpl  a         ;if LEDs are connected "properly"
        mov  86h,a
Wait1:
        mov  a,0AAh
        jnb  acc.7,Wait1
        anl  0AAh,#01111111B

        mov  a,Data1
        ;cpl  a         ;if LEDs are connected "properly"
        mov  86h,a
Wait2:
        mov  a,0AAh
        jnb  acc.7,Wait2
        anl  0AAh,#01111111B

        $ELSE
        push b
        push ar2
       
        mov  a,Data0
        ;cpl  a         ;if LEDs are connected "properly"
        mov  b,#8
Loop1:  clr  P1.7
        rrc  a
        mov  P1.5,c
;        call Delay
        setb P1.7
;        call Delay
        djnz b,Loop1

        mov  a,Data1
        ;cpl  a         ;if LEDs are connected "properly"
        mov  b,#8
Loop2:  clr  P1.7
        rrc  a
        mov  P1.5,c
;        call Delay
        setb P1.7
;        call Delay
        djnz b,Loop2

        pop ar2
        pop b

        $ENDIF

        ;place triggering the latch here, if latched shiftregister used

        pop  acc
        pop  psw
        reti
;--------------- utils ---------
Delay:
;        jnb ri,Delay
;        clr ri
;        ret


        mov  r2,#2
Delay1:
        djnz r2,Delay1
        ret


LongDelay:
        mov  r2,#80
        mov  r4,#0
LDelay1:
        djnz r4,LDelay1

        djnz r2,LDelay1
        ret



Randomize:
            mov   a,RND+3
            rr    a
            rr    a
            xrl   a,RND+2
            rr    a
            rr    a
            rr    a
            rr    a
            xrl   a,RND
            rr    a
            xrl   a,RND
            xrl   a,#1
            rrc   a
            mov   a,RND
            rlc   a
            mov   RND,a
            mov   a,RND+1
            rlc   a
            mov   RND+1,a
            mov   a,RND+2
            rlc   a
            mov   RND+2,a
            mov   a,RND+3
            rlc   a
            mov   RND+3,a
           
            mov   a,RND+7
            anl   a,#11101010b
            mov   c,p
            rlc   a
            xrl   a,RND+4
            rrc   a
            mov   a,RND+7
            rrc   a
            mov   RND+7,a
            mov   a,RND+6
            rrc   a
            mov   RND+6,a
            mov   a,RND+5
            rrc   a
            mov   RND+5,a
            mov   a,RND+4
            rrc   a
            mov   RND+4,a
           
            ret


;----- Data modification algos

Run1:                   ;random running from end to beginning
;         jnb  IntFlag,IWX1
;         clr  IntFlag
         mov  a,IntTim1
         jnz  Run1X1
         mov  IntTim1,#20    ;speed
         mov  a,Rnd+7
         anl  a,#7
         clr  c
         jnz  Run1X2
         setb c
Run1X2:  mov  a,Data0
         orl  a,Data1
         jnz  Run1X3
         setb c
Run1X3:  mov  a,Data0
         jnb  acc.0,Run1X4
         clr  c
Run1X4:  mov  a,Data0
         rlc  a
         mov  Data0,a
         mov  a,Data1
         rlc  a
         mov  Data1,a
         dec  AlgoTim
Run1X1:
         ret


Run2:                   ;random running from beginning to end
         mov  a,IntTim1
         jnz  Run2X1
         mov  IntTim1,#20    ;speed
         mov  a,Rnd+7
         anl  a,#7
         clr  c
         jnz  Run2X2
         setb c
Run2X2:  mov  a,Data0
         orl  a,Data1
         jnz  Run2X3
         setb c
Run2X3:  mov  a,Data1
         jnb  acc.7,Run2X4
         clr  c
Run2X4:  mov  a,Data1
         rrc  a
         mov  Data1,a
         mov  a,Data0
         rrc  a
         mov  Data0,a
         dec  AlgoTim
Run2X1:
         ret


Run3:                   ;1:1 flash
         mov  a,IntTim1
         jnz  Run3X1
         mov  IntTim1,#40    ;speed
         mov  a,AlgoTim
         inc  a
         jnz  Run3X2
         mov  Data0,#55h
         mov  Data1,#55h
         mov  AlgoTim,#100   ;short down this mode - it's too long and boring
Run3X2:
         xrl  Data0,#0FFh
         xrl  Data1,#0FFh
         dec  AlgoTim
Run3X1:
         ret



Run4:    mov  a,IntTim1        ;KIT - KnightRider
         jnz  Run4X1
         mov  IntTim1,#16

         mov  a,AlgoTim
         mov  b,#14
         div  ab
         mov  a,b
         mov  r2,a
         add  a,#Run4T1-Run4X2
         movc a,@a+pc
Run4X2:
         mov  Data0,a

         mov  a,r2
         add  a,#Run4T2-Run4X3
         movc a,@a+pc
Run4X3:
         mov  Data1,a

         dec  AlgoTim
Run4X1:
         ret
Run4T1:  db   80h,40h,20h,10h,08h,04h,02h
         db   01h,02h,04h,08h,10h,20h,40h

Run4T2:  db   01h,02h,04h,08h,10h,20h,40h
         db   80h,40h,20h,10h,08h,04h,02h



Run4a:   mov  a,IntTim1        ;KIT - KnightRider - 2
         jnz  Run4aX1
         mov  IntTim1,#16

         mov  a,AlgoTim
         mov  b,#22
         div  ab
         mov  a,b
         mov  r2,a
         add  a,#Run4aT1-Run4aX2
         movc a,@a+pc
Run4aX2:
         mov  Data0,a

         mov  a,r2
         add  a,#Run4aT2-Run4aX3
         movc a,@a+pc
Run4aX3:
         mov  Data1,a

         dec  AlgoTim
Run4aX1:
         ret
Run4aT2: db   80h,40h,20h,10h,08h,04h,02h
         db   01h,02h,04h,08h,10h,08h,04h,02h
         db   01h,02h,04h,08h,10h,20h,40h

Run4aT1: db   01h,02h,04h,08h,10h,20h,40h
         db   80h,40h,20h,10h,08h,10h,20h,40h
         db   80h,40h,20h,10h,08h,04h,02h



Run5:                   ;ping-pong
         mov  a,IntTim1
         jnz  Run5X1
         mov  IntTim1,#15    ;speed
         mov  a,AlgoTim
         inc  a
         jnz  Run5X2
         mov  Data0,#01h
         mov  Data1,#00h
         sjmp Run5X3
Run5X2:
         mov  a,AlgoTim
         jnb  acc.4,Run5X4     ;determine the movement direction
         clr  c
         mov  a,Data0
         rlc  a
         mov  Data0,a
         mov  a,Data1
         rlc  a
         jc   Run5X3       ;not to loose the "ball" if it would "fall over the edge"
         mov  Data1,a
         sjmp Run5X3
Run5X4:
         clr  c
         mov  a,Data1
         rrc  a
         mov  Data1,a
         mov  a,Data0
         rrc  a
         jc   Run5X3       ;not to loose the "ball" if it would "fall over the edge"
         mov  Data0,a
Run5X3:
         dec  AlgoTim
Run5X1:
         ret
;------------------ THAT'S ALL, FOLKS! -------------------
        end



Tato novinka je z -MCU-mikroelektronika
( http://mcu.cz/news.php?extend.1615 )