$MOD51
    DSEG
    Org 30H
Milidetik:   Ds  1
Detik:       Ds  1
Menit:       Ds  1
Jam:         Ds  1
TabelDesimal:   Ds  2
    CSEG
ROM     EQU     0000
        Org     ROM                   ;Reset Vector
    Ajmp    Start           ;
        Org     ROM+3                   ;External Interrupt 0 Vector
    Ajmp    INTR0
        Org     ROM+0BH                   ;Timer 0 Interrupt Vector
    Ajmp    Timer0_Interrupt
        Org     ROM+13H                   ;External Interrupt 1 Vector
    Ajmp    INTR1
        Org     ROM+1BH                   ;Timer 1 Interrupt Vector
    Reti                ;
        Org     ROM+23H                   ;Serial Interrupt Vector
    Reti

Start:
    Lcall   Init_LCD        ;Inisial LCD
    Acall   ResetWaktu      ;Reset variabel waktu

    Mov TMOD,#01            ;Timer 0 16 bit counter
    Acall   ResetTimer0     ;Atur nilai Timer 0 agar overflow setiap 10mS
    Setb    EA              ;
    Setb    ET0             ;Aktifkan Interupsi Timer 0
    Setb    TR0             ;Aktifkan Timer 0
    Setb    EX0             ;Aktifkan Interupsi External 0
    Setb    EX1             ;Aktifkan Interupsi External 1
    Ajmp    $

;Bagian untuk memberi nilai awal Timer
ResetWaktu:
    Lcall   Init_LCD
    Mov A,#84H              ;Tunjuk kolom 4 dan baris 1 LCD
    Lcall   Kirim_Perintah  ;
    Mov DPTR,#PesanSetTimer
    Lcall   KirimPesan_LCD
    
    Mov A,#0C3H             ;Tunjuk kolom 3 dan baris 2 LCD
    Lcall   Kirim_Perintah  ;
    Acall   Ambil2DigitKeypad
    Mov Jam,A
    Mov A,#':'
    Lcall   Kirim_Karakter
    Acall   Ambil2DigitKeypad
    Mov Menit,A
    Mov A,#':'
    Lcall   Kirim_Karakter
    Acall   Ambil2DigitKeypad
    Mov Detik,A
    Mov A,#':'
    Lcall   Kirim_Karakter
    Acall   Ambil2DigitKeypad
    Mov Milidetik,A
    Acall   Delay_1detik
    Lcall   Init_LCD
    Mov DPTR,#PesanStartTimer
    Lcall   KirimPesan_LCD
    Ret

PesanStartTimer:
    DB  '  Timer Bekerja',0FH
PesanSetTimer:
    DB  'Atur Timer ',0FH
PesanTimeOut:
    DB  'Timer Selesai',0FH

;Timer 0 diberi nilai DC00H atau -2400H
;Timer 0 akan overflow setiap 2400H atau 9216 hitungan
;Setiap hitungan (cycle) = 12/Nilai Crystal atau 12/11059200
;12/11059200 x 9216 = 10mS
ResetTimer0:
    Mov TH0,#0DCH
    Mov TL0,#00H
    Ret

;Interupsi terjadi setiap 10 mS
;Nilai Waktu ditampilkan di display setiap 10 mS
Timer0_Interrupt:
    Clr ET0
    Push    ACC             ;Simpan nilai-nilai register yg akan digunakan 
    Push    B               ;ke Stack
    Push    PSW         ;
    Push    06H         ;
    Push    00H         ;
    Acall   ResetTimer0

    Dec Milidetik
    Acall   DisplayWaktuLCD
    Mov A,Milidetik
    Jnz KeluarTimer0
    Mov Milidetik,#100

    Mov A,Detik
    Jnz DecDetik
    Mov Detik,#59

CekMenit:
    Mov A,Menit
    Jnz DecMenit
    Mov Menit,#59

CekJam:
    Mov A,Jam
    Jnz DecJam
    Mov A,#82H
    Lcall   Kirim_Perintah
    Mov DPTR,#PesanTimeOut
    Lcall   KirimPesan_LCD
    Clr ET0
    Pop 00H                 ;Ambil nilai-nilai register dari Stack
    Pop 06H             ;
    Pop PSW             ;
    Pop B               ;
    Pop ACC             ;
    Reti

KeluarTimer0:
    Pop 00H                 ;Ambil nilai-nilai register dari Stack
    Pop 06H             ;
    Pop PSW             ;
    Pop B               ;
    Pop ACC             ;
    Setb    ET0
    Reti

DecJam:
    Dec Jam
    Ajmp    KeluarTimer0

DecDetik:
    Dec Detik
    Ajmp    KeluarTimer0

DecMenit:
    Dec Menit
    Ajmp    KeluarTimer0

;BAGIAN PENAMPIL DATA WAKTU KE LCD
DisplayWaktuLCD:
    Mov A,#0C3H                 ;Tunjuk kolom 3, baris 2 dari LCD
    Lcall   Kirim_Perintah      ;
    Mov A,Jam
    Acall   LCDDesimal          ;Ubah data hexa ke Desimal ASCII dan tampil
    Mov A,#':'                  ;ke LCD
    Lcall   Kirim_Karakter
    Mov A,Menit
    Acall   LCDDesimal          ;Ubah Data hexa ke Desimal ASCII dan tampil
    Mov A,#':'                  ;ke LCD
    Lcall   Kirim_Karakter
    Mov A,Detik
    Acall   LCDDesimal          ;Ubah Data hexa ke Desimal ASCII dan tampil
    Mov A,#':'                  ;ke LCD
    Lcall   Kirim_Karakter
    Mov A,Milidetik
    Acall   LCDDesimal          ;Ubah Data hexa ke Desimal ASCII dan tampil
    Ret                         ;ke LCD

; Menampilkan nilai hexa menjadi bentuk desimal ASCII pada LCD
LCDDesimal:
    Mov R0,#TabelDesimal
    Mov TabelDesimal,#00
    Mov TabelDesimal+1,#00
    Lcall   Konversi1bDesimal
    Mov R0,#TabelDesimal+1
    Mov A,@R0
    Add A,#30H
    Lcall   Kirim_karakter
    Dec R0
    Mov A,@R0
    Add A,#30H
    Lcall   Kirim_Karakter
    Ret

;INTERUPSI EXTERNAL 1
;Digunakan untuk mereset waktu Timer
INTR1:
    Clr EA
    Push    B
    Mov B,#0FFH
    Djnz    B,$
    Pop B    
    Acall   ResetWaktu
    Acall   DisplayWaktuLCD
    Jnb INT1,$
    Setb    ET0
    Setb    TR0
    Setb    EA
    Reti
    
;INTERUPSI EXTERNAL 0
;Digunakan untuk mengaktif/non aktifkan waktu Timer
INTR0:
    Clr EA
    Lcall   Init_LCD
    Setb    TR0             ;TR0 diaktifkan kembali karena subroutine InitLCD
    Push    B               ;menggunakan Timer 0 dan menghentikan Timer 0
    Mov B,#0FFH             ;setelah selesai
    Djnz    B,$
    Pop B    
    Cpl ET0
    Jnb INT0,$
    Setb    EA
    Reti

    $Include(HD44780.asm)
    $Include(Delay_1d.asm)
    $Include(HexASCII.asm)
    $Include(Hexdec1b.asm)
    $Include(Keypad.asm)
    $Include(Ambkypd.asm)
    $Include(Tabkey2.asm)

    END