;---------------------------------------------------------------------------*
;文件名:[KBI.asm]键盘函数定义                                               *
;本文件包含:                                                                *
;    (1)KBinit:初始化键盘控制及中断的相关寄存器                             *
;    (2)KBscan1:一次扫描4*4键盘,读取键值->A                                 *
;    (3)KBscanN:多次扫描键盘,消除"抖动"                                     *
;    (3)KBdef:键值转为定义值                                                *
;硬件连接:                                                                  *
;    PTD7,3,2及PTG4接键盘4根列线,PTG3-0接键盘4根行线                        *
;    如果键盘插在实验板的上排插孔,无须连线                                  *
;---------------------------------------------------------------------------*
   INCLUDE 'MC9S08AW60.inc'
   
   ;键盘控制引脚定义
KB_DP:   equ    PTDD         ;键盘接在PTD及PTG口上
KB_DD:   equ    PTDDD        ;相应的方向寄存器
KB_GP:   equ    PTGD         ;键盘接在PTD及PTG口上
KB_GD:   equ    PTGDD        ;相应的方向寄存器
KB_DPUE: equ    PTDPE        ;相应的上拉电阻允许寄存器
KB_GPUE: equ    PTGPE        ;相应的上拉电阻允许寄存器
   
   XDEF  EnableKBint          ;允许键盘中断
   XDEF  DisableKBint         ;禁止键盘中断
   XDEF  KBIInit              ;键盘初始化
   XDEF  KBscanN              ;多次扫描键值
   XDEF  KBscan1              ;一次扫描键值
   XDEF  KBdef                ;键值转换
;允许键盘中断----------------------------------------------------------------
EnableKBint:
     BSET 1,KBI1SC    
 RTS

;禁止键盘中断----------------------------------------------------------------
DisableKBint:
   BCLR 1,KBI1SC   
 RTS
;---------------------------------------------------------------------------*
;函 数 名:KBinit:键盘初始化子程序                                           *
;功    能:初始化键盘控制及中断的相关寄存器,但未开放键盘中断                 *
;入    口:无                                                                *
;出    口:无                                                                *
;堆栈深度:2 + 1 = 3                                                         *
;---------------------------------------------------------------------------*
KBIInit:
    PSHA                  ;A进栈(保护寄存器A)
    LDA  #$00             ;复位相应寄存器
    STA  KB_DP             
    LDA  #$00             ;定义列线(7-4位)为输入
    STA  KB_DD
    LDA  #$00             ;复位相应寄存器
    STA  KB_GP
    LDA  #$0F             ;行线(3-0位)为输出
    STA  KB_GD
    LDA  #%10001100       ;输入引脚(列线)有内部上拉电阻
    STA  KB_DPUE
    LDA  #%00010000
    STA  KB_GPUE
    JSR  DisableKBint     ;屏蔽键盘中断(KBIE = 0)
    LDA  #%11110000       ;允许输入引脚的中断可进入
    STA  KBI1PE
    BSET 2,KBI1SC        ;清除键盘中断请求(KBACK = 1)
    PULA                  ;A出栈(恢复寄存器A)
   RTS
;---------------------------------------------------------------------------*
;函 数 名:KBscanN:多次扫描键盘,返回读取的键值                               *
;功    能:多次扫描键盘，消除"抖动"                                          *
;入    口:A = 扫描次数N                                                     *
;出    口:A = 多次扫描键盘得到的键值,如不稳A = 0xFF                         *
;内部调用:KBscan1                                                           *
;堆栈深度:4                                                                 *
;---------------------------------------------------------------------------*
KBscanN:
    PSHX          ;保护寄存器X
    AIS   #-1     ;[SP + 1]中存放上一次扫描值
    DECA 
    TAX           ;X中存放需多次扫描时的循环次数(N - 1)
    CMP   #1
    BHI   KBscanN_1    ;N > 1,转到KBscanN_1处执行
    JSR   KBscan1      ;N <= 1,调扫描4*4键盘1次子程序
    BRA   KBscanN_EXIT ;并退出 
KBscanN_1:
    JSR   KBscan1      ;初始扫描一次键盘   
KBscanN_2:    
    STA   1, SP        ;前一次扫描值存入[SP + 1]    
    JSR   KBscan1      ;当前扫描值在A中
    CBEQ  1, SP, KBscanN_EXIT   ;若当前扫描值与前一次相同
                                ;取当前值,并退出
    DBNZX KBscanN_2    ;若不同,且循环未结束则继续扫描 
    LDA   #$FF         ;若不同,且循环结束,带回$FF 
KBscanN_EXIT:                 
    AIS   #1          ;释放临时变量
    PULX              ;恢复寄存器X 
    RTS    
;---------------------------------------------------------------------------*
;函 数 名:KBscan1:扫描读取键值子程序                                        *
;功    能:扫描4*4键盘,读取键值->A,若无按键,$FF->A                           *
;入    口:无                                                                *
;出    口:A = 键值                                                          *
;堆栈深度:2 + 2 = 5                                                         *
;---------------------------------------------------------------------------*
KBscan1:
    AIS   #-5           ;开辟临时变量
KBscan1_1:
    LDA   #%11111110    ;使第一根行线为0(低电平)
    STA   1,SP
    LDA   #$04          ;最多将扫描4根行线
    STA   2,SP
KBscan1_2:
    ;当前扫描的一行,输出低电平
    LDA   #%11111110 
    STA   KB_GP
    ;等待键按下
    NOP
    NOP
    ;读取键盘口数据值
    LDA   KB_DP          ;temp1=KB_DP
    STA   3,SP
    LDA   KB_GP          ;temp2=KB_GP
    STA   4,SP
    ;整合为8位
    LDA   3,SP
    AND   #$80           ;temp=temp1&0x80
    STA   5,SP
    LDA   3,SP           ;temp1 & =0x0c
    AND   #$0c
    ASLA                 ;temp1=(temp1<<3)
    ASLA
    ASLA
    STA   3,SP
    LDA   5,SP           ;temp |=temp1
    ORA   3,SP
    STA   5,SP
    LDA   4,SP           ;temp2 &=0x1f
    AND   #$1f
    STA   4,SP
    LDA   5,SP           ;temp |=temp2
    ORA   4,SP
    STA   5,SP
    ;通过观察4根列线中是否出现低电平来判断当前行有无按键,通过观察4根列线中
    ;是否出现低电平来判断当前行有无按键
    AND   #%11110000    
    CBEQA #$F0,KBscan1_3    ;当前行无按键,转KBScan_3
    ;当前行有按键
    BRA   KBscan1_Exit
KBscan1_3:
    ;准备扫描下一行
    SEC                    ;C=1
    LDA   1,SP
    ROLA                   ;使下一根行线输出低电平
    ORA   #$01
    STA   1,SP
    DBNZ  2,SP,KBscan1_2    ;没有扫到按键且没有扫完4行
    ;4行扫完仍未扫到按键(认为无按键)
    LDA   #$FF
KBscan1_Exit:
    AIS   #5              ;释放临时变量
 RTS
;---------------------------------------------------------------------------*
;函 数 名:KBdef:键值转为定义值子程序                                        *
;功    能:键值转为键盘定义值                                                *
;入    口:A = 键值                                                          *
;出    口:A = 键定义值                                                      *
;堆栈深度:2 + 3 = 5                                                         *
;---------------------------------------------------------------------------*
KBdef:
    PSHH             ;HX进栈(保护寄存器HX)
    PSHX
    AIS #-1          ;开辟临时变量
    STA 1,SP         ;键值存入[SP+1]
    LDHX #KBtable    ;取键盘定义表首地址
KBdef_1:
    ;在键盘定义表中搜索欲转换的键值,直至表尾($00)
    LDA  ,X
    CMP  #$00
    BEQ  KBdef_3     ;表已搜完,表中无对应的键值定义
    ;表未搜完
    CMP  1,SP        ;表中当前键值与欲转换键值相比较
    BNE  KBdef_2     ;未找到对应键值,转KBDef_2
    ;找到对应键值
    AIX  #1          ;取相应定义值->A,并完成转换
    LDA  ,X
    BRA  KBdef_Exit
KBdef_2:
    AIX #2           ;指向下一个表中键值
    BRA  KBdef_1     ;继续判断
KBdef_3:
    LDA  #$FF        ;表中无对应的键值定义$FF->A
KBdef_Exit:
    AIS  #1          ;释放临时变量
    PULX             ;HX出栈(恢复寄存器HX)
    PULH 
 RTS

;键盘定义表
KBtable: 
    DC.B $EE,'1',$DE,'2',$BE,'3',$7E,'A'
    DC.B $ED,'4',$DD,'5',$BD,'6',$7D,'B'
    DC.B $EB,'7',$DB,'8',$BB,'9',$7B,'C'
    DC.B $E7,'*',$D7,'0',$B7,'#',$77,'D'
    DC.B $00