;Program: Hodina
;*********************************
  LIST P = 16F84, R = DEC
  #INCLUDE <P16F84.INC>
;---------------------------------

 __CONFIG   _CP_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC
;****************************************************************************
RAM     EQU     H'0C'
;----------------------------------------------------------------------------
RAM     EQU     H'0C'
RBF     EQU     RAM
RBF1    EQU     RAM+1
NUM     EQU     RAM+2
NUM1    EQU     RAM+3
TMP     EQU     RAM+4
TM1     EQU     RAM+5
TM2     EQU     RAM+6

JEDN    EQU     RAM+7
DES     EQU     RAM+8
HOD     EQU     RAM+9
MIN     EQU     RAM+10
SEC     EQU     RAM+11
POM     EQU     RAM+12
ADRDD   EQU     RAM+13
HEX     EQU     RAM+14
TMR     EQU     RAM+15
MEM_W   EQU     RAM+16
MEM_S   EQU     RAM+17
        CBLOCK  RAM+18
         TM : 4
        ENDC 

#define Q       PORTB,0
#define RS      PORTB,1 
#define RW      PORTB,2
#define E       PORTB,3
#define BF      RBF,3
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
        ORG     0
        GOTO    START
;*******************************************************************************
        ORG     4
INTR    MOVWF   MEM_W           ;úschova registru W
        SWAPF   STATUS,W
        MOVWF   MEM_S           ;úschova registru STATUS

        BCF     STATUS,RP0      ;banka 0
        NOP                     ;vyrovnání času
        NOP
        NOP
        NOP
        NOP
        MOVLW   100
        MOVWF   TMR0            ;časový registr TMR0 = 100

        INCF    TMR,F           ;registr TMR + 1
        MOVFW   TMR
        XORLW   100
        BTFSS   STATUS,Z        ;je registr TMR=100 nebo-li uplynula 1 sekunda?
        GOTO    CAS_1           ;ne,proveď skok na návěští CAS_1

        CLRF    TMR             ;ano,vynuluj registr TMR

        INCF    SEC,F           ;registr sekund (SEC) + 1
        MOVFW   SEC
        XORLW   60
        BTFSS   STATUS,Z        ;je SEC = 60?
        GOTO    CAS             ;ne,proveď skok na návěští CAS

        CLRF    SEC             ;ano,vynuluj sekundy
        INCF    MIN,F           ;registr minut (MIN) + 1
        MOVFW   MIN
        XORLW   60
        BTFSS   STATUS,Z        ;je MIN = 60?
        GOTO    CAS             ;ne,proveď skok na návěští CAS

        CLRF    MIN             ;ano,vynuluj minuty
        INCF    HOD,F           ;registr hodin (HOD) + 1
        MOVFW   HOD
        XORLW   24
        BTFSC   STATUS,Z        ;je HOD = 24?
        CLRF    HOD             ;ano,vynuluj hodiny

CAS     MOVLW   132             ;nastavení adresy displeje DDRAM
        CALL    Z_CAS           ;zobrazení času

CAS_1   BCF     INTCON,T0IF     ;vynulování bitu přerušení

        SWAPF   MEM_S,W
        MOVWF   STATUS          ;obnova registru STATUS
        SWAPF   MEM_W,F
        SWAPF   MEM_W,W         ;obnova registru W

        RETFIE
;*******************************************************************************
INILCD  CALL    t15mS           ;doba 15 milisekund
        BCF     RS
        BCF     RW
        CALL    A_OUT           ;port A výstup
        BSF     E
        MOVLW   B'00000011'
        MOVWF   PORTA
        BCF     E
        CALL    t4mS            ;doba 4 milisekund
        BSF     E
        MOVLW   B'00000011'
        MOVWF   PORTA
        BCF     E
        CALL    t100uS          ;doba 100 mikrosekund
        BSF     E
        MOVLW   B'00000011'
        MOVWF   PORTA
        BCF     E
        CALL    t100uS          ;doba 100 mikrosekund
        MOVLW   B'00101000'
        CALL    WRPRI           ;4.bitová komunikace a dva řádky
        MOVLW   B'00001000'
        CALL    WRPRI           ;displej OFF
        MOVLW   B'00001100'
        CALL    WRPRI           ;displej ON, kurzor OFF, blikání OFF
        MOVLW   B'00000110'
        CALL    WRPRI           ;inkrementace, normální operace
        MOVLW   1
        CALL    WRPRI           ;reset displeje
        RETURN
;-------------------------------------------------------------------------------
WRDATA  BSF     RS              ;nastavení bitu RS pro zápis dat
        GOTO    $+2
WRPRI   BCF     RS              ;nastavení bitů RS a RW pro zápis příkazu
        BCF     RW
        MOVWF   TMP             ;číslo příkazu nebo data do registru TMP
        CALL    A_OUT           ;portA jako výstup
        SWAPF   TMP,W           ;horní 4 bity do registru W
        BSF     E
        MOVWF   PORTA           ;zápis 4 horních bitů do displeje
        BCF     E
        MOVFW   TMP             ;obsah registru TMP do registru W
        BSF     E
        MOVWF   PORTA           ;zápis dolních 4 bitů do displeje
        BCF     E
        CALL    T_BF            ;testování bitu BF
        RETURN
;------------------------------------------------------------------------------- 
RDDATA  CALL    WRPRI           ;nastavení čtené adresy
        CALL    A_IN            ;port A vstup 
        BSF     RS
        BSF     RW
        BSF     E
        MOVFW   PORTA
        MOVWF   NUM             ;jedna půlka dat do registru NUM
        SWAPF   NUM,F
        BCF     E
        MOVLW   B'11110000'
        ANDWF   NUM,F           ;úprava registru NUM
        BSF     E
        MOVFW   PORTA
        MOVWF   NUM1
        BCF     E
        MOVLW   B'00001111'
        ANDWF   NUM1,W
        IORWF   NUM,F           ;druhá půlka dat do registru NUM
        CALL    T_BF            ;čeká konec operace
        RETURN
;-------------------------------------------------------------------------------
T_BF    BCF     RS              ;podprogram testuje konec operace (bit BF)
        BSF     RW
        CALL    A_IN            ;portA vstup (po ukončení zase výstup)
        BSF     E
        MOVFW   PORTA
        MOVWF   RBF
        BCF     E
        NOP
        BSF     E
        MOVFW   PORTA
        MOVWF   RBF1
        BCF     E
        BTFSC   BF              ;je bit BF=0 ? (0 = konec operace)
        GOTO    $-10            ;ne - testuj znova
;-------------------------------------------------------------------------------
A_OUT   MOVLW   B'11110000'     ;pin A0/A3 výstup, pin A4 vstup
        GOTO    $+2
A_IN    MOVLW   B'11111111'     ;pin A0/A7 vstup
        BSF     STATUS,RP0      ;banka 1
        MOVWF   TRISA           ;nastavení portu A
        BCF     STATUS,RP0      ;banka 0
        RETURN
;*******************************************************************************

t15mS   MOVLW   246             ;doba 15 milisekund
        GOTO    $+2
t4mS    MOVLW   66              ;doba 4 milisekund
        MOVWF   TM1
        MOVLW   19
        MOVWF   TM2
        DECFSZ  TM2,F
        GOTO    $-1
        DECFSZ  TM1,F
        GOTO    $-5
        RETURN
;-------------------------------------------------------------------------------
t100uS  MOVLW   33              ;doba 100 mikrosekund
        MOVWF   TM1
        DECFSZ  TM1,F
        GOTO    $-1
        RETURN

;*******************************************************************************
t500mS  CLRF    TM2             ;doba 500 milisekund
        CLRF    TM1
        NOP
        DECFSZ  TM1,F
        GOTO    $-2
        NOP
        DECFSZ  TM1,F
        GOTO    $-2
        DECFSZ  TM2,F
        GOTO    $-7
        RETURN
;*******************************************************************************
PREVOD  MOVLW   48
        MOVWF   DES             ;registr DES=48
        MOVWF   JEDN            ;registr JEDN=48
        MOVLW   10
        SUBWF   NUM,W           ;W=NUM-10
        BTFSS   STATUS,C        ;došlo k podtečení?
        GOTO    $+4             ;ano,proveď skok
        MOVWF   NUM             ;obsah W do NUM
        INCF    DES,F           ;registr DES + 1
        GOTO    $-6             ;odečítej znova
        MOVFW   NUM
        ADDWF   JEDN,F          ;zbytek přičíst do registru JEDN
        RETURN

;*******************************************************************************
PREV_X  MOVWF   POM             ;úschova adresy DDRAM
        CALL    RDDATA          ;načtení čísla z adresy DDRAM do NUM
        CLRF    HEX             ;vynulování registru HEX
        MOVLW   47
        SUBWF   NUM,F           ;registr NUM=NUM-47

        DECF    NUM,F           ;registr NUM-1
        BTFSC   STATUS,Z        ;je NUM=0?
        GOTO    $+4             ;ano,proveď skok
        MOVLW   10              ;ne
        ADDWF   HEX,F           ;registr HEX=HEX+10
        GOTO    $-5             ;a znova dokola

        INCF    POM,W           ;uschovaná adresa DDRAM+1
        CALL    RDDATA          ;načtení čísla z adresy DDRAM do NUM
        MOVLW   47
        SUBWF   NUM,F           ;registr NUM=NUM-47

        DECF    NUM,F           ;registr NUM-1
        BTFSC   STATUS,Z        ;je NUM=0?
        GOTO    $+3             ;ano,proveď skok
        INCF    HEX,F           ;ne,registr HEX=HEX-1
        GOTO    $-4             ;a znova dokola

        MOVFW   HEX             ;obsah HEX do W
        RETURN

;*******************************************************************************
Z_CAS   CALL    WRPRI           ;dle obsahu registru W nastaví adresu displeje DDRAM
        MOVFW   HOD
        MOVWF   NUM             ;obsah registru hodin do NUM
        CALL    PREVOD          ;převod na dekadické číslo
        CALL    ZOBR            ;zobrazení hodin

        MOVFW   MIN
        MOVWF   NUM             ;obsah registru minut do NUM
        CALL    PREVOD          ;převod na dekadické číslo
        CALL    ZOBR_1          ;zobrazení dvojtečky a minut

        MOVFW   SEC
        MOVWF   NUM             ;obsah registru sekund do NUM
        CALL    PREVOD          ;převod na dekadické číslo
        CALL    ZOBR_1          ;zobrazení dvojtečky a minut

        RETURN

;-------------------------------------------------------------------------------
ZOBR_1  MOVLW   58
        CALL    WRDATA          ;tisk dvojtečky

ZOBR    MOVFW   DES
        CALL    WRDATA          ;tisk desítek
        MOVFW   JEDN
        CALL    WRDATA          ;tisk jednotek

        RETURN
;*******************************************************************************
TISK    MOVFW   ADRDD
        CALL    WRPRI           ;nastavení adresy displeje DDRAM
        MOVFW   NUM
        CALL    WRDATA          ;tisk znaku z registru NUM
        RETURN
;*******************************************************************************                
t1hod   MOVLW   H'FE'           ;čtyřbajtová časová smyčka
        MOVWF   TM+0
        MOVLW   H'94'
        MOVWF   TM+1
        MOVLW   H'BA'
        MOVWF   TM+2
        MOVLW   H'0A'
        MOVWF   TM+3
        CALL    t10uS
        
SMC     MOVF    TM+0,F
        BTFSS   STATUS,Z
        GOTO    SMC_1
        MOVF    TM+1,F
        BTFSS   STATUS,Z
        GOTO    SMC_2
        MOVF    TM+2,F
        BTFSS   STATUS,Z
        GOTO    SMC_3
        MOVF    TM+3,F
        BTFSC   STATUS,Z
        GOTO    SMC_4
        
        DECF    TM+3,F        
SMC_5   DECF    TM+2,F
SMC_6   DECF    TM+1,F
SMC_7   DECF    TM+0,F
        NOP
        NOP
        GOTO    SMC
        
SMC_1   CALL    t9uS
        GOTO    SMC_7                
        
SMC_2   CALL    t5uS
        GOTO    SMC_6
        
SMC_3   NOP
        GOTO    SMC_5
        
SMC_4   CALL    t5uS
        RETURN        
        
;-------------------------------------------------------------------------------
t10uS   NOP                     ;časové vyrovnánky čtyřbajtové časové smyčky
t9uS    NOP
        NOP
        NOP
        NOP
t5uS    NOP
        RETURN
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
;PROGRAM
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
START   BSF     STATUS,RP0      ;banka1
        MOVLW   B'11100001'
        MOVWF   TRISB           ;nastavení portu B
        MOVLW   B'11000101'
        MOVWF   OPTION_REG      ;registr TMR0 načítán vnitřními hodinami s dělícím poměrem 1:64
        BCF     STATUS,RP0      ;banka 0

        CALL    INILCD          ;inicializace a reset displeje

        CLRF    HOD             ;registr hodin vynulován
        CLRF    MIN             ;registr minut vynulován
        CLRF    SEC             ;registr sekund vynulován
        CLRF    TMR             ;časový registr TMR vynulován

        MOVLW   132
        CALL    Z_CAS           ;na adresu 132 DDRAM se vytiskne čas 00:00:00

        MOVLW   B'00001110'
        CALL    WRPRI           ;kurzor povolen

        MOVLW   132
        MOVWF   ADRDD           ;výchozí adresa DDRAM (132)

KLAVES  MOVFW   ADRDD
        CALL    WRPRI           ;nastav adresu DDRAM displeje

        CALL    t500mS          ;doba 0,5 sekundy

KLAV    CLRF    POM             ;0 do registru POM
        MOVFW   POM
        MOVWF   PORTA           ;obsah registru POM na port A
        BTFSC   Q               ;je stisknuto příslušné tlačítko?
        GOTO    SKOK            ;ano,proveď jdi na návěští SKOK
        INCF    POM,F           ;registr POM + 1
        BTFSS   POM,3           ;je POM = 8?
        GOTO    $-6             ;ne,udělej skok
        GOTO    KLAV            ;ano,jdi na KLAV

;*******************************************************************************

DOLU    MOVFW   ADRDD           ;adresa DDRAM do registru W
        CALL    RDDATA          ;přečti data
        DECF    NUM,F           ;registr NUM - 1
        MOVFW   NUM
        XORLW   47
        BTFSC   STATUS,Z        ;je NUM = 47?
        INCF    NUM,F           ;ano,odečti jednu
        CALL    TISK            ;proveď tisk na displej
        GOTO    KLAVES          ;jdi na návěští KLAVES

PRAVO   INCF    ADRDD,F         ;adresa DDRAM + 1
        MOVFW   ADRDD
        XORLW   134
        BTFSC   STATUS,Z        ;je adresa displeje DDRAM rovna 134?
        INCF    ADRDD,F         ;ano,tak ji zvyš o jednu
        MOVFW   ADRDD 
        XORLW   137
        BTFSC   STATUS,Z        ;je adresa displeje DDRAM rovna 137?
        INCF    ADRDD,F         ;ano,tak ji zvyš o jednu
        MOVFW   ADRDD
        XORLW   140
        BTFSC   STATUS,Z        ;je adresa displeje DDRAM rovna 140?
        DECF    ADRDD,F         ;ano,tak ji sniž o jednu
        GOTO    KLAVES          ;jdi na návěští KLAVES

NAHR    MOVFW   ADRDD           ;adresa DDRAM do registru W
        CALL    RDDATA          ;přečti data
        INCF    NUM,F           ;registr NUM + 1
        MOVFW   NUM
        XORLW   58
        BTFSC   STATUS,Z        ;je NUM = 58?
        DECF    NUM,F           ;ano,odečti jednu
        CALL    TISK            ;proveď tisk na displej
        GOTO    KLAVES          ;jdi na návěští KLAVES

VLEVO   DECF    ADRDD,F         ;adresa DDRAM - 1
        MOVFW   ADRDD
        XORLW   137
        BTFSC   STATUS,Z        ;je adresa displeje DDRAM rovna 137?
        DECF    ADRDD,F         ;ano,tak ji sniž o jednu
        MOVFW   ADRDD
        XORLW   134
        BTFSC   STATUS,Z        ;je adresa displeje DDRAM rovna 134?
        DECF    ADRDD,F         ;ano,tak ji sniž o jednu
        MOVFW   ADRDD
        XORLW   131
        BTFSC   STATUS,Z        ;je adresa displeje DDRAM rovna 131?
        INCF    ADRDD,F         ;ano,tak ji zvyš o jednu
        GOTO    KLAVES          ;jdi na návěští KLAVES

;**************************************************************
ENTER   MOVLW   B'00001100' 
        CALL    WRPRI           ;kurzor vypnut

        MOVLW   132             ;adresa displeje DDRAM do registru W
        CALL    PREV_X          ;proveď převod
        MOVWF   HOD             ;výsledek převodu zapiš do registru hodin

        MOVLW   135             ;adresa displeje DDRAM do registru W
        CALL    PREV_X          ;proveď převod
        MOVWF   MIN             ;výsledek převodu zapiš do registru minut

        MOVLW   138             ;adresa displeje DDRAM do registru W
        CALL    PREV_X          ;proveď převod
        MOVWF   SEC             ;výsledek převodu zapiš do registru sekund


BOD     CLRF    TMR0            ;časový speciální registr TMR0 vynulován
        MOVLW   B'10100000'
        MOVWF   INTCON          ;přerušení od přetečení registru TMR0 povoleno

        CALL    t1hod           ;zavolání podprogramu doby 1 hodiny
        CLRF    INTCON          ;zákaz přerušení
        GOTO    $-0             ;věčná smyčka

;**************************************************************
        ORG     768             ;nastavení adresy programové paměti
SKOK    MOVLW   3
        MOVWF   PCLATH          ;nastavení stránky PCLATH
        MOVFW   POM
        ADDWF   PCL,F           ;skok podle velikosti POM
        GOTO    ENTER           ;jdi na návěští ENTER
        GOTO    DOLU            ;jdi na návěští DOLU
        GOTO    PRAVO           ;jdi na návěští PRAVO
        GOTO    NAHR            ;jdi na návěští NAHR
        GOTO    VLEVO           ;jdi na návěští VLEVO
        GOTO    KLAV            ;jdi na návěští KLAV
        GOTO    KLAV            ;jdi na návěští KLAV
        GOTO    KLAV            ;jdi na návěští KLAV
;**************************************************************
        END        
         
