;Program: Hodiny
;*********************************
	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

#define Q       PORTB,0
#define RS      PORTB,1 
#define RW      PORTB,2
#define E       PORTB,3
#define BF      RBF,3
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
	ORG     0
	GOTO    START
	ORG     4
;****************************************************************************
;PODPROGRAMY
;****************************************************************************
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		;tiskt znaku z registru NUM
	RETURN

;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
;PROGRAM
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
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

	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

