PTM – KEYB

Zadanie 1: Trzy zestawy znaków przełączane klawiszami *, #, D
            ljmp start

P5 equ 0F8H
P7 equ 0DBH
    
LCDstatus  equ 0FF2EH
LCDcontrol equ 0FF2CH
LCDdataWR  equ 0FF2DH

#define  HOME     0x80
#define  INITDISP 0x38
#define  HOM2     0xc0
#define  LCDON    0x0e
#define  CLEAR    0x01

#define LINE_1    0x7f
#define LINE_2    0xbf
#define LINE_3    0xdf
#define LINE_4    0xef

            org 0100H

; ============================================================================
; MAKRA LCD
; ============================================================================
LCDcntrlWR MACRO x
           LOCAL loop
loop:      MOV  DPTR,#LCDstatus
           MOVX A,@DPTR
           JB   ACC.7,loop
           MOV  DPTR,#LCDcontrol
           MOV  A, x
           MOVX @DPTR,A
           ENDM

LCDcharWR MACRO
          LOCAL tutu
          PUSH ACC
tutu:     MOV  DPTR,#LCDstatus
          MOVX A,@DPTR
          JB   ACC.7,tutu
          MOV  DPTR,#LCDdataWR
          POP  ACC
          MOVX @DPTR,A
          ENDM

init_LCD MACRO
         LCDcntrlWR #INITDISP
         LCDcntrlWR #CLEAR
         LCDcntrlWR #LCDON
         ENDM

; ============================================================================
; FUNKCJE
; ============================================================================

delay:      mov r1, #0FFH
dwa:        mov r2, #0FFH
trzy:       djnz r2, trzy
            djnz r1, dwa
            ret

putcharLCD: LCDcharWR
            ret

; ============================================================================
; TABLICA - MALE LITERY (a-m dla klawiszy 0-9, A, B, C)
; ============================================================================
keyascii_lower:
            mov dptr, #80EBH
            mov a, #"a"
            movx @dptr, a
            
            mov dptr, #8077H
            mov a, #"b"
            movx @dptr, a
            
            mov dptr, #807BH
            mov a, #"c"
            movx @dptr, a
            
            mov dptr, #807DH
            mov a, #"d"
            movx @dptr, a
            
            mov dptr, #80B7H
            mov a, #"e"
            movx @dptr, a
            
            mov dptr, #80BBH
            mov a, #"f"
            movx @dptr, a
            
            mov dptr, #80BDH
            mov a, #"g"
            movx @dptr, a
            
            mov dptr, #80D7H
            mov a, #"h"
            movx @dptr, a
            
            mov dptr, #80DBH
            mov a, #"i"
            movx @dptr, a
            
            mov dptr, #80DDH
            mov a, #"j"
            movx @dptr, a
            
            mov dptr, #807EH
            mov a, #"k"
            movx @dptr, a
            
            mov dptr, #80BEH
            mov a, #"l"
            movx @dptr, a
            
            mov dptr, #80DEH
            mov a, #"m"
            movx @dptr, a
            
            ret

; ============================================================================
; TABLICA - DUZE LITERY (A-M)
; ============================================================================
keyascii_upper:
            mov dptr, #80EBH
            mov a, #"A"
            movx @dptr, a
            
            mov dptr, #8077H
            mov a, #"B"
            movx @dptr, a
            
            mov dptr, #807BH
            mov a, #"C"
            movx @dptr, a
            
            mov dptr, #807DH
            mov a, #"D"
            movx @dptr, a
            
            mov dptr, #80B7H
            mov a, #"E"
            movx @dptr, a
            
            mov dptr, #80BBH
            mov a, #"F"
            movx @dptr, a
            
            mov dptr, #80BDH
            mov a, #"G"
            movx @dptr, a
            
            mov dptr, #80D7H
            mov a, #"H"
            movx @dptr, a
            
            mov dptr, #80DBH
            mov a, #"I"
            movx @dptr, a
            
            mov dptr, #80DDH
            mov a, #"J"
            movx @dptr, a
            
            mov dptr, #807EH
            mov a, #"K"
            movx @dptr, a
            
            mov dptr, #80BEH
            mov a, #"L"
            movx @dptr, a
            
            mov dptr, #80DEH
            mov a, #"M"
            movx @dptr, a
            
            ret

; ============================================================================
; TABLICA - CYFRY (0-9, A, B, C)
; ============================================================================
keyascii_num:
            mov dptr, #80EBH
            mov a, #"0"
            movx @dptr, a
            
            mov dptr, #8077H
            mov a, #"1"
            movx @dptr, a
            
            mov dptr, #807BH
            mov a, #"2"
            movx @dptr, a
            
            mov dptr, #807DH
            mov a, #"3"
            movx @dptr, a
            
            mov dptr, #80B7H
            mov a, #"4"
            movx @dptr, a
            
            mov dptr, #80BBH
            mov a, #"5"
            movx @dptr, a
            
            mov dptr, #80BDH
            mov a, #"6"
            movx @dptr, a
            
            mov dptr, #80D7H
            mov a, #"7"
            movx @dptr, a
            
            mov dptr, #80DBH
            mov a, #"8"
            movx @dptr, a
            
            mov dptr, #80DDH
            mov a, #"9"
            movx @dptr, a
            
            mov dptr, #807EH
            mov a, #"A"
            movx @dptr, a
            
            mov dptr, #80BEH
            mov a, #"B"
            movx @dptr, a
            
            mov dptr, #80DEH
            mov a, #"C"
            movx @dptr, a
            
            ret

; ============================================================================
; PROGRAM GLOWNY
; ============================================================================
start:      
            init_LCD
            acall keyascii_lower    ; domyslnie male litery
            
            mov r7, #10H            ; licznik znakow
            mov r6, #01H            ; flaga linii

; ============================================================================
; SPRAWDZANIE POZYCJI NA LCD
; ============================================================================
check_chars:
            mov a, r7
            jz check_line
            jmp key_1
            
check_line: 
            mov a, r6
            jnz set_line2
            
set_line1:  
            LCDcntrlWR #CLEAR
            LCDcntrlWR #HOME
            mov r7, #10H
            mov r6, #01H
            jmp key_1
            
set_line2:  
            LCDcntrlWR #HOM2
            mov r6, #00H
            mov r7, #10H

; ============================================================================
; SKANOWANIE LINII 1
; ============================================================================
key_1:      
            mov r0, #LINE_1
            mov a, r0
            mov P5, a
            mov a, P7
            anl a, r0
            mov r2, a
            clr c
            subb a, r0
            jz key_2
            mov a, r2
            mov dph, #80H
            mov dpl, a
            movx a, @dptr
            mov P1, a
            acall putcharLCD
            acall delay
            dec r7

; ============================================================================
; SKANOWANIE LINII 2
; ============================================================================
key_2:      
            mov r0, #LINE_2
            mov a, r0
            mov P5, a
            mov a, P7
            anl a, r0
            mov r2, a
            clr c
            subb a, r0
            jz key_3
            mov a, r2
            mov dph, #80H
            mov dpl, a
            movx a, @dptr
            mov P1, a
            acall putcharLCD
            acall delay
            dec r7

; ============================================================================
; SKANOWANIE LINII 3
; ============================================================================
key_3:      
            mov r0, #LINE_3
            mov a, r0
            mov P5, a
            mov a, P7
            anl a, r0
            mov r2, a
            clr c
            subb a, r0
            jz key_4
            mov a, r2
            mov dph, #80H
            mov dpl, a
            movx a, @dptr
            mov P1, a
            acall putcharLCD
            acall delay
            dec r7

; ============================================================================
; SKANOWANIE LINII 4 - Z OBSLUGA KLAWISZY SPECJALNYCH
; ============================================================================
key_4:      
            mov r0, #LINE_4
            mov a, r0
            mov P5, a
            mov a, P7
            anl a, r0
            mov r2, a
            clr c
            subb a, r0
            jz jump_check           ; brak klawisza
            
            ; Sprawdz czy * (kod E7H) -> male litery
            mov a, r2
            clr c
            subb a, #0E7H
            jz to_lower
            
            ; Sprawdz czy # (kod EDH) -> duze litery
            mov a, r2
            clr c
            subb a, #0EDH
            jz to_upper
            
            ; Sprawdz czy D (kod EEH) -> cyfry
            mov a, r2
            clr c
            subb a, #0EEH
            jz to_num
            
            ; Normalny klawisz - wyswietl
            mov a, r2
            mov dph, #80H
            mov dpl, a
            movx a, @dptr
            mov P1, a
            acall putcharLCD
            acall delay
            dec r7
            ljmp check_chars

jump_check: 
            ljmp check_chars

; ============================================================================
; PRZELACZANIE ZESTAWOW ZNAKOW
; ============================================================================
to_lower:
            acall keyascii_lower
            acall delay             ; opoznienie zeby nie powtarzac
            ljmp check_chars
            
to_upper:
            acall keyascii_upper
            acall delay
            ljmp check_chars
            
to_num:
            acall keyascii_num
            acall delay
            ljmp check_chars

            nop
            nop
            nop
            jmp $
            end start
Zadanie 2: Wyświetlanie tekstu z klawiatury z przewijaniem
            ljmp start

P5 equ 0F8H
P7 equ 0DBH
    
LCDstatus  equ 0FF2EH
LCDcontrol equ 0FF2CH
LCDdataWR  equ 0FF2DH

#define  HOME     0x80
#define  INITDISP 0x38
#define  HOM2     0xc0
#define  LCDON    0x0e
#define  CLEAR    0x01

#define LINE_1    0x7f
#define LINE_2    0xbf
#define LINE_3    0xdf
#define LINE_4    0xef

            org 0100H

; ============================================================================
; MAKRA LCD
; ============================================================================
LCDcntrlWR MACRO x
           LOCAL loop
loop:      MOV  DPTR,#LCDstatus
           MOVX A,@DPTR
           JB   ACC.7,loop
           MOV  DPTR,#LCDcontrol
           MOV  A, x
           MOVX @DPTR,A
           ENDM

LCDcharWR MACRO
          LOCAL tutu
          PUSH ACC
tutu:     MOV  DPTR,#LCDstatus
          MOVX A,@DPTR
          JB   ACC.7,tutu
          MOV  DPTR,#LCDdataWR
          POP  ACC
          MOVX @DPTR,A
          ENDM

init_LCD MACRO
         LCDcntrlWR #INITDISP
         LCDcntrlWR #CLEAR
         LCDcntrlWR #LCDON
         ENDM

; ============================================================================
; FUNKCJE
; ============================================================================

delay:      mov r1, #0FFH
dwa:        mov r2, #0FFH
trzy:       djnz r2, trzy
            djnz r1, dwa
            ret

putcharLCD: LCDcharWR
            ret

; ============================================================================
; TABLICA PRZEKODOWAN
; ============================================================================
keyascii:   
            mov dptr, #80EBH
            mov a, #"0"
            movx @dptr, a
            
            mov dptr, #8077H
            mov a, #"1"
            movx @dptr, a
            
            mov dptr, #807BH
            mov a, #"2"
            movx @dptr, a
            
            mov dptr, #807DH
            mov a, #"3"
            movx @dptr, a
            
            mov dptr, #80B7H
            mov a, #"4"
            movx @dptr, a
            
            mov dptr, #80BBH
            mov a, #"5"
            movx @dptr, a
            
            mov dptr, #80BDH
            mov a, #"6"
            movx @dptr, a
            
            mov dptr, #80D7H
            mov a, #"7"
            movx @dptr, a
            
            mov dptr, #80DBH
            mov a, #"8"
            movx @dptr, a
            
            mov dptr, #80DDH
            mov a, #"9"
            movx @dptr, a
            
            mov dptr, #807EH
            mov a, #"A"
            movx @dptr, a
            
            mov dptr, #80BEH
            mov a, #"B"
            movx @dptr, a
            
            mov dptr, #80DEH
            mov a, #"C"
            movx @dptr, a
            
            mov dptr, #80EEH
            mov a, #"D"
            movx @dptr, a
            
            mov dptr, #80E7H
            mov a, #"*"
            movx @dptr, a
            
            mov dptr, #80EDH
            mov a, #"#"
            movx @dptr, a
            
            ret

; ============================================================================
; PROGRAM GLOWNY
; ============================================================================
start:      
            init_LCD
            acall keyascii
            
            mov r7, #10H            ; licznik znakow w linii (16)
            mov r6, #01H            ; flaga linii (1=linia1, 0=linia2)

; ============================================================================
; SPRAWDZANIE POZYCJI NA LCD
; ============================================================================
check_chars:
            mov a, r7
            jz check_line
            jmp key_1
            
check_line: 
            mov a, r6
            jnz set_line2
            
set_line1:  
            ; Po 32 znakach - czysc i zacznij od nowa
            LCDcntrlWR #CLEAR
            LCDcntrlWR #HOME
            mov r7, #10H
            mov r6, #01H
            jmp key_1
            
set_line2:  
            ; Po 16 znakach - przejdz do linii 2
            LCDcntrlWR #HOM2
            mov r6, #00H
            mov r7, #10H

; ============================================================================
; SKANOWANIE LINII 1
; ============================================================================
key_1:      
            mov r0, #LINE_1
            mov a, r0
            mov P5, a
            mov a, P7
            anl a, r0
            mov r2, a
            clr c
            subb a, r0
            jz key_2
            mov a, r2
            mov dph, #80H
            mov dpl, a
            movx a, @dptr
            mov P1, a
            acall putcharLCD
            acall delay
            dec r7

; ============================================================================
; SKANOWANIE LINII 2
; ============================================================================
key_2:      
            mov r0, #LINE_2
            mov a, r0
            mov P5, a
            mov a, P7
            anl a, r0
            mov r2, a
            clr c
            subb a, r0
            jz key_3
            mov a, r2
            mov dph, #80H
            mov dpl, a
            movx a, @dptr
            mov P1, a
            acall putcharLCD
            acall delay
            dec r7

; ============================================================================
; SKANOWANIE LINII 3
; ============================================================================
key_3:      
            mov r0, #LINE_3
            mov a, r0
            mov P5, a
            mov a, P7
            anl a, r0
            mov r2, a
            clr c
            subb a, r0
            jz key_4
            mov a, r2
            mov dph, #80H
            mov dpl, a
            movx a, @dptr
            mov P1, a
            acall putcharLCD
            acall delay
            dec r7

; ============================================================================
; SKANOWANIE LINII 4
; ============================================================================
key_4:      
            mov r0, #LINE_4
            mov a, r0
            mov P5, a
            mov a, P7
            anl a, r0
            mov r2, a
            clr c
            subb a, r0
            jz jump_check
            mov a, r2
            mov dph, #80H
            mov dpl, a
            movx a, @dptr
            mov P1, a
            acall putcharLCD
            acall delay
            dec r7
            ljmp check_chars

jump_check: 
            ljmp check_chars

            nop
            nop
            nop
            jmp $
            end start
Zadanie 3: Wyłączenie repetycji klawisza
ljmp start

P5 equ 0F8H
P7 equ 0DBH
    
LCDstatus  equ 0FF2EH
LCDcontrol equ 0FF2CH
LCDdataWR  equ 0FF2DH

#define  HOME     0x80
#define  INITDISP 0x38
#define  HOM2     0xc0
#define  LCDON    0x0e
#define  CLEAR    0x01

#define LINE_1    0x7f
#define LINE_2    0xbf
#define LINE_3    0xdf
#define LINE_4    0xef

            org 0100H

; ============================================================================
; MAKRA LCD
; ============================================================================
LCDcntrlWR MACRO x
           LOCAL loop
loop:      MOV  DPTR,#LCDstatus
           MOVX A,@DPTR
           JB   ACC.7,loop
           MOV  DPTR,#LCDcontrol
           MOV  A, x
           MOVX @DPTR,A
           ENDM

LCDcharWR MACRO
          LOCAL tutu
          PUSH ACC
tutu:     MOV  DPTR,#LCDstatus
          MOVX A,@DPTR
          JB   ACC.7,tutu
          MOV  DPTR,#LCDdataWR
          POP  ACC
          MOVX @DPTR,A
          ENDM

init_LCD MACRO
         LCDcntrlWR #INITDISP
         LCDcntrlWR #CLEAR
         LCDcntrlWR #LCDON
         ENDM

; ============================================================================
; FUNKCJE POMOCNICZE
; ============================================================================

delay:      mov r1, #0FFH
dwa:        mov r2, #0FFH
trzy:       djnz r2, trzy
            djnz r1, dwa
            ret

putcharLCD: LCDcharWR
            ret

; ============================================================================
; TABLICE PRZEKODOWANIA (Mapowanie kodów klawiatury na ASCII w XRAM)
; ============================================================================
keyascii_lower:
            mov dptr, #80EBH
            mov a, #"a"
            movx @dptr, a
            mov dptr, #8077H
            mov a, #"b"
            movx @dptr, a
            mov dptr, #807BH
            mov a, #"c"
            movx @dptr, a
            mov dptr, #807DH
            mov a, #"d"
            movx @dptr, a
            mov dptr, #80B7H
            mov a, #"e"
            movx @dptr, a
            mov dptr, #80BBH
            mov a, #"f"
            movx @dptr, a
            mov dptr, #80BDH
            mov a, #"g"
            movx @dptr, a
            mov dptr, #80D7H
            mov a, #"h"
            movx @dptr, a
            mov dptr, #80DBH
            mov a, #"i"
            movx @dptr, a
            mov dptr, #80DDH
            mov a, #"j"
            movx @dptr, a
            mov dptr, #807EH
            mov a, #"k"
            movx @dptr, a
            mov dptr, #80BEH
            mov a, #"l"
            movx @dptr, a
            mov dptr, #80DEH
            mov a, #"m"
            movx @dptr, a
            ret

keyascii_upper:
            mov dptr, #80EBH
            mov a, #"A"
            movx @dptr, a
            mov dptr, #8077H
            mov a, #"B"
            movx @dptr, a
            mov dptr, #807BH
            mov a, #"C"
            movx @dptr, a
            mov dptr, #807DH
            mov a, #"D"
            movx @dptr, a
            mov dptr, #80B7H
            mov a, #"E"
            movx @dptr, a
            mov dptr, #80BBH
            mov a, #"F"
            movx @dptr, a
            mov dptr, #80BDH
            mov a, #"G"
            movx @dptr, a
            mov dptr, #80D7H
            mov a, #"H"
            movx @dptr, a
            mov dptr, #80DBH
            mov a, #"I"
            movx @dptr, a
            mov dptr, #80DDH
            mov a, #"J"
            movx @dptr, a
            mov dptr, #807EH
            mov a, #"K"
            movx @dptr, a
            mov dptr, #80BEH
            mov a, #"L"
            movx @dptr, a
            mov dptr, #80DEH
            mov a, #"M"
            movx @dptr, a
            ret

keyascii_num:
            mov dptr, #80EBH
            mov a, #"0"
            movx @dptr, a
            mov dptr, #8077H
            mov a, #"1"
            movx @dptr, a
            mov dptr, #807BH
            mov a, #"2"
            movx @dptr, a
            mov dptr, #807DH
            mov a, #"3"
            movx @dptr, a
            mov dptr, #80B7H
            mov a, #"4"
            movx @dptr, a
            mov dptr, #80BBH
            mov a, #"5"
            movx @dptr, a
            mov dptr, #80BDH
            mov a, #"6"
            movx @dptr, a
            mov dptr, #80D7H
            mov a, #"7"
            movx @dptr, a
            mov dptr, #80DBH
            mov a, #"8"
            movx @dptr, a
            mov dptr, #80DDH
            mov a, #"9"
            movx @dptr, a
            mov dptr, #807EH
            mov a, #"A"
            movx @dptr, a
            mov dptr, #80BEH
            mov a, #"B"
            movx @dptr, a
            mov dptr, #80DEH
            mov a, #"C"
            movx @dptr, a
            ret

; ============================================================================
; PROGRAM GŁÓWNY
; ============================================================================
start:      
            init_LCD
            acall keyascii_lower    ; Domyślnie małe litery
            
            mov r5, #0              ; R5: Przechowuje ostatnio wciśnięty klawisz (anti-repetycja)
            mov r7, #10H            ; R7: Licznik znaków w linii
            mov r6, #01H            ; R6: Flaga aktualnej linii (1 lub 0)

; ============================================================================
; LOGIKA PRZEŁĄCZANIA LINII LCD
; ============================================================================
check_chars:
            mov a, r7
            jnz scan_start          ; Jeśli r7 > 0, skanuj klawisze
            
            ; Jeśli linia się skończyła:
            mov a, r6
            jnz set_line2           ; Jeśli była linia 1, idź do 2
            
set_line1:  
            LCDcntrlWR #CLEAR
            LCDcntrlWR #HOME
            mov r7, #10H
            mov r6, #01H
            jmp scan_start
            
set_line2:  
            LCDcntrlWR #HOM2
            mov r6, #00H
            mov r7, #10H

; ============================================================================
; SKANOWANIE KLAWIATURY (Debouncing & Anti-repetition)
; ============================================================================
scan_start:
            ; Skanowanie wszystkich linii po kolei
            
            ; --- Linia 1 ---
            mov r0, #LINE_1
            acall scan_line
            jnz key_found           ; Jeśli A != 0, znaleziono klawisz
            
            ; --- Linia 2 ---
            mov r0, #LINE_2
            acall scan_line
            jnz key_found
            
            ; --- Linia 3 ---
            mov r0, #LINE_3
            acall scan_line
            jnz key_found
            
            ; --- Linia 4 ---
            mov r0, #LINE_4
            acall scan_line
            jnz key_found
            
            ; Brak wciśniętego klawisza
            mov r5, #0              ; Resetujemy pamięć poprzedniego klawisza
            ljmp check_chars

; Podfunkcja skanująca konkretną linię (R0)
; Zwraca w akumulatorze kod klawisza lub 0
scan_line:
            mov a, r0
            mov P5, a               ; Ustaw linię skanowania
            mov a, P7
            anl a, r0               ; Odczytaj stan
            mov r2, a               ; R2 = aktualny stan pinów
            clr c
            subb a, r0
            jz no_key_in_line       ; Jeśli wynik 0, nic nie wciśnięto
            
            ; Sprawdzenie anti-repetycji (czy to ten sam klawisz co przed chwilą?)
            mov a, r2
            clr c
            subb a, r5
            jz no_key_in_line       ; Ten sam klawisz - zignoruj
            
            ; Debouncing (krótkie opóźnienie i ponowne sprawdzenie)
            acall delay_short
            mov a, P7
            anl a, r0
            mov r2, a
            clr c
            subb a, r0
            jz no_key_in_line       ; Drgania styków - fałszywy alarm
            
            mov a, r2               ; Zwróć kod klawisza
            ret
no_key_in_line:
            mov a, #0
            ret

delay_short: mov r3, #50H           ; Krótkie opóźnienie dla debouncingu
             djnz r3, $
             ret

; ============================================================================
; OBSŁUGA ZNALEZIONEGO KLAWISZA
; ============================================================================
key_found:
            mov r5, a               ; Zapamiętaj klawisz w R5 (blokada powtórzeń)
            mov r2, a               ; R2 = kod klawisza do analizy
            
            ; 1. Sprawdź funkcje specjalne (Linia 4)
            ; * (E7H) -> małe litery
            cjne a, #0E7H, check_upper
            acall keyascii_lower
            ljmp check_chars

check_upper:
            ; # (EDH) -> duże litery
            mov a, r2
            cjne a, #0EDH, check_num
            acall keyascii_upper
            ljmp check_chars

check_num:
            ; D (EEH) -> cyfry
            mov a, r2
            cjne a, #0EEH, print_normal
            acall keyascii_num
            ljmp check_chars

print_normal:
            ; 2. Wyświetl standardowy znak
            mov a, r2
            mov dph, #80H
            mov dpl, a
            movx a, @dptr           ; Pobierz mapowanie ASCII
            mov P1, a               ; Diagnostyka na LED
            acall putcharLCD        ; Wyślij na LCD
            dec r7                  ; Zmniejsz licznik znaków w linii
	    acall delay
	    acall delay
	    acall delay
	    acall delay
            ljmp check_chars

            nop
            jmp $
            end start
BONUS: Kalkulator prosty (dodawanie dwóch cyfr)
            ljmp start

P5          equ 0F8H
P7          equ 0DBH

LCDstatus   equ 0FF2EH
LCDcontrol  equ 0FF2CH
LCDdataWR   equ 0FF2DH

#define  HOME     0x80
#define  INITDISP 0x38
#define  HOM2     0xc0
#define  LCDON    0x0e
#define  CLEAR    0x01

#define LINE_1    0x7f
#define LINE_2    0xbf
#define LINE_3    0xdf
#define LINE_4    0xef

; zmienne w RAM
key_state   equ 30H
last_scan   equ 31H
num1        equ 32H         ; pierwsza liczba (0-9)
num2        equ 33H         ; druga liczba (0-9)
result      equ 34H         ; wynik
calc_state  equ 35H         ; stan kalkulatora: 0=czekaj na num1, 1=czekaj na num2, 2=pokaz wynik

            org 0100H

; ============================================================================
; MAKRA LCD
; ============================================================================
LCDcntrlWR MACRO x
           LOCAL loop
loop:      MOV  DPTR,#LCDstatus
           MOVX A,@DPTR
           JB   ACC.7,loop
           MOV  DPTR,#LCDcontrol
           MOV  A, x
           MOVX @DPTR,A
           ENDM

LCDcharWR MACRO
          LOCAL tutu
          PUSH ACC
tutu:     MOV  DPTR,#LCDstatus
          MOVX A,@DPTR
          JB   ACC.7,tutu
          MOV  DPTR,#LCDdataWR
          POP  ACC
          MOVX @DPTR,A
          ENDM

init_LCD MACRO
         LCDcntrlWR #INITDISP
         LCDcntrlWR #CLEAR
         LCDcntrlWR #LCDON
         ENDM

; ============================================================================
; DANE - komunikaty
; ============================================================================
msg_calc:   db "KALKULATOR +",0
msg_num1:   db "Podaj 1 liczbe:",0
msg_num2:   db "Podaj 2 liczbe:",0
msg_result: db "Wynik: ",0
msg_clear:  db "* = RESET",0

; ============================================================================
; TABLICA PRZEKODOWAN (tylko cyfry 0-9)
; ============================================================================
init_keys:
            mov dptr, #80EBH
            mov a, #0               ; '0' -> wartosc 0
            movx @dptr, a
            mov dptr, #8077H
            mov a, #1               ; '1' -> wartosc 1
            movx @dptr, a
            mov dptr, #807BH
            mov a, #2
            movx @dptr, a
            mov dptr, #807DH
            mov a, #3
            movx @dptr, a
            mov dptr, #80B7H
            mov a, #4
            movx @dptr, a
            mov dptr, #80BBH
            mov a, #5
            movx @dptr, a
            mov dptr, #80BDH
            mov a, #6
            movx @dptr, a
            mov dptr, #80D7H
            mov a, #7
            movx @dptr, a
            mov dptr, #80DBH
            mov a, #8
            movx @dptr, a
            mov dptr, #80DDH
            mov a, #9
            movx @dptr, a
            ; Klawisze specjalne
            mov dptr, #80E7H        ; '*' = reset
            mov a, #0FEH
            movx @dptr, a
            mov dptr, #80EDH        ; '#' = oblicz
            mov a, #0FDH
            movx @dptr, a
            ret

; ============================================================================
; FUNKCJE POMOCNICZE
; ============================================================================

delay:      mov r0, #10H
d_one:      mov r1, #0FFH
d_two:      mov r2, #0FFH
d_three:    djnz r2, d_three
            djnz r1, d_two
            djnz r0, d_one
            ret

delay_short:
            mov r0, #03H
ds_one:     mov r1, #0FFH
ds_two:     djnz r1, ds_two
            djnz r0, ds_one
            ret

putcharLCD: LCDcharWR
            ret

; Wyswietl string z pamieci programu
putstrLCD:  clr a
            movc a, @a+dptr
            jz ps_end
            push dph
            push dpl
            acall putcharLCD
            pop dpl
            pop dph
            inc dptr
            sjmp putstrLCD
ps_end:     ret

; Wyswietl cyfre (0-9) na LCD
show_digit:
            add a, #'0'             ; konwersja na ASCII
            acall putcharLCD
            ret

; Wyswietl liczbe dwucyfrowa (0-18)
show_number:
            mov b, #10
            div ab                  ; A = dziesiatki, B = jednosci
            jz only_units           ; jesli dziesiatki = 0, pokaz tylko jednosci
            add a, #'0'
            acall putcharLCD
only_units:
            mov a, b
            add a, #'0'
            acall putcharLCD
            ret

; ============================================================================
; SKANOWANIE KLAWIATURY Z ANTI-REPETYCJA
; ============================================================================
scan_keyboard:
            mov a, #LINE_1
            mov P5, a
            mov a, P7
            anl a, #0FH
            cjne a, #0FH, sk_l1
            
            mov a, #LINE_2
            mov P5, a
            mov a, P7
            anl a, #0FH
            cjne a, #0FH, sk_l2
            
            mov a, #LINE_3
            mov P5, a
            mov a, P7
            anl a, #0FH
            cjne a, #0FH, sk_l3
            
            mov a, #LINE_4
            mov P5, a
            mov a, P7
            anl a, #0FH
            cjne a, #0FH, sk_l4
            
            mov a, #0FFH
            ret

sk_l1:      orl a, #LINE_1
            ret
sk_l2:      orl a, #LINE_2
            ret
sk_l3:      orl a, #LINE_3
            ret
sk_l4:      orl a, #LINE_4
            ret

get_key:
            acall scan_keyboard
            mov r4, a
            
            mov a, key_state
            jnz gk_pressed

gk_released:
            mov a, r4
            cjne a, #0FFH, gk_just_pressed
            mov a, #0FFH
            ret

gk_just_pressed:
            acall delay_short
            mov last_scan, r4
            mov key_state, #1
            mov a, #0FFH
            ret

gk_pressed:
            mov a, r4
            cjne a, #0FFH, gk_still
            acall delay_short
            mov key_state, #0
            mov a, last_scan
            mov dph, #80H
            mov dpl, a
            movx a, @dptr
            ret

gk_still:   mov a, #0FFH
            ret

; ============================================================================
; FUNKCJA RESETU KALKULATORA
; ============================================================================
reset_calc:
            mov calc_state, #0
            mov num1, #0
            mov num2, #0
            mov result, #0
            
            LCDcntrlWR #CLEAR
            LCDcntrlWR #HOME
            mov dptr, #msg_calc
            acall putstrLCD
            
            LCDcntrlWR #HOM2
            mov dptr, #msg_num1
            acall putstrLCD
            ret

; ============================================================================
; PROGRAM GLOWNY
; ============================================================================
start:
            init_LCD
            acall init_keys
            
            mov key_state, #0
            acall reset_calc

; ============================================================================
; GLOWNA PETLA KALKULATORA
; ============================================================================
main_loop:
            acall get_key
            cjne a, #0FFH, process_input
            sjmp main_loop

process_input:
            ; Sprawdz czy to reset (*)
            cjne a, #0FEH, chk_equals
            acall reset_calc
            sjmp main_loop

chk_equals:
            ; Sprawdz czy to oblicz (#)
            cjne a, #0FDH, chk_digit
            ; Oblicz wynik jesli mamy obie liczby
            mov r5, a
            mov a, calc_state
            cjne a, #1, main_loop   ; musimy byc w stanie 1
            
            ; Oblicz sume
            mov a, num1
            add a, num2
            mov result, a
            
            ; Wyswietl wynik
            LCDcntrlWR #CLEAR
            LCDcntrlWR #HOME
            mov a, num1
            acall show_digit
            mov a, #'+'
            acall putcharLCD
            mov a, num2
            acall show_digit
            mov a, #'='
            acall putcharLCD
            mov a, result
            acall show_number
            
            LCDcntrlWR #HOM2
            mov dptr, #msg_clear
            acall putstrLCD
            
            mov calc_state, #2
            sjmp main_loop

chk_digit:
            ; To musi byc cyfra (0-9)
            mov r5, a               ; wartosc cyfry
            
            ; Sprawdz w jakim jestesmy stanie
            mov a, calc_state
            cjne a, #0, state1
            
            ; Stan 0: czekamy na pierwsza liczbe
            mov num1, r5
            
            ; Wyswietl na LCD
            LCDcntrlWR #CLEAR
            LCDcntrlWR #HOME
            mov a, num1
            acall show_digit
            mov a, #' '
            acall putcharLCD
            mov a, #'+'
            acall putcharLCD
            mov a, #' '
            acall putcharLCD
            mov a, #'?'
            acall putcharLCD
            
            LCDcntrlWR #HOM2
            mov dptr, #msg_num2
            acall putstrLCD
            
            mov calc_state, #1
            sjmp main_loop

state1:
            cjne a, #1, state2
            
            ; Stan 1: czekamy na druga liczbe
            mov num2, r5
            
            ; Wyswietl na LCD
            LCDcntrlWR #CLEAR
            LCDcntrlWR #HOME
            mov a, num1
            acall show_digit
            mov a, #' '
            acall putcharLCD
            mov a, #'+'
            acall putcharLCD
            mov a, #' '
            acall putcharLCD
            mov a, num2
            acall show_digit
            
            LCDcntrlWR #HOM2
            mov a, #'#'
            acall putcharLCD
            mov a, #'='
            acall putcharLCD
            mov a, #'O'
            acall putcharLCD
            mov a, #'B'
            acall putcharLCD
            mov a, #'L'
            acall putcharLCD
            mov a, #'I'
            acall putcharLCD
            mov a, #'C'
            acall putcharLCD
            mov a, #'Z'
            acall putcharLCD
            
            sjmp main_loop

state2:
            ; Stan 2: wynik wyswietlony, czekamy na reset
            sjmp main_loop

            nop
            nop
            nop
            jmp $
            end start

https://github.com/Ite-2022-pwr/sem4-ptm1-lab-ak-mb/tree/master/lab4