一个PS2仿真键盘的设计

    技术2022-05-11  71

    设计目的: 1.熟悉PS/2协议的原理 2.学习单片机的使用 设计内容: 依照PS/2协议,在51芯片上开发汇编程序,使得按下开发板上的按键时,能够在PC机上输出a、b、c。 实验环境: 开发板、STC12C2052AD芯片、PS/2线、PC机、Keil软件、STC-ISP程序下载器 相关参数: 单片机振荡频率6MHz(具体情况请看此型号单片机用户手册) 指令周期0.5微秒(51型单片机的指令周期是其振荡频率的12分之一) PS/2连接器引脚定义(见参考文献《PS/2技术参考》) 能够接受的键盘时钟信号频率10-20KHz(最大33KHz,推荐设为15KHz)   设计思想: 使用开发板上的按钮产生中断信号,使单片机进入相应的中断处理程序,从而向PC机发送相应的扫描码。PC机主板中有一个解码芯片,此芯片在收到扫描码之后,引发PC机操作系统的中断(I/O的中断),转到操作系统中的中断处理程序,从面在系统中输出相应字符。 原理: 实际的通用键盘上的每一个键都对应一个唯一个扫描码,这些键会在极短的时间内被扫描一遍,以确认它们有没有被按下,如果某个键被按下了,就发送其相应的扫描码。而在开发板上,51芯片有三个按键,对应芯片上的两个中断口和一个定时/计数器输入口。中断接口可以直接使用,当按下键时就触发中断,而定时/计数器需要设置为初始值为FFH,一旦按下键便会溢出而产生中断的计数器。 主机与键盘有四根线相连,时钟信号数、数据线、接地线、电源线。 时钟信号在任何时刻都是由键盘产生的,PC机在时种的下降沿接收数据线上的信号,要是PC机向键盘发送数据,则键盘在时钟的上升沿接收数据线上的数据。虽是由键盘产生时钟信号,但是PC机对总线有着绝对的控制权,只要其将时钟线拉低(高低电平信号有这样的特性:只有一端的信号为低电平,则整条线的信号都为低电平。这就是为什么要向单片机I/O口输出一个信号,要先将外部输入单片机这个I/O口的信号释放(拉高)。否则输出的永远都是低电平),就要以抵制键盘的输出。 总线上有这些几种状态: 1、PC等待键盘输出状态(键盘可以输出状态):CLK=1,DATA=1; 2、键盘等待PC输出状态(PC可以输出状态):CLK=1,DATA=0(这个状态之前还有一些状态要生产生的,详情请见参考文献《PS/2技术参考》) 3、正在输出状态:此时的时钟线与数据线上的信号没有定值,依据所要发送的数据不同而不同,CLK=X,DATA=X   键盘从外部存储器中读取相应键位的扫描码,当要改变某个键所要发送的扫描码时,只需改变外部存储器中对应位置的扫描码,这样就可以方便地改变某键所要发送的扫描码。在存放扫描码时,只需将扫描码按顺序存放,如E0,70按存储地址从小到大顺序地排列。因为通码(make code)最多只有两个十六进制数,且如有两个则第一个必是E0H,而断码(break code)最多只有三个,且如果有三个,则第一个必是E0H,如果有二个,则第一个必是F0H。所以,当发送时,如果发现第一个是E0H或F0H的话,则再发送其后的一个扫描码。 注意事项: 1、  发送8个数据位时,是低位先发送(least significant bit first),如果是用高位先发送,主机自然是无法识别会发送的数据,会报警; 2、  如果想要精确计算时间,那么像子程序调用语句会占用两个指令周期也应该考虑到; 3、  连接线应该连在指示灯靠近51芯片的一端,否则无法接收到主机发来的信号;PS/2 4、  汇编程序前的org 语句必须按其指示的地址大小排列,小的在前,大的在后;   程序: ; ======================================= ; program ; check clk and data before every 8 bit data sending ; a function is created for send all 11bit data ; a function is created for parity calculating ; CAPSLOCK :BIG LETTER P1.3=0,SMALL LETTER P1.3=1   ; ======================================= ; ======================================= ; VARS USED LOCALY ; R0 IS USED LOCALY AS A COUNTER ; 20H.1 20H.2 20H.3 20H.4 IS USED IN FUNCTION AS TEMP VAR ; R3,R4,R5 USED LOCALLY IN DELAY() ; =================================== ; Define Samples ; ==================================== MCLK EQU P1 .2      ; VALUE OF CLOCK LINE MDATA EQU P1 .1      ; VALUE OF DATA LINE SCAN EQU R1         ; VALUE OF THE SCAN CODE RECV EQU R2         ; VALUE RECEIVED BY KEYBOARD RECV2 EQU R6     ; THE VALUE RECEIVED SECONDLY NEXTBIT EQU CY    ; VALUE OF THE BIT WILL SENT NEXT PARITY EQU 20H .1     ; VALUE OF PARITY TEMP   EQU 20H .2     ; THIS BIT IS FOR TEMPORITARY USE TEMP1  EQU 20H .3     ; THIS BIT IS FOR TEMP USE TEMP8BIT EQU 21HLOOPCOUNTER EQU 30H  ; COUNTER SPECIAL FOR SENDALLBIT SCROLLLOCK EQU P1 .5 CAPSLOCK EQU P1 .6 NUMLOCK EQU P1 .7 ERROR_LIGHT EQU P1 .4            ; PARITY ERROR ERROR_LIGHT_STOPBIT EQU P1 .3    ; STOP BIT RECEIVE ERROR ; =================================== ; =================================== ; ORG ; =================================== ORG 00HJMP MAINORG 0003HLJMP K1DOWNORG    000BHLJMP K3DOWNORG 0013HLJMP K2DOWN ; ============================================================ ; MAIN  ; ============================================================ MAIN: ; ============================== ; SET INTERRUPTER AND TIMER     mov ie , #10000101B  ; 中断使能     mov ip , #00H  ; 中断优先     mov tcon , #00000101b  ; 中断为电平触发       ; TIME0 AS A BUTTON     MOV TMOD , #06H    MOV TH0 , #0FFH    MOV TL0 , #0FFH    SETB ET0    SETB TR0 ; ============================== ; ============================== ; SET CLK AND DATA LINE TO NORMAL STATUS     SETB MCLK    SETB MDATA ; ==============================     SETB CAPSLOCK  ; CAPSLOCK OFF(1)     SETB NUMLOCK   ; NUMLOCK OFF(1)     SETB SCROLLLOCK      ; SCROLLLOCK OFF(1) CHKSTATUS:    JNB MCLK , CHKSTATUS     ; IF MCLK==0 THEN GOTO CHKSTATUS     JB  MDATA , CHKSTATUS       ; IF MDATA==1 THEN GOTO CHKSTAUS      ; NOW MCLK=1 AND MDATA =0 ,READY TO RECEIVE DATA FROM PC     LCALL RECV_CHK_SEND    ; RECEIVE DATA FROM PC      LJMP CHKSTATUS      ; WAIT FOR BREAK ; ============================================================ ; ///MAIN ; ============================================================ ; =============================================================================================== ;                             AREA FOR FUNCTION               ; =============================================================================================== LJMP ENDOFFILE ; ==================================== ; IN THIS FUNCTION:  RECEIVE ALL 10BIT DATA BY RECEIVEALLBIT() AND CHK WHETHER IT'S CORRECT THEN SEND CORRESPONDING SCANCODE TO PC ; ==================================== RECV_CHK_SEND:    CLR P1 .0      ; INDICATE START RECEIVEING      LCALL RECEIVEALLBIT  ; RECV PARITY TEMP1     MOV A , RECV    CJNE A , #0EDH , RECV_CHK_SEND_END     ; =====================      ; RECV==EQ NOW SET LED      ; CHKSTATUS_2:      ;     JNB MCLK,CHKSTATUS_2    ;IF MCLK==0 THEN GOTO CHKSTATUS      ;     JB  MDATA,CHKSTATUS_2      ;IF MDATA==1 THEN GOTO CHKSTAUS         LCALL DELAY50        LCALL DELAY50        LCALL RECEIVEALLBIT  ; RECV PARITY TEMP1                          ; ========================          ; THE CODE IS RIGHT AFTER THIS  ,TESTED BY MOV "RECV,#00000110"         MOV A , RECV        RRC A         ; NOW C=LEAST BIT OF A         CPL C         ; PC: C=1 ON   ;C=0 OFF NOW IN KEYBOARD C=1 OFF(LIGHT OFF) C=0 ON(LIGHT ON)         MOV SCROLLLOCK , C        RRC A         ; NOW C=LEAST BIT OF A         CPL C         ; PC: C=1 ON   ;C=0 OFF NOW IN KEYBOARD C=1 OFF(LIGHT OFF) C=0 ON(LIGHT ON)         MOV NUMLOCK , C        RRC A         ; NOW C=LEAST BIT OF A         CPL C         ; PC: C=1 ON   ;C=0 OFF NOW IN KEYBOARD C=1 OFF(LIGHT OFF) C=0 ON(LIGHT ON)         MOV CAPSLOCK , C        SETB P1 .0     LJMP RECV_CHK_SEND_END     ; /==================== RECV_CHK_SEND_END:RET ; ==================================== ; IN THIS FUNCTION:  RECEIVE ALL 10BIT DATA BY RECEIVEALLBIT() AND CHK WHETHER IT'S CORRECT THEN SEND CORRESPONDING SCANCODE TO PC ; ==================================== ; ==================================== ; RECIEVE ALL THE 10BIT DATA FROM PC    AND CHECK WHETHER IT'S RIGHT ; SAVE THE 8BIT DATA TO RECV ; TEMP1: PARITY FIGURED OUT ; PARITY: PARITY RECEIVED ; ==================================== RECEIVEALLBIT:    MOV LOOPCOUNTER , #0008H    RECV8BIT_LOOP:        LCALL RECEIVEONE   ; GET ONE BIT AND SAVE IT TO CY         RRC A               ; RIGHT MOVE THIS BIT TO A         DJNZ LOOPCOUNTER , RECV8BIT_LOOP   ; LOOP FOR 8 TIMES         MOV C , P                 ; C=P(THIS DOUBLE PARITY JUST RECEIVED         CPL C                 ; CHANG TO ODD PARITY         MOV TEMP1 , C             ; STORE THE ODD PARITY TO TEMP1                 MOV RECV , A           ; RECV=A         LCALL RECEIVEONE   ; GET PARITY BIT         MOV PARITY , C       ; PARITY=C         LCALL RECEIVEONE   ; PC PULL UP DATA LINE         MOV TEMP , C           ; RECEIVE TERMINAL BIT(1)          ; MOV P1,RECV ;JUST FOR TESTING                 JNB MDATA , STOPBIT_ERROR     ;   1==MDATA THEN  RECEIVEALLBIT_ERROR          ; SEND ACK                 LCALL SENDACK        MOV C , TEMP1     ;  C = PARITY FIGURED OUT         MOV A , #00H      ; A=OOH         RRC A             ; SAVE C TO A         MOV TEMP8BIT , A   ; SAVE A TO TEMP8BIT         MOV C , PARITY        MOV A , #00H              RRC A        CJNE A , TEMP8BIT , PARITY_ERROR         ; DATA RECEIV SUCCESSFUL         MOV SCAN , #00H        LCALL SENDALLBIT         ; IF THE PROGRAM CAN RUN HERE,INDICATE ALL IS IN GOOD CONDICION          ; SCAN 00H TO TELL PC ALL IN IN GOOD          ; MOV SCAN,#00H          ; LCALL SENDALLBIT         LJMP ENDOFSENDALLBIT         ; ===================          ; THE PARITY IS WRONG ,SO KEYBOARD RECEIVED A WRONG DATA         PARITY_ERROR:            CLR ERROR_LIGHT             ; MOV SCAN,#0FFH              ; LCALL SENDALLBIT          ; /==================         LJMP ENDOFSENDALLBIT         ; ===================          ; STOPBIT ERROR         STOPBIT_ERROR:            CLR ERROR_LIGHT_STOPBIT             ; MOV SCAN,#0FFH              ; LCALL SENDALLBIT         LJMP ENDOFSENDALLBIT                    ENDOFSENDALLBIT:        RET ; ==================================== ; /RECIEVE ALL THE 10BIT DATA FROM PC    AND CHECK WHETHER IT'S RIGHT ; /SAVE THE 8BIT DATA TO RECV ; ==================================== ; ==================================== ; SENDACK ; ==================================== SENDACK:                                 LCALL DELAY15    CLR MDATA    LCALL DELAY5    CLR MCLK    LCALL DELAY40    SETB MCLK    LCALL DELAY5    SETB MDATARET ; //================================== ; ==================================== ; RECEIVE ONE BIT DATA FROM PC ; SAVE THIS BIT TO CY ; ==================================== RECEIVEONE:    LCALL DELAY20    CLR MCLK    LCALL DELAY40    SETB MCLK    LCALL DELAY20    MOV C , MDATA        ; SAVE THIS BIT OF DATA TO CY,SAVE IT TO RECV LATER RET ; ==================================== ; /RECEIVE ONE BIT DATA FROM PC ; ==================================== ; ==================================== ; INVOKE THIS FUNCTION WHEN K1 IS DOWN ; ==================================== K1DOWN:            MOV SCAN , #01CH    LCALL SENDALLBIT     MOV SCAN , #0F0H    LCALL SENDALLBIT      MOV SCAN , #01CH    LCALL SENDALLBIT     ; LCALL DELAY   ;DON'T PRINT SO FAST RETI ; ==================================== ; //INVOKE THIS FUNCTION WHEN K1 IS DOWN ; ==================================== ; ==================================== ; INVOKE THIS FUNCTION WHEN K2 IS DOWN ; ==================================== K2DOWN:            MOV SCAN , #032H    LCALL SENDALLBIT     MOV SCAN , #0F0H    LCALL SENDALLBIT      MOV SCAN , #032H    LCALL SENDALLBIT     ; LCALL DELAY   ;DON'T PRINT SO FAST RETI ; ==================================== ; //INVOKE THIS FUNCTION WHEN K2 IS DOWN ; ==================================== ; ==================================== ; INVOKE THIS FUNCTION WHEN K3 IS DOWN ; ==================================== K3DOWN:            MOV SCAN , #021H    LCALL SENDALLBIT     MOV SCAN , #0F0H    LCALL SENDALLBIT      MOV SCAN , #021H    LCALL SENDALLBIT     ; LCALL DELAY   ;DON'T PRINT SO FAST RETI ; ==================================== ; //INVOKE THIS FUNCTION WHEN K3 IS DOWN ; ==================================== ; ==================================== ; SEND ALL 11 BIT DATA ; ==================================== SENDALLBIT:     ; THE VAR SCANCODE MUST BE SET BEFORE THE FUNCTION      ; SET CLK AND DATA LINE TO 1     INIT:        SETB MCLK ;         SETB MDATA ;      ; CHECK WHETHER THE CLK AND DATA IS IN STATE THAT CAN TRANSFER DATA     CHKCLKHIGH:        JNB MCLK , CHKCLKHIGH  ; IF CLK=0 THEN GOTO CHKCLKHIGH ELSE CONTINUE actually,this is the cache,wait for clk=1 to send the data         LCALL DELAY50       ; DELAY 50us         JNB MCLK , CHKCLKHIGH  ;         JNB MDATA , CHKCLKHIGH ; IF DATA=0 THEN GOTO CHKCLKHIGH ELSE CONTINUE          ; NOW CLK=1 FOR 50US AND DATA=1         LCALL DELAY20 ;      ;DELAY 20US      ; ================================      ; CLK AND DATA CHECK FINISHED ,START DATA TRANSFAN      ; ================================     STARTSEND:        CLR NEXTBIT  ; SET START BIT                         ;1 PR         LCALL SENDBIT ; SENT THE START BIT                 ;170 PR          ; SEND SCAN CODE              ; NOW SCAN IS SET BEFOR SENDALLBIT()                                           ; MOV SCAN,#035H ;LET SCAN= THE SCAN CODE OF KEY A ;2 PR         LCALL SENDSCAN  ; SEND THE SCAN CODE                 ;1123 PR      ;     SEND PARITY ; #### COULD BE BETTER IN SENDING PARITY  #########         LCALL CALPARITY        MOV C , PARITY        LCALL SENDBIT                                      ; 140 PR          ; SEND TERMINAL SIGN         SETB NEXTBIT    ; TERMINAL SIGN=1                     ;1 PR         LCALL SENDBIT                                      ; 140 PR         LCALL DELAY50      ; DELAY 50us         LCALL DELAY20      ; DELAY 50us          ; FINISHED SENDING DATA    USED 1950 PERIODS RET  ; SENDALLBIT END ; ===================================== ; ===================================== ; long time delay ; ===================================== Delay:     MOV   R3 ,  #000H        MOV   R4 ,  #000H        MOV   R5 ,  #0DHDelay_Loop:        DJNZ  R3 ,  Delay_Loop        DJNZ  R4 ,  Delay_Loop        DJNZ  R5 ,  Delay_Loop    RET ; ===================================== ; ===================================================== ; SEND THE SCAN CODE IN VAR SCAN  ; PERIODS:1123 PR ; ===================================================== SENDSCAN:    CLR C                          ; 1 PR     MOV A , SCAN                      ; 2 PR                                      RRC A  ; MOVE RIGHT             ;1 PR     LCALL SENDBIT   ; SEND 7TH     ;140 PR     RRC A  ; MOVE RIGHT             ;1 PR     LCALL SENDBIT   ; SEND 6TH     ;140 PR     RRC A  ; MOVE RIGHT             ;1 PR     LCALL SENDBIT   ; SEND 5TH     ;170 PR     RRC A  ; MOVE RIGHT             ;1 PR     LCALL SENDBIT   ; SEND 4TH     ;140 PR     RRC A  ; MOVE RIGHT             ;1 PR     LCALL SENDBIT   ; SEND 3TH     ;140 PR     RRC A  ; MOVE RIGHT             ;1 PR     LCALL SENDBIT   ; SEND 2TH     ;140 PR     RRC A  ; MOVE RIGHT             ;1 PR     LCALL SENDBIT   ; SEND 1TH      ;140 PR     RRC A  ; MOVE RIGHT             ;1 PR     LCALL SENDBIT   ; SEND 0TH      ;140 PR RET ; ===================================================== ; ===================================================== ; SEND THE NEXTBIT ; PERIODS:138 PERIODS ; ===================================================== SENDBIT:    MOV MDATA , C              ; 1 period     LCALL DELAY20         ; 42 PERIODS     CLR MCLK           ; PULL DOWN THE CLOCK LINE     LCALL DELAY40         ; 82 PERIODS     SETB MCLK             ; 1 PERIODS     LCALL DELAY20         ; 12 PERIODS RET ; ===================================================== ; ====================================================== ; SUB FOR DELAY 16US ; RAM USED:R0 ; ====================================================== DELAY16:    MOV R0 , #003H  ; 2     DELAY16_IN:DJNZ R0 , DELAY16_IN ; THIS COMMAND WILL BE EXCUTE FOR 15 TIMES,    2period RET ; ====================================================== ; ====================================================== ; SUB FOR DELAY 32US ; RAM USED:R0 ; ====================================================== DELAY32:    MOV R0 , #00EH  ;     DELAY32_IN:DJNZ R0 , DELAY32_IN ; THIS COMMAND WILL BE EXCUTE FOR 31 TIMES,    2period RET ; ====================================================== ; ====================================================== ; SUB FOR DELAY 50US correct? ; RAM USED:R0 ; ====================================================== DELAY50US:    MOV R0 , #01aH  ;     DELAY50_LOOP:DJNZ R0 , DELAY50_LOOP ; THIS COMMAND WILL BE EXCUTE FOR 31 TIMES,    2period RET ; ====================================================== ; ====================================================== ; SUB FOR DELAY 20US ; RAM USED:R0 ; periods:TOTAL 40PERIODS ; ====================================================== DELAY20:    MOV R0 , #013H  ; RUN 19TIMES 2period     DELAY20_IN:DJNZ R0 , DELAY20_IN ; THIS COMMAND WILL BE EXCUTE FOR 19 TIMES,    2period RET ; ====================================================== ; ====================================================== ; SUB FOR DELAY 5US ; RAM USED:R0 ; periods: ; ====================================================== DELAY5:    MOV R0 , #004H  ; RUN 10TIMES ;2period     DELAY5_IN:DJNZ R0 , DELAY5_IN ; THIS COMMAND WILL BE EXCUTE FOR 4 TIMES,    2period RET ; ====================================================== ; ====================================================== ; SUB FOR DELAY 20US      correct? ; RAM USED:R0 ; periods:TOTAL 40PERIODS ; ====================================================== DELAY20US:    MOV R0 , #00DH  ; RUN 19TIMES 2period     DELAY20US_LOOP:DJNZ R0 , DELAY20US_LOOP ; THIS COMMAND WILL BE EXCUTE FOR 19 TIMES,    2period RET ; ====================================================== ; ====================================================== ; SUB FOR DELAY 50US ; RAM USED:R0 ; PERIODS:100 PERIODS ; ====================================================== DELAY50:    MOV R0 , #0B1H     DELAY50_IN:DJNZ R0 , DELAY50_IN ; RET ; ====================================================== ; ====================================================== ; SUB FOR DELAY 30US ; RAM USED:R0 ; PERIODS:60 PERIODS ; ====================================================== DELAY30:    MOV R0 , #01DH     DELAY30_IN:DJNZ R0 , DELAY30_IN ; RET ; ====================================================== ; ====================================================== ; SUB FOR DELAY 15US ; RAM USED:R0 ; ====================================================== DELAY15:    MOV R0 , #00EH     DELAY15_IN:DJNZ R0 , DELAY15_IN ; RET ; ====================================================== ; ====================================================== ; SUB FOR DELAY 40US ; RAM USED:R0 ; PERIODS:80 PERIODS ; ====================================================== DELAY40:    MOV R0 , #27H     DELAY40_IN:DJNZ R0 , DELAY40_IN ; RET ; ====================================================== ; ====================================================== ; CACULATE THE PARITY OF THE CODE ; RAM CHANGED:A,C,PARITY ; INPUT :SCAN ; RETURN VAR:PARITY ; ====================================================== CALPARITY:    MOV A , SCAN    MOV C , P    CPL C    MOV PARITY , CRET ; ====================================================== ; =================================================================================================================== ENDOFFILE:END  ; END OF THE PROGRAM

    最新回复(0)