?? pcf8574key20.asm
字號:
;PCF8574KEY20.ASM 20鍵掃描加6位數碼顯示的實驗程序B:
;R1,存放掃描行的鍵值:各行首鍵的值分別為 #0,#4,#8,#12 (共有四行)
;R2,存放PB口送掃描的數。
;R5,存放掃描列的鍵值: #0,#1,#2,#3 (共有四列)
$include(c8051f020.inc)
SLA1W EQU 70H ;PCF8574 A片寫的節點地址(可選地址開關:000H)
SLA1R EQU 71H ;PCF8574 A片讀的節點地址
SLA2W EQU 72H ;PCF8574 B片寫的節點地址 (可選地址開關:001H )
SLA2R EQU 73H ;PCF8574 B片讀的節點地址
SLA3W EQU 76H ;PCF8574 C片寫的節點地址 (可選地址開關:011H)
SLA3R EQU 77H ;PCF8574 C片讀的節點地址
SLA EQU 60H
SLAW EQU 62H
SLAR EQU 63H
NUMBYT EQU 61H ;被傳送的字節數存放單元
MTD EQU 20H ;發送數據緩沖區首地址
MRD EQU 30H ;接收字節緩沖區首地址
VSCL EQU P0.1 ;模擬I2C總線時鐘線
VSDA EQU P0.0 ;模擬I2C總線數據線
ORG 0
AJMP BEGIN
ORG 30H
BEGIN: ACALL INIT ;初始化,將顯示緩沖區(71H~76H)全置#0FFH(非數據)
ACALL INITA ;作為輸入用的芯片PCF8574A(U1)應先將口鎖存器置為高電平
MAIN: MOV WDTCN,#0DEH ;禁止看門狗定時器
MOV WDTCN,#0ADH;
MOV XBR2,#40H ;C8051F交叉開關使能
ACALL INITA ;作為輸入用的芯片應先初始化
LCALL KEY0 ;查詢功能鍵F1(PA4),F2(PA5),F3(PA6),F4(PA7)是否按下?
ACALL KEY20 ;調用判鍵子程序(針對小鍵盤上的20個鍵),查詢是否有鍵按下?
ACALL DISP ;調用顯示子程序,動態顯示71H~76H中的值
MOV A,6CH ;處理四個功能鍵(F1,F2,F3,F4)的子程序。功能鍵值在6CH中
CJNE A,#10H,PP1
ACALL BELL1 ;按下F0鍵,蜂鳴器響一聲(模擬F1功能)
PP1: CJNE A,#20H,PP2
ACALL BELL2 ;按下F1鍵,蜂鳴器響二聲(模擬F2功能)
PP2: CJNE A,#40H,PP3 ;
ACALL BELL3 ;按下F2鍵,蜂鳴器響三聲(模擬F3功能)
PP3: CJNE A,#80H,MAIN
ACALL BELL4 ;按下F3鍵,蜂鳴器響四聲(模擬F4功能)
AJMP MAIN
;查詢鍵按的子程序( 針對小鍵盤上的16個數字鍵,共有四行、四列)
KEY20: MOV R5,#0 ;(R5) = 列號,其值為#0,#1,#2,#3
MOV R2,#0FEH
KEY20S: MOV A,R2 ;往PB口送掃描數據:#0FEH
ACALL WRITEB
ACALL READA ;讀A口
MOV A,MRD ;讀PA口,判斷按鍵在那一行?
MOV R1,#0 ;(R1)=行值:#0,#4,#8,#12
JNB ACC.0,REL0 ;第0行有鍵按下,行首鍵值R1為#0。轉REL0處理
MOV R1 ,#04H
JNB ACC.1,REL0 ; 第1行有鍵按下,行首鍵值R1為#4。轉REL0處理
MOV R1,#08H
JNB ACC.2, REL0 ; 第2行有鍵按下,行首鍵值R1為#8。轉REL0處理
MOV R1, #0CH
JNB ACC.3 , REL0 ; 第3行有鍵按下,行首鍵值R1為#12。轉REL0處理
MOV R1,#0
MOV A, R2
RL A
MOV R2,A ;準備掃描下一列(PB口),共有四列:#0,#1,#2,#3
INC R5 ;列的鍵值加1
CJNE R2, #0EFH, KEY20S ;第三列未掃描完,返回繼續檢測有無按鍵
RET ;第三列已掃描完,返回主程序
;有鍵按下,重設顯示區
REL0: LCALL BELL ;有鍵按下,鳴笛
ACALL KEY20A ;消除按鍵抖動
MOV A, R5 ;取按鍵數值:行首值(#0,#4,#8,#12)加列值(#0,#1,#2,#3)
ADD A, R1 ;(R5)+(R1)=按鍵位置對應的數值(#0,#1,….#E,#F)
PUSH ACC ;保存鍵值(行值加列值)
MOV A , 71H ;將按鍵數值存入71H~76H中
CJNE A , #0FFH, RE1 ;71H中有數(非#0FFH),說明四位地址有效,轉RE1,
;應將新數存入75H,76H中去
MOV 71H, 72H ;71H中無數((71H)=# 0FFH),數據從后位移向前位
MOV A, 71H ;鍵入的是四位地地址,應存入71H~74H中
CJNE A , #0FFH , KY4
SJMP KY5
KY4: CJNE A, #8, KY2 ;在71H中的數據應小于8。因為四位地址不能大于7FFFH
SJMP KY3
KY2: JNC KY3 ;即是說71H中的數不能出現#8,#9,#0A,#0B,#0C,#0D,#0E,#0F
KY5: MOV 72H,73H ;按一鍵,地址往前移動一位
MOV 73H,74H
POP ACC
MOV 74H,A ;將最新鍵入的數存入74H中,看作地址用
RET
KY3: MOV 71H,#0 ; 若四位地址值大于7FFFH,地址非法,應將四位地址改寫為0000H
MOV 72H,#0
MOV 73H,#0
MOV 74H,#0
POP ACC
RET
RE1: POP ACC
MOV 75H,76H ;75H,76H中存放兩位數值。76H向75H移動
MOV 76H , A ;將最新鍵入的數存入76H
RET
;消除抖動子程序
KEY20A: ACALL READA ;讀A口
MOV A,MRD
CJNE A, #0FFH, KEY20A ;KEY20是否有鍵按下,有返回KEY20A
ACALL DEL0 ;延時消除誤判
MOVX A, @DPTR
CJNE A,#0FFH,KEY20A ;再判是否有鍵按下,有則返回KEY20A等待
RET
INIT: MOV 71H,#6 ;在RAM 71H~76H 中充入#0FFH
MOV A,#0FFH
INDP: MOV @R0,A
INC R0
DJNZ R4,INDP
RET
READA: MOV SLAW,#SLA1W ;從A口輸入的數據
MOV SLAR,#SLA1R
WRA: MOV SLA,SLAR
MOV NUMBYT,#1
LCALL RDNBYT
RET
INITA: MOV SLAW,#SLA1W ;初始化:置輸入口鎖存器為高電平
MOV SLAR,#SLA1R
MOV MTD,#0FFH
MOV SLA,SLAW
MOV NUMBYT,#1
LCALL WRNBYT
RET
WRITEB: MOV SLAW,#SLA2W ;將數據送器件B
MOV SLAR,#SLA2R
ACALL WRBC
RET
WRITEC: MOV SLAW,#SLA3W ;將數據送器件C
MOV SLAR,#SLA3R
ACALL WRBC
RET
WRBC: MOV MTD,A
MOV SLA,SLAW
MOV NUMBYT,#1
LCALL WRNBYT
RET
;查看F1,F2,F3,F4(PA4~PA7)是否有鍵按下?如有,則存入6CH中
KEY0: ACALL READA ;讀A口
MOV A,MRD
ANL A,#0F0H ;只取高四位(F1,F2,F3,F4對應的位在高四位中)
CJNE A,#0F0H,K1
RET
K1: CPL A
MOV 6CH,A ;將功能鍵值存入6CH中
RET
BELL: CLR P3.4
ACALL DELY
SETB P3.4
RET
DELY: MOV R6,#20H ;延時子程序
TM: MOV R5,#0
DJNZ R5,$
DJNZ R6,TM
RET
DELYL: MOV R4,#4 ;長延時子程序
TT1: MOV R5,#0H
TT2: MOV R6,#0
DJNZ R6,$
DJNZ R5,TT2
DJNZ R4,TT1
RET
BELL1: ACALL BELL ;鳴笛一聲,模擬功能鍵F1的功能
RET
BELL2: MOV R7,#2 ; 鳴笛二聲,模擬功能鍵F2的功能
DF2: ACALL BELL
ACALL DELYL
DJNZ R7,DF2
RET
BELL3: MOV R7,#3 ; 鳴笛三聲,模擬功能鍵F3的功能
DF3: ACALL BELL
ACALL DELYL
DJNZ R7,DF3
RET
BELL4: MOV R7,#4 ; 鳴笛四聲,模擬功能鍵F4的功能
DF4: ACALL BELL
ACALL DELYL
DJNZ R7,DF4
RET
;顯示六位數碼管的子程序
DISP: MOV R2,#01H ; 字位碼在R2中,(R2)= #1,#2,#4,#8
MOV R5,#6 ;顯示6個數
MOV R0,#71H ;71H為要顯示的數據區的首地址
DSP1: MOV A,R2
ACALL WRITEB ;B口輸出作為六位數碼管的位選
MOV A,@R0 ;將要顯示的數值送入A中
DSP2: MOV DPTR,#BCD ;查表
MOVC A,@A+DPTR ;查表,查出要顯示的數值的字形碼
ACALL WRITEC ;C口輸出字形碼
ACALL DEL0 ;延時
MOV A,R2
RL A
MOV R2,A ; 字位碼指向下一位
INC R0 ;準備顯示下一位
DJNZ R5, DSP1
RET
BCD: DB 3FH,06H,5BH,4FH ;顯示數值0,1,2,3
DB 66H,6DH,7DH,07H ;4,5,6,7
DB 7FH,6FH,77H,7CH ;8,9,A,B
DB 39H,5EH,79H,71H ;C,D,E,F
DB 73H,3EH,31H,6EH ;P,U,Z,Y
DB 40H,00H ;- ,滅
DEL0: MOV R6,#00H ;延時子程序
TMA: MOV R7,#01
DJNZ R7,$
DJNZ R6,TMA
RET
WRNBYT: MOV R3,NUMBYT
LCALL ST ;啟動I2C總線
MOV A,SLA ;發送SLAW字節
LCALL WRBYT
LCALL CACK ;檢查應答位
JB F0,WRNBYT ;非應答位則重發
MOV R1,#MTD
WRDA: MOV A,@R1
LCALL WRBYT
LCALL CACK
JB F0,WRNBYT
INC R1
DJNZ R3,WRDA
LCALL STOP
RET
WRBYT: MOV R0,#08H ;8為數據長度送R0中
WLP: RLC A ;發送數據左移,使發送位入C
JC WR1 ;判斷發送"1"還是"0",發送"1"轉WR1
AJMP WR0 ;發送"0"轉WR0
WLP1: DJNZ R0,WLP ;8位是否發送完,未完轉WLP
RET ;8位發送完結束
WR1: SETB VSDA ;發送"1"程序段
SETB VSCL
NOP
NOP
CLR VSCL
CLR VSDA
AJMP WLP1
WR0: CLR VSDA ;發送"0"程序段
SETB VSCL
NOP
NOP
CLR VSCL
AJMP WLP1
RDNBYT: MOV R3,NUMBYT
LCALL ST ;發送啟動位
MOV A,SLA ;發送尋址字節(讀)
LCALL WRBYT
LCALL CACK ;檢查應答位
JB F0,RDNBYT ;非正常應答時重新開始
RDN: MOV R1,#MRD ;接收數據緩沖區首址MDR入R1
RDN1: LCALL RDBYT ;讀入一個字節到接收數據緩沖中
MOV @R1,A
DJNZ R3,ACK ;N節讀完否?未完轉ACK
LCALL MNACK ;N個字節讀完發送非應答位A
LCALL STOP ;發送停止信號
RET ;子程序結束
ACK: LCALL MACK ;發送應答位
INC R1 ;指向下一個接收數據緩沖單元
SJMP RDN1 ;轉讀入下一個字節數據
RDBYT: MOV R0,#08H ;8位數據長度如R0
RLP: SETB VSDA ;置VSDA為輸入方式
SETB VSCL ;使VSDA上數據有效
MOV C,VSDA ;讀入VSDA引腳狀態
MOV A,R2 ;讀入"0"程序段,由C拼裝入R2中
RLC A
MOV R2,A
CLR VSCL ;使VSCL=0可繼續接收數據位
DJNZ R0,RLP ;8位讀完否?未讀完轉RLP
RET
STOP: CLR VSDA ;停止I2C總線數據傳送
SETB VSCL
NOP
NOP
SETB VSDA
NOP
NOP
CLR VSDA
CLR VSCL
RET
MACK: CLR VSDA ;發送應答位
SETB VSCL
NOP
NOP
CLR VSCL
SETB VSDA
RET
MNACK: SETB VSDA ;發送非應答位
SETB VSCL
NOP
NOP
CLR VSCL
CLR VSDA
RET
CACK: SETB VSDA ;應答位檢查
SETB VSCL
CLR F0
MOV C,VSDA
JNC CEND
SETB F0
CEND: CLR VSCL
RET
ST: SETB VSDA ;啟動I2C總線
SETB VSCL
NOP
NOP
CLR VSDA
NOP
NOP
CLR VSCL
RET
END
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -