;lab7 註解修改版,尚未實際跑過,若有註解或修改錯誤請回到v2.0或者v1.0
;(v1.0已經通過檢查)
;2008/05/11 BY Duran
;將鍵盤外部中斷,改成每格一段時間是檢查按鍵是否被按
;2CH和2DH預設紀錄計時器狀態,這個程式沒有用到,可以省略
;2EH放置舊的按鍵檢查狀態,#00H表示按鍵沒按狀態,#01H表示按鍵被按住狀態
;前面DISPLAY和大部份功能不做註解,詳情到LAB6程式有註解
;此版本只保留a鍵和b鍵功能
;去彈跳尚未完成

ORG 00H
JMP START
ORG 0BH ;計時器#0的中斷向量地址
JMP TIMER0 ;執行內部中斷#0的中斷服務程式

ORG 30H
START:
MOV SP,#50H ;設定堆疊指標
MOV R0,#20H ;R0用來放置七段位置,先放入#20H,在用@轉換記憶體位置

INIT:
MOV @R0,#00H ;清除顯示暫存器
INC R0
CJNE R0,#34H,INIT

MOV 2CH,#00H
MOV 2DH,#00H

MOV 35H,#01H ;35H 7seg-select
MOV R3,#01H ;;;;;;;利用R3做計數器 #01H =第一組數字 #02H = 第二組數字 ;可能需要初始化記憶體位置
CLR A


;;;;;;;;計時器;;;;;;;

MOV TMOD,#00H ;使用計時器#0的工作模式為#0
MOV IE,#82H ;設定外部中斷#0的致能旗標(EA=1、ET0=1)
MOV TL0,#00H ;設定計時器#0的暫存器初值
MOV TH0,#0C0H
SETB TR0

DISPLAY: ;顯示數值
MOV R1,35H

MOV A,20H
ANL A,#0F0H
SWAP A
CALL SET_P
ORL A,#70H
MOV P0,A
CALL DELAY
MOV A,20H
ANL A,#0FH
CALL SET_P
ORL A,#60H
MOV P0,A
CALL DELAY

MOV P2,#7FH ;掃描鍵盤第一列

MOV A,21H
ANL A,#0F0H
SWAP A
CALL SET_P
ORL A,#50H
MOV P0,A
CALL DELAY
MOV A,21H
ANL A,#0FH
CALL SET_P
ORL A,#40H
MOV P0,A
CALL DELAY

MOV P2,#0BFH ;掃描鍵盤第二列

MOV A,22H
ANL A,#0F0H
SWAP A
CALL SET_P
ORL A,#30H
MOV P0,A
CALL DELAY
MOV A,22H
ANL A,#0FH
CALL SET_P
ORL A,#20H
MOV P0,A
CALL DELAY

MOV P2,#0DFH ;掃描鍵盤第三列

MOV A,23H
ANL A,#0F0H
SWAP A
CALL SET_P
ORL A,#10H
MOV P0,A
CALL DELAY
MOV A,23H
ANL A,#0FH
CALL SET_P
ORL A,#00H
MOV P0,A
CALL DELAY

MOV P2,#0EFH ;掃描鍵盤第四列

JMP DISPLAY

SET_P:
XCH A,R1
RRC A
XCH A,R1
JC set_B
ORL A,#80H
set_B:
RET


TIMER0:
MOV TL0,#00H ;重設計時器#0的暫存器初值
MOV TH0,#0C0H
PUSH ACC ;存入累加器資訊

;;;;;;;;;第一層增加時間回圈沒用到;;;;;
; MOV A,2CH
; INC A
; MOV 2CH,A
; CJNE A,#0F0H,NOCHANGE1
;;;;;;;;;第一層增加時間回圈沒用到;;;;;


;;;計時時間到,做偵測P2內容;;;
MOV A,P2 ;取得鍵盤狀態的資料
MOV B,A ;暫存到 B 暫存器
MOV DPTR,#KEY_TABLE ;比對電氣表
MOV R2,#00H ;初始化R2,R2紀錄按什麼按鍵(電氣表to數字)

WRONG1:
MOV A,R2
MOVC A,@A+DPTR
XRL A,B
JZ RIGHT1 ;對了,跳到RIGHT
INC R2 ;錯了,累加R2
CJNE R2,#10H,WRONG1 ;偵測16個按鈕,如果第17個按鈕都不對,則跳到KEY2

;;;;R2內容都不對,則改變記憶體內容,回去繼續跑(等於沒按00,或者放開10,所以把2EH放入#00H)
MOV 2EH,#00H

;;;;2CH 2DH沒用到,可以不管
MOV 2CH,#00H
MOV 2DH,#00H
POP ACC
RETI


RIGHT1:
;代表有按(11)或者(01),如果11則回去;01則做按鍵內容
MOV A,2EH
CJNE A,#00H,do_key_a ;取出目前鍵盤狀態,如果狀態沒按,跳鍵盤a,否則結束計時器

;;;;2CH 2DH沒用到,可以不管
MOV 2CH,#00H
MOV 2DH,#00H

POP Acc
RETI

do_key_a:
CJNE R2,#0aH,do_key_b ;不相等跳do_key_b,相等執行下一行(按A)
MOV A,35H ;讀入35H資料
RL A ;左移位數
MOV 35H,A ;放回記憶體位置
JMP KEY2 ;跳到KEY2;就是結束

do_key_b:
CJNE R2,#0bH,do_key_c ;倘若不是按到B,則跳do_key_c

;做旗標切換 ;這段做兩個記憶體位置切換
DJNZ R3,LOOP3
MOV 24H,20H
MOV 25H,21H
MOV 26H,22H
MOV 27H,23H

MOV 20H,28H
MOV 21H,29H
MOV 22H,2AH
MOV 23H,2BH

MOV R3,#02H

MOV 35H,#01H ;回到第一位
JMP KEY2 ;跳到KEY2;就是結束

LOOP3:


MOV 28H,20H
MOV 29H,21H
MOV 2AH,22H
MOV 2BH,23H

MOV 20H,24H
MOV 21H,25H
MOV 22H,26H
MOV 23H,27H

MOV R3,#01H

MOV 35H,#01H ;回到第一位
JMP KEY2 ;跳到KEY2;就是結束

do_key_c: ;clear to 0
CJNE R2,#0cH,do_key_d ;若不是按C 則跳D
JMP KEY2

do_key_d:
CJNE R2,#0dH,do_key_e ;若不是按D則跳E
JMP KEY2

do_key_e:
CJNE R2,#0eH,do_key_f ;若不是E 則跳F
JMP KEY2 ;結束


do_key_f: ;清除所有資料
CJNE R2,#0eH,do_key_num
JMP KEY2

do_key_num: ;應該0-9數字讀入與判斷 ;123錯誤

MOV A,35H
MOV R0,#20H
R_C:
RRC A
JC W_B
RRC A
JC W_B2
INC R0
SJMP R_C
W_B:
MOV A,@R0
ANL A,#0FH
SWAP A
ORL A,R2
SWAP A
MOV @R0,A
JMP KEY2
W_B2:
MOV A,@R0
ANL A,#0F0H
ORL A,R2
MOV @R0,A

KEY2:
MOV 2EH,#01H
MOV 2CH,#00H
MOV 2DH,#00H
POP Acc
RETI


;沒用到,這段是用來增加檢查時間
NOCHANGE1:
MOV 2EH,#00H
POP ACC
RETI
;鍵盤掃描廷遲時間副程式
DELAY:
MOV R6,#06H
D1:
MOV R7,#00H
DJNZ R7,$
DJNZ R6,D1
RET
;鍵盤去彈跳副程式
DELAY_K:
MOV R5,#40H
D2: CALL DELAY
DJNZ R5,D2
RET

;鍵盤電氣狀態表
KEY_TABLE:
DB 7EH ;0
DB 7DH ;1
DB 0BDH ;2
DB 0DDH ;3
DB 7BH ;4
DB 0BBH ;5
DB 0DBH ;6
DB 77H ;7
DB 0B7H ;8
DB 0D7H ;9
DB 0BEH ;A
DB 0DEH ;B
DB 0E7H ;C
DB 0EBH ;D
DB 0EDH ;E
DB 0EEH ;F
END