96個key的零延時采集
HotPower 發表于 2003-11-5 18:04 侃單片機 ←返回版面 ;-------96鍵演示程序------------------------- ;這是1個回復題中的應用示例,已通過軟仿真“驗證” ;這只是鍵掃描技術的1個“縮影”,方法實在太多. ;有“難看之處”,敬請高手們批評指教. ;HotPower將虛心接受,堅決改正.重新做人. ;發表目的: 在21IC中壯大游擊隊. ;---------------------------------------------------- ;由于2051資源問題,本程序只取多任務鍵盤的壓放鍵2個事件 ;廢除長壓鍵(壓鍵1段時間后才激活)事件 ;廢除長放鍵(放鍵1段時間后才激活)事件 ;廢除雙擊鍵事件 ;廢除任意組合鍵事件 ;----------常數定義------------------------------ TIME208US EQU -208;20mS/96=208uS TIME50MS EQU -5000;50000uS ;KEYCOUNT EQU 1;鍵盤鍵個數(軟仿真時用) ;------------------------------------------------ KEYCOUNT EQU 96;鍵盤鍵個數(實際應用) ;----------RAM地址定義---------------------------- ;--------96鍵鍵狀態標志位數組Bits[12*8位]-------- KEYBUFF1 DATA 08H;08H~13H(12個字節96位)對應96鍵 ;--------96鍵鍵跳變標志位數組Bits[12*8位]-------- KEYBUFF2 DATA 14H;14H~1FH(12個字節96位)對應96鍵 ;------------------------------------------------ KEYNUM DATA 30H; HotPower_55H DATA 6EH HotPower_AAH DATA 6FH ;--------------------------------------- SP_MIN DATA HotPower_AAH ;-------主程序開始---------------------- ORG 0000H START: LJMP MAINSTART;主程序開始 ORG 0003H ;-------掉電保護中斷INT0服務程序-------- INT0_INTADDR: RETI ORG 000BH ;-------定時器T0中斷服務程序------------ ;工作在8位自動裝載方式,每208uS中斷一次 T0_INTADDR: LJMP T0INTPROC;定時器T0中斷服務程序 RETI ORG 0013H ;-------外部中斷INT1服務程序------------ INT1_INTADDR: RETI ORG 001BH ;-------定時器T1中斷服務程序------------ T1_INTADDR: LJMP T1INTPROC;定時器T1中斷服務程序 RETI ; ORG 0023H ;-------串行中斷服務程序---------------- ;SINT_INTADDR: ; RETI ;------------------------------------------- ; ORG 002BH ;-------定時器T2中斷服務程序------------ ; LJMP T2INTPROC;執行中斷服務程序 ; RETI ;-------執行鍵盤命令---------------------- ;本程序利用散轉回收技術(指針函數) ;它的最大優點是散轉處的子程序可被它用(函數) ;它比JMP @A+DPTR指令要“游擊”很多,靈活和隱蔽了許多 ;它在對付“反匯編”方面,比JMP @A+DPTR更“壞” ;HotPower打死也不用JMP @A+DPTR KEYPROC: ;入口: DPTR散轉地址表 ; ACC 散轉號 CJNE A,#KEYCOUNT,$+3 JNC KEYPROC_EXIT;非法鍵(96~255)防止程序飛,不散轉 RL A;*2;地址需要2字節(像ARM的大端模式) ADD A,DPL MOV DPL,A CLR A ADDC A,DPH MOV DPH,A MOV A,#01H;低8位 MOVC A,@A+DPTR;取低8位地址 PUSH ACC;壓入事件處理低8位地址 CLR A;高8位 MOVC A,@A+DPTR;取高8位地址 PUSH ACC;壓入事件處理高8位地址 KEYPROC_EXIT: RET;執行鍵盤命令(散轉JMP @A+DPTR) ;-------壓鍵事件處理地址表-------------------- KEYJMPPROCTAB: DW KEYPROC0;0鍵壓鍵 DW KEYPROC1 DW KEYPROC2 ;............................ DW KEYPROC95;95鍵壓鍵 ;-------放鍵事件處理地址表-------------------- KEYJMPPROCTABX: DW KEYPROC0X;0鍵放鍵 DW KEYPROC1X DW KEYPROC2X ;............................ DW KEYPROC95X;95鍵放鍵 MAINSTART: ;-------P0口初始化------------------ MOV P0,#11111111B ;-------P1口初始化------------------ MOV P1,#11111111B ;-------P2口初始化------------------ MOV P2,#11111111B ;-------P3口初始化------------------ MOV P3,#11111111B ;-------------------------------- MOV IE,#00000000B;EA=0,ES=ET2=ET1=EX1=ET0=EX0=0 MOV SP,#SP_MIN; MOV PSW,#00000000B;RS1RS0=00,R0~R7=00H~07H MOV A,#LOW(MAINNEXT) PUSH ACC MOV A,#HIGH(MAINNEXT) PUSH ACC RETI MAINPROC: LCALL MAININIT;系統初始化 MOV IE,#10001010B;開中斷 ;-------主循環------------------------------- MAINLOOP: ORL PCON,#10001101B;待機 SJMP MAINLOOP;死循環 MAINNEXT: MOV A,#LOW(MAINPROC) PUSH ACC MOV A,#HIGH(MAINPROC) PUSH ACC RETI ;-------主程序初始化------------------------ MAININIT: ;-------接口初始化-------------------------- ;-------內存初始化------------------------- MOV A,HotPower_55H XRL A,HotPower_AAH CPL A JZ MAININITNEXT;內存未破壞 MOV HotPower_55H,#055H MOV HotPower_AAH,#0AAH LCALL SYSTEMINIT;系統初始化 MAININITNEXT: ;-------運行初始化--------------- LCALL SYSTEMSETUP;系統設置 RET SYSTEMINIT: LCALL KEYBUFFINIT RET SYSTEMSETUP: ;-------系統主頻12MHz--------------------------------- ; MOV IP,#00100001B;中斷優先級EX0>ET2>ET0>EX1>ES MOV TMOD,#00010010B;T1=MODE1(16位定時器),T0=MODE2(8位定時器) MOV TCON,#01010101B;啟動定時器TR1EQUTR0EQU1,IT1EQUIT0EQU1 ;------------------------------------------------------ MOV TL0,#TIME208US;設置定時器0時間常數 MOV TH0,#TIME208US;設置定時器0時間常數 ;------------------------------------------------------ ; MOV TL1,#LOW(TIMEXMS);設置定時器1時間常數 ; MOV TH1,#HIGH(TIMEXMS) ;------- KEYBUFFINIT: MOV KEYNUM,#00H MOV R0,#KEYBUFF1 KEYBUFFINITLOOP: MOV @R0,#00H INC R0 CJNE R0,#KEYBUFF2+12,KEYBUFFINITLOOP RET ;--------------------------------------------- INKEY: ;T0每中斷1次,將進行1次鍵"掃描" LCALL TESTKEY;鍵盤測試(不掃但描) ;-------鍵盤軟仿真測試點----------------- ;在此 A=0 無鍵壓下,A<>0有鍵壓下 ;若調試n個鍵,需將KEYCOUNT設置為n.(KEYCOUNT=1~96) ;---------------------------------------- JNZ INKEY1;有鍵壓下 INKEY0: ;-------無鍵壓下------------------------ LCALL GETKEYBIT;取鍵狀態 JZ INKEY01;鍵狀態未發生變化 LCALL CLRKEYBIT;設置放鍵標志 LCALL SETKEYBITK;設置跳變標志(防止放鍵抖動) RET INKEY01: LCALL GETKEYBITK;取鍵跳變標志 JZ INKEY02;鍵未發生跳變(防止2次事件處理) LCALL CLRKEYBITX;設置重入標志 MOV A,KEYNUM;取鍵號 MOV DPTR,#KEYJMPPROCTABX;鍵盤放鍵事件處理表 LCALL KEYPROC;執行鍵盤放鍵事件處理 INKEY02: RET INKEY1: ;-------有鍵壓下------------------------ LCALL GETKEYBIT;取鍵狀態 JNZ INKEY11;鍵狀態未發生變化(防止2次事件處理) LCALL SETKEYBIT;設置壓鍵標志 LCALL SETKEYBITK;設置跳變標志(防止壓鍵抖動) RET INKEY11: LCALL GETKEYBITK;取鍵跳變標志 JZ INKEY12;鍵未發生跳變 LCALL CLRKEYBITX;設置重入標志 MOV A,KEYNUM;取鍵號 MOV DPTR,#KEYJMPPROCTAB;鍵盤壓鍵事件處理表 LCALL KEYPROC;執行鍵盤壓鍵事件處理 INKEY12: RET GETKEYBITK: MOV A,R0 ADD A,#12 MOV R0,A SJMP GETKEYBITX GETKEYBIT: LCALL GETKEYBITADDR LCALL GETKEYBITVAL GETKEYBITX: MOV A,@R0 ANL A,B RET SETKEYBITK: MOV A,R0 ADD A,#12 MOV R0,A SJMP SETKEYBITX SETKEYBIT: LCALL GETKEYBITADDR LCALL GETKEYBITVAL SETKEYBITX: MOV A,@R0 ORL A,B MOV @R0,A RET CLRKEYBITK: MOV A,R0 ADD A,#12 MOV R0,A SJMP CLRKEYBITX CLRKEYBIT: LCALL GETKEYBITADDR LCALL GETKEYBITVAL CLRKEYBITX: MOV A,@R0 XRL B,#0FFH;取反B ANL A,B XRL B,#0FFH;還原B MOV @R0,A RET ;----------------------------------- ;CPLKEYBITK: ; MOV A,R0 ; ADD A,#12 ; MOV R0,A ; SJMP CPLKEYBITX ;CPLKEYBIT: ; LCALL GETKEYBITADDR ; LCALL GETKEYBITVAL ;CPLKEYBITX: ; MOV A,@R0 ; XRL A,B ; MOV @R0,A ; RET ;--------------------------------------------- GETKEYBITVAL: MOV A,KEYNUM ANL A,#07H ADD A,#GETKEYBITTAB-GETKEYBITTABOFF MOVC A,@A+PC GETKEYBITTABOFF: MOV B,A RET GETKEYBITTAB: DB 00000001B DB 00000010B DB 00000100B DB 00001000B DB 00010000B DB 00100000B DB 01000000B DB 10000000B RET ;---------------------------------------------- GETKEYBITADDR: MOV A,KEYNUM ANL A,#01111000B RR A RR A RR A ADD A,#KEYBUFF1 MOV R0,A RET ;-------鍵測試子程序-------------------------- TESTKEY: ;鍵號KEYNUM=000 0000B~101 1111B(0~95) ;入口 無 ;出口 ACC==0 無鍵壓下(鍵號KEYNUM) ; ACC<>0 有鍵壓下(鍵號KEYNUM) MOV A,KEYNUM;取鍵號 ANL A,#0FH;取行號(鍵號低4位) ANL P3,#0F0H;清行信號 ORL P3,A;發送行掃描信號DCBA;P3.3~P3.0 MOV A,KEYNUM;取鍵號 ANL A,#01110000B;取列號(鍵號高3位) SWAP A;變換到低3位 ADD A,#TESTKEYTAB-TESTKEYTABOFF;得到表地址 MOVC A,@A+PC;取列表值 TESTKEYTABOFF: JZ TESTKEYEXIT;6,7非法列,認為無鍵壓下 PUSH B;保護現場 MOV B,A;暫存 ANL A,P1;接收列值P1.7~P1.2,有鍵壓下為0 XRL A,B;有鍵壓下非0 POP B;恢復現場 TESTKEYEXIT: RET TESTKEYTAB: DB 00000100B;0列 DB 00001000B;1列 DB 00010000B;2列 DB 00100000B;3列 DB 01000000B;4列 DB 10000000B;5列 DB 00000000B;6列非法 DB 00000000B;7列非法 ;-------定時器T0中斷服務程序-------------------- ;每個鍵20mS掃描1次,并自動進行壓鍵或放鍵消抖處理 ;這是1個大規模(96鍵)的鍵盤游擊戰的非典戰例 ;特點: ;1.不需鍵掃描.(T0中斷的次序即為鍵掃描號) ;2.不需鍵消抖.(在T0中斷96次后自動消抖) ;3.壓鍵放鍵事件分離(散轉回收技術) ;4.用戶事件"并行處理"(mS級分時) T0INTPROC: PUSH PSW PUSH ACC PUSH B PUSH DPL PUSH DPH T0INTPROC_START: LCALL INKEY;鍵掃描并執行壓放鍵事件處理 INC KEYNUM;準備下一鍵號(T0中斷計數) MOV A,KEYNUM CJNE A,#KEYCOUNT,T0INTPROC_EXIT MOV KEYNUM,#00H;開始下1輪鍵掃描 T0INTPROC_EXIT: POP DPH POP DPL POP B POP ACC POP PSW RETI ;-------定時器T1中斷服務程序------------ T1INTPROC: RETI ;-------0鍵壓鍵事件處理--------------------- KEYPROC0: ;在此添加用戶壓鍵事件 RET ;-------1鍵壓鍵事件處理--------------------- KEYPROC1: ;在此添加用戶壓鍵事件 RET ;-------2鍵壓鍵事件處理--------------------- KEYPROC2: ;在此添加用戶壓鍵事件 RET ;-------95鍵壓鍵事件處理--------------------- KEYPROC95: ;在此添加用戶壓鍵事件 RET ;-------0鍵放鍵事件處理--------------------- KEYPROC0X: ;在此添加用戶放鍵事件 RET ;-------1鍵放鍵事件處理--------------------- KEYPROC1X: ;在此添加用戶放鍵事件 RET ;-------2鍵放鍵事件處理--------------------- KEYPROC2X: ;在此添加用戶放鍵事件 RET ;-------95鍵放鍵事件處理--------------------- KEYPROC95X: ;在此添加用戶放鍵事件 RET ;-------全部程序結束-------------------------------------- END
|
評論