;目的:藉由按鍵輸入來改變七斷顯示器的內容,共有兩個資料儲存,其功能如下:
;註解版如編譯錯誤,請通知敝人拿取原版
;a sel-7seg
;b write back and change next number data
;c nothing
;d nothing
;e nothing
;f 歸零
;被選擇的七斷顯示器會出現小數點


ORG 00H ;起始位置
JMP START
ORG 13H ;外部中斷#1服務地址
JMP KEY_IP

ORG 30H
START:
MOV SP,#50H ;設定堆疊指標
MOV R0,#20H
INIT:
MOV @R0,#00H ;清除顯示暫存器
INC R0 ;將R0暫存器+1
CJNE R0,#34H,INIT ;RO !=#34H 則跳到INIT,否則執行下一指令
MOV 35H,#01H ;35H 7seg-select
MOV R3,#01H
;利用R3做計數器 #01H =第一組數字 #02H = 第二組數字 ;可能需要初始化記憶體位置
CLR A ;A清除為0
MOV IE,#84H ;致能外部中斷#1產生中斷

DISPLAY: ;顯示數值
MOV R1,35H ;將記憶體位址35H內容放入R1暫存器

MOV A,20H ;將記憶體位置20H放入暫存器A
ANL A,#0F0H ;取得前四位元內容
SWAP A ;將A暫存器內容前後四位元掉換
CALL SET_P ;呼叫SET_P
ORL A,#70H ;讓他亮在七斷顯示器最左邊(就是第8個七斷顯示器顯示)
MOV P0,A ;顯示
CALL DELAY
MOV A,20H ;將記憶體位置20H放入暫存器A
ANL A,#0FH ;取得後四位元
CALL SET_P ;呼叫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 ;累加器A與R1內容互換
RRC A ;將A內容往右旋轉一位
XCH A,R1 ;累加器A與R1內容互換(上面三步在把R1內容向右推);
JC set_B ;如果C=1,跳到set_B ,否則執行下個指令;
ORL A,#80H ;否則將最左邊BIT設定為1 ,意思是說選到的那顆七段顯示器會有多一個點
set_B:
RET ;回去

;中斷開始
KEY_IP:
PUSH Acc
CLR EX1 ;外部中斷源#1除能
MOV A,P2 ;取得鍵盤狀態的資料
MOV B,A ;暫存到 B 暫存器
MOV DPTR,#KEY_TABLE ;取得電器表狀態
MOV R2,#00H ;設定R2=#00H,清除R2內容
WRONG: ;這段在比對電氣表
MOV A,R2
MOVC A,@A+DPTR ;電氣表內容放入A
XRL A,B ;比對
JZ RIGHT ;比對成功,跳到RIGHT
INC R2 ;不成功,R2+1
CJNE R2,#10H,WRONG ;比對錯誤,當作沒看到
JMP KEY2

RIGHT: ;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

;做旗標切換
;作記憶體內容互換 ;一組存在24H~27H,另依組存在28H~2BH
DJNZ R3,LOOP3 ;判斷現在是顯示哪個記憶體位的資料;R3=#01H執行下面 R3=#02H執行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 ;設定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 ;設定R3=#01H

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



do_key_c:
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
MOV 20H,#00H
MOV 21H,#00H
MOV 22H,#00H
MOV 23H,#00H
JMP KEY2


;;;;;;;;;;;;;;;;這裡很難懂(這段不是我寫的,引用古人的程式);;;;;;;;;;;;;;;;
;因為35H初始設定為#01H,每按一下選擇就向左旋轉一位
;在這裡判斷是不斷的把35H中的內容不斷向右邊移動,假如旋轉到C=1,則存入該記憶體位置
;假若C=0則選擇下一個記憶體位置(就是R0+1),繼續向右旋轉
;直到抓取現在選擇的七斷顯示器之位置
;(寫這判斷的人邏輯真厲害,居然用旋轉與CARRYFLAG來判斷選擇哪個七斷顯示器)
;35H內存的並非選擇位置,而是判斷變數,位置反而跟變數相反(最左邊的變數是最右邊的七斷顯示器)

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

MOV A,35H ;放入現在所指七段顯示器位址
MOV R0,#20H ;R0放入#20H
R_C:
RRC A ;將A向右旋轉
JC W_B ;C=1則跳W_B
RRC A ;將A向右旋轉
JC W_B2 ;C=1則跳W_B2
INC R0 ;將R0+1
SJMP R_C ;跳到R_C;這裡應該是判斷取記憶體位置前四位元或者後四位元
W_B: ;這裡是取記憶體前4 BIT的資料(奇數七段顯示器內容1.3.5.7)
MOV A,@R0 ;R0資料變成記憶體地址放入A
ANL A,#0FH ;取得後四位元,顯示的位置,放入累加器A中
SWAP A ;前後四位元交換
ORL A,R2 ;將R2放入後四位元
SWAP A ;前後四位元交換
MOV @R0,A ;將資料寫回記憶位置
JMP KEY2
W_B2: ;這裡是取記憶體後4 BIT的資料(偶數七段顯示器內容0.2.4.6)
MOV A,@R0 ;R0資料變成記憶體地址放入A
ANL A,#0F0H ;取得後四位元,顯示的位置,放入累加器A中
ORL A,R2 ;將R2放入後四位元
MOV @R0,A ;將資料寫回記憶位置

;;;;;;;;;;;;;;;;這裡很難懂(這段不是我寫的,引用古人的程式);;;;;;;;;;;;;;;;


KEY2: ;去彈跳
JB P3.3,KEY0
CALL DELAY_K
JMP KEY2
KEY0:
SETB EX1 ;外部中斷源#1致能
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 7FH ;1
DB 0BFH;2
DB 0DFH;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 0EFH;E
DB 0EEH;F
END