在单片机开发领域,掌握基础的输入输出控制是迈向复杂项目的关键一步。本次实验聚焦于利用单片机开发板,通过矩阵键盘实现学号后 8 位的输入与数码管显示,旨在掌握数码管显示、软件延时以及键盘扫描及去抖动等核心方法。接下来,就带大家深入剖析实验的全过程。
一、实验目的与内容
本次实验有着明确的目标,即熟练掌握数码管显示方法、软件延时方法以及键盘扫描及去抖动方法。围绕这些目标,实验内容具体为:利用单片机开发板的矩阵键盘,实现个人学号后 8 位的输入和显示;通过矩阵键盘 S1 - S10 输入数字 1 - 0;借助数码管 LED8 - LED1 从左到右显示 8 位学号。
二、实验设计与实现
(一)整体思路
实验采用模块化设计理念,将整个功能拆解为显示、键盘输入检测和计算三个模块。首先,键盘输入检测模块负责扫描确定输入的键码;接着,计算模块依据键码计算出要显示的数字;最后,显示模块完成数字在数码管上的呈现,各模块协同工作实现整体功能。
(二)流程图
- 整体设计思路:从程序启动开始,先进行初始化操作,随后进入键盘检测循环。一旦检测到按键输入,就调用计算模块处理键码,再将处理后的数字传递给显示模块进行显示,如此循环往复,构成完整的程序逻辑。
- 显示模块:利用数码管动态显示法,通过 R3 寄存器存放 LED 灯的位选码,从最高位开始逐次递减,实现动态扫描。同时,借助间接寻址 R1 寄存器获取对应数字,完成一轮显示后重新初始化相关寄存器,开启下一轮显示。
- 键盘检测模块:先对整个键盘进行检测,若检测到输入则调用防抖程序后再次检测,确认有按键按下后,通过行列扫描确定按键的行列号。
- 计算模块:获取按键的行列号后进行加法运算,将结果保存在栈中,等待按键松开后,将键码存入指定地址区域,并记录数字个数,达到 8 个后重置数据。
(三)主要模块设计思路及分析
- 显示模块
设计思路上,运用数码管动态显示法,通过 R3 寄存器控制 LED 灯的位选,从高位到低位逐次切换,配合 R1 寄存器间接寻址获取对应数字的段码,实现数字在数码管上的动态显示。
DISPLAY:
;显示位码的选择
MOV A, R3
MOV P2, A
ADD A, #-04H
MOV R3, A
;数字的输入
MOV A, @R1 ;间接读取键码
MOVC A, @A+DPTR
MOV P0, A
INC R1
LCALL D1 ;调用延时
CJNE R3, #0FCH, DISPLAY ;判断八位数字是否显示完毕
;显示一轮完成后开启新的一轮循环
MOV R3, #1CH
MOV R1, #30H
RET
代码中,首先将 R3 中的位选码赋值给 A 并送到 P2 口,控制数码管的位选;然后通过 ADD 指令改变位选码,实现从高位到低位的切换。接着,通过间接寻址从内存中获取数字,再根据数字从段码表中获取对应的段码,送到 P0 口显示。最后,通过调用延时函数和条件判断,完成一轮显示后重新初始化相关寄存器。
- 检测模块
检测模块先对键盘进行整体检测,发现有输入后调用防抖程序,再次确认后通过行列扫描确定按键位置。
KEY:
LCALL KS
JNZ K1 ;键盘有输入跳转K1
LCALL DISPLAY ;延时
AJMP KEY ;延时后重新检测
K1:
LCALL DISPLAY ;按键去抖
LCALL KS ;再次调用检测子程序
JNZ K2 ;确认有键盘按下转入k2检测
AJMP KEY ;无按键按下则返回继续检测
K2:
MOV R2, #0F7H ;列扫描值确定
MOV R4, #00H ;将第0列号送入R4暂存
K3:
MOV P1, R2 ;将R2的列扫描值送P1口,驱动P1.3为低
;检测行,A中存放行号
;检测第一行
L0:
JB P1.7, L1
MOV A, #00H
AJMP LK
;检测第二行
L1:
JB P1.6, L2
MOV A, #04H
AJMP LK
;检测第三行
L2:
JB P1.5, L3
MOV A, #08H
AJMP LK
;检测第四行
L3:
JB P1.4, NEXT
MOV A, #0CH
在这段代码里,KEY 处先调用 KS 检测是否有按键按下,若有则进行去抖和再次检测。确认有按键后,通过设置 R2 和 R4 进行列扫描,对每一行进行检测,根据 P1 口的状态确定行号,从而获取按键的行列信息。
- 计算模块
计算模块将获取到的行列号相加,计算出键码,存入指定地址,并处理数字个数达到 8 个时的重置操作。
LK:
ADD A, R4
PUSH ACC
AJMP K4
NEXT:
INC R4 ;列计数器加一
MOV A, R2
JNB ACC.0, KEY ;判断是否扫描完
RR A ;右移扫描码进行下行扫描
MOV R2, A
AJMP K3
K4:
LCALL DISPLAY ;调用显示子程序
LCALL KS ;调用按键检测程序
JNZ K4 ;按键没有松开继续返回检测
POP ACC ;按键松开,将堆栈中的键号送入ACC
INC A ;实际键号加一(表首地址为0)
MOV @R0, A ;将键号保存至保存地址
INC R0 ;地址加一
LCALL DISPLAY ;调用显示子程序
CJNE R0, #39H, KEY ;判断是否已经读取了八个数字
RESET:
DEC R0
MOV @R0, #00H ;地址数字初始化
CJNE R0, #30H, RESET ;判断是否初始化完毕
LJMP KEY ;跳转至KEY重新检测
LK 处将行列号相加后入栈,等待按键松开。按键松开后,将键码出栈并处理,存入 R0 指向的地址,同时地址自增。当输入数字达到 8 个时,进入 RESET 部分进行数据重置,以便重新输入。
三、实现效果
经过代码编写与调试,成功实现了通过矩阵键盘 S1 - S10 输入数字 1 - 0,并在数码管 LED8 - LED1 上从左到右显示 8 位学号的功能。无论是单个数字的输入显示,还是完整学号的录入展示,都能稳定、准确地呈现,达到了预期的实验效果。
四、实验总结
在本次实验过程中,遇到了诸如理解代码逻辑和硬件连接等问题。但通过查阅资料、反复调试和实践,逐步攻克了这些难关。通过这次实验,对 8051 微控制器编程有了更深入的理解,编程和硬件调试技能得到了显著提升。同时,也深刻认识到调试工具在排查问题中的重要性,以及代码注释和模块化设计对于程序可读性和可维护性的关键意义。未来,可以通过增加更详细的注释、优化延时处理算法以及增强用户交互功能,进一步提升程序的健壮性和友好性。
最后附上完整的实验源代码,方便大家参考学习:
ORG 0000H
AJMP MAIN
ORG 0100H
MAIN:
MOV R0, #30H ;片内的30H用于存放各个位的键码
MOV R1, #30H ;读取数字地址
MOV R3, #1CH ;R3存放显示位选码
MOV DPTR, #TAB
AJMP KEY
;显示模块
DISPLAY:
;显示位码的选择
MOV A, R3
MOV P2, A
ADD A, #-04H
MOV R3, A
;数字的输入
MOV A, @R1 ;间接读取键码
MOVC A, @A+DPTR
MOV P0, A
INC R1
LCALL D1 ;调用延时
CJNE R3, #0FCH, DISPLAY ;判断八位数字是否显示完毕
;显示一轮完成后开启新的一轮循环
MOV R3, #1CH
MOV R1, #30H
RET
;检测模块
KEY:
LCALL KS
JNZ K1 ;键盘有输入跳转K1
LCALL DISPLAY ;延时
AJMP KEY ;延时后重新检测
K1:
LCALL DISPLAY ;按键去抖
LCALL KS ;再次调用检测子程序
JNZ K2 ;确认有键盘按下转入k2检测
AJMP KEY ;无按键按下则返回继续检测
K2:
MOV R2, #0F7H ;列扫描值确定
MOV R4, #00H ;将第0列号送入R4暂存
K3:
MOV P1, R2 ;将R2的列扫描值送P1口,驱动P1.3为低
;检测行,A中存放行号
;检测第一行
L0:
JB P1.7, L1
MOV A, #00H
AJMP LK
;检测第二行
L1:
JB P1.6, L2
MOV A, #04H
AJMP LK
;检测第三行
L2:
JB P1.5, L3
MOV A, #08H
AJMP LK
;检测第四行
L3:
JB P1.4, NEXT
MOV A, #0CH
;计算模块,计算键码
LK:
ADD A, R4
PUSH ACC
AJMP K4
;检测完一列,换列
;R4寄存器存放列数
NEXT:
INC R4 ;列计数器加一
MOV A, R2
JNB ACC.0, KEY ;判断是否扫描完
RR A ;右移扫描码进行下行扫描
MOV R2, A
AJMP K3
;去长按模块
K4:
LCALL DISPLAY ;调用显示子程序
LCALL KS ;调用按键检测程序
JNZ K4 ;按键没有松开继续返回检测
POP ACC ;按键松开,将堆栈中的键号送入ACC
INC A ;实际键号加一(表首地址为0)
MOV @R0, A ;将键号保存至保存地址
INC R0 ;地址加一
LCALL DISPLAY ;调用显示子程序
CJNE R0, #39H, KEY ;判断是否已经读取了八个数字
;重置模块
RESET:
DEC R0
MOV @R0, #00H ;地址数字初始化
CJNE R0, #30H, RESET ;判断是否初始化完毕
LJMP KEY ;跳转至KEY重新检测
KS:
MOV P1, #0F0H ;按键检测,将P1口低四位置0,高四位置1,为输入
MOV A, P1 ;读入P1口高四位,即读行线的状态
XRL A, #0F0H ;将两次行线的状态相异或,若无按下,则A=0
RET
D1: ;延时子程序(显示延时)
MOV R7, #20
D10: MOV R6, #20
DJNZ R6, $
DJNZ R7, D10
RET
TAB: DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H,7FH,6FH ;表记录显示段码
DB 3FH
END
希望通过这篇博文,能让大家对单片机矩阵键盘与数码管显示实验有更清晰的认识。如果你在实践过程中有任何疑问或新的想法,欢迎在评论区交流分享!