;                                     _\|/_
;                                   ( o   o )
;==============================oOOo=====V=====oOOo=============================
;Výukový prográmek 3 - HÁZECÍ KOSTKY
;------------------------------------------------------------------------------
;Zdrojový text pro makroasembler MetaLink a kompatibilní
;Kódování češtiny : ANSI
;Hardware: µP 89C2051
;          krystal cca 12 MHz (1 str. cykl pak trvá 1 µs)
;==============================================================================


;Obvod imituje jednu až tři házecí kostky, počet kostek se volí přepínačem FUNKCE.
;Tečky na házecích kostkách jsou imitovány obrazcem vytvořeným z LED
;Princip funkce :
;  volně běžící čítač T1 je nastaven na cykl 216
;  pomocí tlačítek START resp. STOP se povoluje resp. zakazuje běh čítače T1
;  stav čítače T1 je cyklicky čten a podle zvolené funkce je převáděn na kód pro rozsvěcení LED


            $MOD2051
            $NOPAGING
            $PAGEWIDTH(115)
;******************************************************************************
;Porty uP
;==============================================================================
;                 P1.0   nepoužito
KATODY      EQU   P1    ;bity .1 až .7 - katody matice LED (výstupy, aktivní = 0)
;                 P3.0-1 přepínač funkce (vstupy, aktivní = 0)
BUTSTART    EQU   P3.2  ;tlačítko START (vstup, aktivní = 0)
;                 P3.3-5 anody matice LED (přes tranzistorové spínače, aktivní = 0)
BUTSTOP     EQU   P3.7  ;tlačítko STOP (vstup, aktivní = 0)
;==============================================================================


;******************************************************************************
;Organizace paměti
;==============================================================================
;Vyhražená RAM
;==============================================================================
            DSEG  AT 0008h
LEDREGA:    DS    1      ;registr stavu LED pro kostku A
            DSEG  AT 0010h
LEDREGB:    DS    1      ;registr stavu LED pro kostku B
            DSEG  AT 0020h
LEDREGC:    DS    1      ;registr stavu LED pro kostku C
            DSEG  AT 0040h
STACK:      DS    64     ;zásobník
;==============================================================================
;Banky registrů - všechny procedury používají pouze banku 0, banky 1 až 3 nevyužity
;==============================================================================
LEDPTR      EQU   R0     ;[adr. 00h] pointer pozice aktivní kostky (tj. anod LED)
                         ;           nabývá hodnoty 08h, 10h, 20h
;==============================================================================
;Přímo adresované proměnné
;==============================================================================
COUNTER     DATA  30h    ;softwarový časovač intervalu cca 10 ms
NUMA        DATA  31h    ;číslo určující zobrazení kostky A
NUMB        DATA  32h    ;číslo určující zobrazení kostky B
NUMC        DATA  33h    ;číslo určující zobrazení kostky C
;==============================================================================
;Bitové proměnné
;------------------------------------------------------------------------------
FLAG        DATA  21h
FLSTOP      EQU   FLAG.0 ;příznak stisknutého tlačítka STOP, mění se pouze v přerušení T0
FLSTART     EQU   FLAG.1 ;příznak stisknutého tlačítka START, mění se pouze v přerušení T0
;==============================================================================


;*******************************************************************************
;Vektory přerušení
;===============================================================================
            CSEG
            ORG   0000h
            JMP   init               ;inicializace, začátek běhu programu po zapnutí
            ORG   000Bh
            JMP   timer0             ;časovač T0 - časová základna
            CSEG  AT 0030h
;===============================================================================


;*******************************************************************************
;Inicializace
;===============================================================================
init:       ;nulování interní uživatelské RAM µP
            MOV   R0, #07Fh
init1:      MOV   @R0, #0            ;do všech buněk RAM (v pořadí 7Fh -> 00h) je zapsána 0
            DJNZ  R0, init1
            ;-------------------------------------------------------------------
            ;nastavení proměnných
            MOV   LEDPTR, #00100000b ;výchozí stav pointeru anod LED - aktivní kostka C
            MOV   COUNTER, #10       ;časovač intervalu 10 ms
            MOV   LEDREGA, #0FFh     ;zhasnout A
            MOV   LEDREGB, #0FFh     ;zhasnout B
            MOV   LEDREGC, #0FFh     ;zhasnout C
            ;-------------------------------------------------------------------
            ;nastavení SFR
            MOV   SP, #STACK-1       ;nastavení hloubky zásobníku
            MOV   TH0, #252          ;přetečení T0 po 1024 str.c. [ (256-252)x256 ]
            MOV   TL0, #0
            MOV   TH1, #40           ;přetečení T1 po 216 str.c.
            MOV   TL1, #40
            MOV   TMOD, #00100001b   ;T0 -> časovač v módu 1, T1 -> časovač v módu 2
            MOV   TCON, #01010000b   ;T0 i T1 běží
            MOV   IE, #10000010b     ;povoleno přerušení "global" a T0
            ;v ostatních SFR zůstávají hodnoty nastavené při resetu
;===============================================================================


;*******************************************************************************
;Hlavní programová smyčka
;===============================================================================
;Podle stavu (příznaku) tlačítek se povoluje nebo zakazuje běh čítače T1
;-------------------------------------------------------------------------------
main:       ;čekat na uvolnění obou tlačítek
            MOV   A, FLAG
            ANL   A, #00000011b      ;jen bity .0 a .1
            JNZ   main
            ;-------------------------------------------------------------------
main_1:     JNB   FLSTOP, main_2
            ;bylo stisknuto tlačítko STOP
            CLR   TR1                ;zastavit T1
            JMP   main               ;návrat na začátek hl. smyšky
main_2:     JNB   FLSTART, main_1
            ;bylo stisknuto tlačítko START
            SETB  TR1                ;rozběhnout T1
            JMP   main               ;návrat na začátek hl. smyšky
;===============================================================================


;*******************************************************************************
;Obsluha přerušení od časovače T0 - po 1024 str. cyklech (cca 1 ms)
;===============================================================================
;- časová základna pro řízení multiplexu matice LED
;- čtení ovládacích tlačítek a přepínače funkce
;- výpočty hodnot pro zobrazení LED
;-------------------------------------------------------------------------------
timer0:     MOV   TH0, #252          ;zkrácení běhu 16ti bitového časovače na (256-252)x256=1024 cyklů
            PUSH  ACC                ;uložení obsahu akumulátoru do zásobníku
            PUSH  PSW                ;uložení stavu příznaků do zásobníku
            ;-------------------------------------------------------------------
            ;obsluha matice LED - frekvence multiplexu cca 325,5 Hz
            ORL   P3, #00111000b     ;vypnutí všech anod matice LED (neaktivní stav = 1)
            MOV   A, LEDPTR          ;načtení stávajícího pointeru anod LED
            RL    A                  ;posun aktivní anody
            CJNE  A, #01000000b, tim0_1 ;pokud není nová hodnota pointeru anod mino povolený rozsah, tak pokračovat
            MOV   A, #00001000b      ;při "přetečení" pointeru zpět na první anody (kostka A)
tim0_1:     MOV   LEDPTR, A          ;uložení nové hodnoty poineru anod LED
            MOV   KATODY, @LEDPTR    ;nová data na katody LED - z adres 08h / 10h / 20h
            CPL   A                  ;invertovat - aktivní anody jsou 0
            ANL   A, P3              ;přičíst stav portu k novému poineru anod LED
            MOV   P3, A              ;přesun výsledku zpět na port - nyní jsou aktivovány nové anody
                                     ;při zachování stavu ostatních bitů portu P3
            ;-------------------------------------------------------------------
            DJNZ  COUNTER, tim0_e
            MOV   COUNTER, #10       ;časovač intervalu 10x1024 str. cyklů
            ;-------------------------------------------------------------------
            ;čtení stavu tlačítek po cca 10 ms
            MOV   C, BUTSTART        ;čtení bitu portu P3
            CPL   C                  ;ivertovat hodnotu
            MOV   FLSTART, C         ;uložit hodnotu do příznaku tlačítka (1 = stisk, 0 = uvolnění)
            MOV   C, BUTSTOP         ;čtení bitu portu P3
            CPL   C                  ;ivertovat hodnotu
            MOV   FLSTOP, C          ;uložit hodnotu do příznaku tlačítka (1 = stisk, 0 = uvolnění)
            ;-------------------------------------------------------------------
            ;čtení stavu přepínače funkce
            MOV   A, P3              ;načtení stavu přepínače
            ANL   A, #00000011b      ;zachovat pouze bity .0 a .1 - ostatní nejsou přepínač
            DEC   A                  ;nyní je v ACC číslo funkce : 0 = A+C, 1 = B, 2 = A+B+C
            ;-------------------------------------------------------------------
            ;zobrazení LED dle stavu čítače T1 a dle stavu přepínače funkce
            RL    A                  ;ACC = 0 / 2 / 4
            MOV   DPTR, #disp_dir
            JMP   @A+DPTR            ;podle zvolené funkce se provede skok na odpovídající proceduru
disp_dir:   AJMP  disp_0
            AJMP  disp_1
            AJMP  disp_2
            ;-------------------------------------------------------------------
disp_0:     ;zobrazují se kostky A+C
            MOV   NUMB, #6           ;kostka B zhasnuta
            MOV   A, TL1             ;= 40 až 255
            CPL   A                  ;= 215 až 0
            MOV   B, #6
            DIV   AB                 ;vydělením šesti dostaneme podíl (0 až 35) a zbytek (0 až 5)
            MOV   NUMA, B            ;zbytek je hodnota kostky
            MOV   B, #6
            DIV   AB                 ;opakovaným dělením šesti dostaneme podíl (0 až 5) a zbytek (0 až 5)
            MOV   NUMC, B            ;zbytek je hodnota kostky
            CALL  led_data           ;překódování čísel a přenos do registrů LED
            JMP   tim0_e
            ;-------------------------------------------------------------------
disp_1:     ;zobrazuje se kostka B
            MOV   NUMA, #6           ;kostka A zhasnuta
            MOV   NUMC, #6           ;kostka C zhasnuta
            MOV   A, TL1             ;= 40 až 255
            CPL   A                  ;= 215 až 0
            MOV   B, #6
            DIV   AB                 ;vydělením šesti dostaneme podíl (0 až 35) a zbytek (0 až 5)
            MOV   NUMB, B            ;zbytek je hodnota kostky
            CALL  led_data           ;překódování čísel a přenos do registrů LED
            JMP   tim0_e
            ;-------------------------------------------------------------------
disp_2:     ;zobrazují se kostky A+B+C
            MOV   A, TL1             ;= 40 až 255
            CPL   A                  ;= 215 až 0
            MOV   B, #6
            DIV   AB                 ;vydělením šesti dostaneme podíl (0 až 35) a zbytek (0 až 5)
            MOV   NUMA, B            ;zbytek je hodnota kostky
            MOV   B, #6
            DIV   AB                 ;opakovaným dělením šesti dostaneme podíl (0 až 5) a zbytek (0 až 5)
            MOV   NUMB, B            ;tato čísla jsou již hodnotami kostek
            MOV   NUMC, A
            CALL  led_data           ;překódování čísel a přenos do registrů LED
            ;-------------------------------------------------------------------
tim0_e:     POP   PSW                ;obnovení stavu příznaků ze zásobníku
            POP   ACC                ;obnovení obsahu akumulátoru ze zásobníku
            RETI                     ;návrat z obsluhy přerušení
;===============================================================================


;*******************************************************************************
;Podprogram překódování a přenosu dat do registrů LED
;===============================================================================
;čísla 0 až 5 jsou překódována na symboly 1 až 6 teček házecích kostek
;číslo 6 znamená zhasnutí všech LED
;-------------------------------------------------------------------------------
led_data:   MOV   DPTR, #tab_dat     ;adresa začátku převodní tabulky
            MOV   A, NUMA            ;hodnota kostky A (0 až 5 / 6)
            MOVC  A, @A+DPTR         ;převod na kód katod LED
            MOV   LEDREGA, A         ;uložení kódu katod LED do registru pro zobrazení
            MOV   A, NUMB            ;hodnota kostky A (0 až 5)
            MOVC  A, @A+DPTR         ;převod na kód katod LED
            MOV   LEDREGB, A         ;uložení kódu katod LED do registru pro zobrazení
            MOV   A, NUMC            ;hodnota kostky A (0 až 5)
            MOVC  A, @A+DPTR         ;převod na kód katod LED
            MOV   LEDREGC, A         ;uložení kódu katod LED do registru pro zobrazení
            RET                      ;návrat z podprogramu
;===============================================================================


;*******************************************************************************
;Tabulky dat
;===============================================================================
;Překódování čísel pro matici LED, hodnoty 0 až 5 se mění na data pro katody LED :

;           Port P1:   .7  .6  .5  .4  .3  .2  .1  .0
;Hodnota    Kostka A:  D1  D2  D3  D4  D5  D6  D7  -
;  vst.     Kostka B:  D8  D9  D10 D11 D12 D13 D14 -
; čísla     Kostka D:  D15 D16 D17 D18 D19 D20 D21 -
;-------    ------------------------------------------------
;   0                  1   1   1   1   1   1   0   1   = FDh
;   1                  0   1   1   1   1   0   1   1   = 7Bh
;   2                  0   1   1   1   1   0   0   1   = 79h
;   3                  0   1   0   0   1   0   1   1   = 4Bh
;   4                  0   1   0   0   1   0   0   1   = 49h
;   5                  0   0   0   0   0   0   1   1   = 03h
;zhasnuto              1   1   1   1   1   1   1   1   = FFh
;-------------------------------------------------------------------------------
tab_dat:    DB    0FDh,07Bh,079h,04Bh,049h,003h,0FFh
;===============================================================================
;Signatura
;-------------------------------------------------------------------------------
            DB    'HAZECI KOSTKY'
;===============================================================================
            END