⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 实验七(键盘扫描).asm

📁 单片机只是别人的东西
💻 ASM
字号:

;功能:5*4键盘扫描程序

KEYNAME DATA 28H  ;b4~b0位记录按键值
                  ;b7-作为按键值有效标志,b7为0时,表示b4-b0位中的按键值无效。
                  ;b7为1时,表示b4-b0位记录的按键值有效,且未尚未处理,不能
                  ;接受新按键。
		  ;b6-保留。
;外部程序执行了按键功能后,将按键有效标志清0,允许接收新按键
KEYSTU  DATA 2AH  ;键盘按键状态寄存器,其中b2、b1、b0分别记录最近
                  ;三次定时中断的按键状态。

DISPBUF DATA 30H  ;显示缓冲区首地址(30H-33H)

PORTDR  DATA 34H  ;U105(八上升沿D型触发器74HC273)地址内存中的影射地址
                  ;设置影射地址目的是为了在执行键盘扫描过程中不影响
                  ;该输出口高3位(b5~b3)位内容

BTIME   DATA 40H  ;10ms计数单元
DISPB   BIT  00H  ;50ms定时时间到标志

SDI     BIT  P1.2 ;串行数据输入
SCLK    BIT  P3.4 ;串行数据移位脉冲
PCLK    BIT  P3.5 ;并行锁存脉冲

PORTA   EQU 9000H ;8255A口地址
PORTB   EQU 9100H ;8255B口地址
PORTC   EQU 9200H ;8255C口地址
PORTS   EQU 9300H ;8255控制/状态口地址
PORTD   EQU 8800H ;U105(八上升沿D型触发器74HC273)地址


ORG 0000H
LJMP MAIN

ORG 002BH
LJMP CTC2       ;定时/计数器T2中断服务程序入口地址

ORG 0050H
;-----主程序开始-----
PROC MAIN
MAIN:
     MOV SP, #0DFH     ;对于具有256字节内部RAM芯片来说,
                       ;将0E0H-0FFH,共计32字节作为堆栈区
     MOV DPTR, #8000H   ;关闭蜂鸣器
     MOV A, #0FFH
     MOVX @DPTR, A


     ;---复位后,将08H-0FF内部RAM单元清0。
     MOV R7, #248
     MOV R0, #08H
LOOP1:
     MOV @R0, #0
     INC R0
     DJNZ R7, LOOP1

     MOV KEYSTU, #07H 	   ;按键状态初始化为111
     MOV KEYNAME, #1FH	   ;将键盘按键置为1FH(无效)

     ;初始化U107(8255)可编程并行I/O接口芯片的工作方式

     MOV DPTR, #PORTS       ;8255控制/状态口地址
     MOV A, #10011011B      ;A口工作在方式0,输入;B口工作在方式0,输入;
                            ;C口高、低半部暂时定义为输入
     MOVX @DPTR, A          ;送控制字寄存器

     ;将PD4~PD0置为高电平,使U105(74HC273)输出级截止,降低功耗。
     MOV DPTR, #PORTD       ;U105口地址送DPTR
     MOV A, PORTDR          ;读U105口在内存中的映象地址
     ORL  A, #1FH
     MOVX @DPTR, A          ;数据送U105输出口

     ;----初始化定时器T2
;     MOV TH2, #0FCH
;     MOV TL2, #67H          ;初值0DC00送定时器T2
;     MOV RCAP2H, #0FCH
;     MOV RCAP2L, #67H       ;初始化重装初值

     MOV TH2, #0FCH
     MOV TL2, #67H          ;初值0DC00送定时器T2
     MOV RCAP2H, #0FCH
     MOV RCAP2L, #67H       ;初始化重装初值
     MOV T2CON, #00000100B   ;初始化T2工作方式(自动重装初值、定时)
                             ;并启动了T2

     ;-----初始化中断控制器
     SETB ET2                ;允许定时器T2中断
     SETB EA                 ;开中断
     MOV BTIME, #5           ;初值为5(即每50ms检测一次)

LOOP2:
     JNB DISPB, LOOP2        ;50ms定时时间未到
     CLR DISPB
     LCALL KEYCHK            ;每50ms读键盘状态
     ;检查键盘有无输入
     MOV A, KEYNAME
     JNB ACC.7, LOOP2        ;键盘按键无效,就循环等待

     ;按键有效,先将显示缓冲区笔段码左移一个字节
     MOV R0, #DISPBUF        ;显示缓冲区首地址送R0
     MOV R1, #DISPBUF+1      ;显示缓冲区地址送R1
     MOV R7, #3
LOOP3:
     MOV A, @R1
     MOV @R0, A
     INC R0
     INC R1
     DJNZ R7, LOOP3

     MOV A, KEYNAME          ;读按键值
     ANL A, #1FH             ;保留
     MOV KEYNAME, A          ;清除按键处理标志
     CJNE A, #10H, NEXT1
NEXT1:
     JC NEXT2
     ;按下了功能键,键值>=10H,用两位LED来显示
     ANL A, #0F0H
     SWAP A
     MOV DPTR, #LEDTAB       ;0-F字模表首地址送DPTR
     MOVC A, @A+DPTR         ;查表取模
     MOV R1, #DISPBUF+2      ;显示缓冲区地址送R1
     MOV @R1, A              ;字模送显示缓冲区
NEXT2:
     MOV A, KEYNAME          ;读按键值
     ANL A, #0FH             ;保留低4位
     MOV DPTR, #LEDTAB       ;0-F字模表首地址送DPTR
     MOVC A, @A+DPTR         ;查表取模
     MOV R1, #DISPBUF+3      ;显示缓冲区地址送R1
     MOV @R1, A              ;字模送显示缓冲区
     LCALL S_DISP            ;串行显示
     LJMP LOOP2              ;循环等待

END

PROC S_DISP             ;串行输出子程序
S_DISP:
    MOV R0, #DISPBUF    ;显示缓冲区首地址送R0
    MOV R7, #4
LOOP2:
    MOV A, @R0
    MOV R6, #8
LOOP1:
    CLR SCLK
    RLC A
    MOV SDI, C         ;串行数据送SDI引脚
    NOP
    SETB SCLK          ;锁存串行输入数据
    DJNZ R6, LOOP1
    ;取下一显示码
    INC R0
    DJNZ R7, LOOP2
    ;4位笔段码已全部移到串入并出芯片中
    CLR PCLK
    NOP                  ;延迟一个机器周期
    SETB PCLK
    RET
END

;定时/计数器T2中断服务程序
PROC CTC2
CTC2:
     PUSH PSW
     DJNZ  BTIME, EXIT ;溢出次数减1,不为0跳转
     ;溢出次数已经回到0,重新初始化溢出次数
     MOV BTIME, #5
     SETB DISPB         ;置位1秒时间到标志
EXIT:

     CLR TF2             ;清除定时器T2溢出标志
     POP PSW
     RETI
END

PROC KEYCHK            ;键盘检测
KEYCHK:
;---键盘检测-----------
    MOV DPTR, #PORTD         ;U105口地址送DPTR
    MOV A, PORTDR            ;读U105口在内存中的映象地址
    ANL A, #0E0H             ;输出全为低电平的扫描信号
    MOVX @DPTR, A            ;数据送U105输出口,将PD4~PD0置为低电平

    MOV DPTR, #PORTB         ;8255(U107)B口地址送DPTR
    MOVX A, @DPTR            ;读出B口
    ANL A, #0FH              ;屏蔽高4位
    CJNE A, #0FH, NEXT1
    ;等于0F,说明没有按键被按下
    SETB C                   ;将C标志置1
    SJMP NEXT2
NEXT1:
    CLR C                    ;C标志清0
NEXT2:
    MOV A, KEYSTU
    RLC A                    ;左移一位,记录最新的按键状态
    ANL A, #07H              ;保留按键状态
    MOV KEYSTU, A            ;保存按键状态

    ;判别按键状态,决定是否执行按键扫描
    CJNE A, #0, SNEXT1
    ;处于000态,按键未释放,退出(假设一次按键仅视为一次输入)
    SJMP KEXIT
SNEXT1:
    CJNE A, #1, SNEXT2
    ;处于001态, 按键可能刚被释放,不处理
    SJMP KEXIT
SNEXT2:
    CJNE A, #2, SNEXT3
    ;处于010态,干扰,作000态处理
    ANL KEYSTU, #00H
    SJMP KEXIT
SNEXT3:
    CJNE A, #3, SNEXT4
    ;处于011态,按键处于释放状态,退出
    SJMP KEXIT
SNEXT4:
    CJNE A, #4, SNEXT5
    ;处于100态,按键已经稳定闭合,进行按键扫描
    LCALL KEYSCAN               ;执行键盘扫描,确定哪一按键被按下
    SJMP KEXIT
SNEXT5:
    CJNE A, #5, SNEXT6
    ;处于101态, 干扰,作111态处理
    ORL KEYSTU, #07H       ;b2~b0位置1
    SJMP KEXIT
SNEXT6:
    CJNE A, #6, SNEXT7
    ;处于110态,按键刚被按下,未稳定,暂不处理
;    LJMP EXIT
SNEXT7:
    ;处于111态
KEXIT:
    ;将PD4~PD0置为高电平,使74HC273输出级截止,降低功耗。
    MOV DPTR, #PORTD       ;U105口地址送DPTR
    MOV A, PORTDR          ;读U105口在内存中的映象地址
    ORL  A, #1FH
    MOVX @DPTR, A          ;数据送U105输出口
;---键盘检测结束-----------
    RET
END

PROC KEYSCAN                 ;键盘扫描程序
KEYSCAN:
    MOV R7, #5               ;定义扫描次数
    MOV R1, #0               ;初始化列地址
    MOV R3, #01111111B       ;扫描码初值

LOOP1:
    ;生成扫描码
    MOV A, R3
    RL A                     ;左移一位(从PD0开始扫描)
    MOV R3, A                ;保存扫描码
    ANL A, #00011111B        ;保留扫描
    MOV B, A                 ;暂时保存在B寄存器中

    MOV DPTR, #PORTD         ;U105口地址送DPTR
    MOV A, PORTDR            ;读U105口在内存中的映象地址
    ANL A, #0E0H             ;保留与键盘扫描无关的b7~b5位。
    ORL A, B                 ;与扫描或
    MOVX @DPTR, A            ;数据送U105输出口,将PD4~PD0置为低电平
    NOP                      ;延迟一个机器周期等待输出口状态稳定

    MOV DPTR, #PORTB         ;B口地址送DPTR
    MOVX A, @DPTR            ;读B口
    ANL A, #0FH              ;屏蔽高4位
    JB ACC.0, NEXT1
    ;ACC.0位为0,说明0行有按键被按下
    MOV R2, #0               ;行地址为0
    SJMP NEXT5
NEXT1:
    JB ACC.1, NEXT2
    ;ACC.1位为0,说明1行有按键被按下
    MOV R2, #1               ;行地址为1
    SJMP NEXT5
NEXT2:
    JB ACC.2, NEXT3
    ;ACC.2位为0,说明2行有按键被按下
    MOV R2, #2               ;行地址为2
    SJMP NEXT5
NEXT3:
    JB ACC.3, NEXT4
    ;ACC.3位为0,说明3行有按键被按下
    MOV R2, #3               ;行地址为3
    SJMP NEXT5
NEXT4:
    ;说明该列上没有按键被按下
    INC R1                   ;列地址加+1,继续扫描
    DJNZ R7, LOOP1
    ;扫描所有列,均没发现按按键被按下
    SJMP EXIT

NEXT5:
    ;计算行列地址,查表或区
    MOV A, R1
    RL A
    RL A                   ;列地址乘4(每列对应4行)
    ADD A, R2              ;加行地址
    MOV DPTR, #KEYTAB
    MOVC A, @A+DPTR        ;查表获取键值
    MOV KEYNAME, A         ;按键值送键名寄存器中
    ORL KEYNAME, #80H      ;按键有效标志置1
EXIT:
    RET
END

;***********按键扫描码、键值对应关系******************
KEYTAB:
DB 0FH		;扫描码为0,即PD0与PB0交叉点对应数字键"F"
DB 0EH		;扫描码为1,即PD0与PB1交叉点对应数字键"E"
DB 0DH		;扫描码为2,即PD0与PB2交叉点对应数字键"D"
DB 0CH		;扫描码为3,即PD0与PB3交叉点对应数字键"C"

DB 09H		;扫描码为4,即PD1与PB0交叉点对应数字键"9"
DB 06H		;扫描码为5,即PD1与PB1交叉点对应数字键"6"
DB 03H		;扫描码为6,即PD1与PB2交叉点对应数字键"3"
DB 0BH		;扫描码为7,即PD1与PB3交叉点对应数字键"B"

DB 08H		;扫描码为8,即PD2与PB0交叉点对应数字键"8"
DB 05H		;扫描码为9,即PD2与PB1交叉点对应数字键"5"
DB 02H		;扫描码为A,即PD2与PB2交叉点对应数字键"2"
DB 00H		;扫描码为B,即PD2与PB3交叉点对应数字键"0"

DB 07H		;扫描码为C,即PD3与PB0交叉点对应数字键"7"
DB 04H		;扫描码为D,即PD3与PB1交叉点对应数字键"4"
DB 01H		;扫描码为E,即PD3与PB2交叉点对应数字键"1"
DB 0AH		;扫描码为F,即PD3与PB3交叉点对应数字键"A"

DB 13H		;扫描码为10,即PD4与PB0交叉点对应"↑"
DB 12H		;扫描码为11,即PD4与PB1交叉点对应"Enter"
DB 11H		;扫描码为12,即PD4与PB2交叉点对应"ESC"
DB 10H		;扫描码为13,即PD4与PB3交叉点对应"↓"




LEDTAB:                 ;八段LED共阳数码管字模
;数码  0     1     2     3     4     5    6    7
DB     0C0H, 0F9H, 0A4H, 0B0H, 99H, 92H, 82H, 0F8H

;数码  8     9     A     B     C     D     E     F
DB     80H,  90H,  88H, 83H,  0C6H, 0A1H, 86H, 8EH

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -