数码管显示与按键输入技术.docx
《数码管显示与按键输入技术.docx》由会员分享,可在线阅读,更多相关《数码管显示与按键输入技术.docx(18页珍藏版)》请在冰豆网上搜索。
数码管显示与按键输入技术
第七讲数码管显示与按键输入技术
郧阳师专电工电子实验教学中心艾庆生
单片机与个人微机(PC机)间的最大区别就是:
它追求“小而全”,只有简单的输入和输出部件。
而数码管和按键就是这样的即简单又常用又重要的部件,我们必须熟练掌握。
一、数码管的结构
LED(LightEmittingDiode)数码管
如图所示:
7只或8只发光二极管构成一位数码管,俗称“7段8”或“8段8”,我们以8段8为例来讲解:
若8只发光管的阳极接在一起引出的话,称之为共阳极数码管;反之,8只发光管的阴极接在一起引出的话,称之为共阴极数码管。
使用时,数码管各段必须接限流电阻。
数码管的各段有统一的规定,用a、b、…、g、dot定义。
二、数码管的显示代码
由于数码管各段排列的特殊性,它所显示的字符与送给它的代码是不一样的。
以共阴极数码管为例,如,送给它代码3FH,将显示字符“0”,送代码06H,将显示字符“1”,…。
下表列出了共阴和共阳数码管所显示字符的代码表。
图二则告诉了如何得到显示代码的方法。
三、数码管的显示技术
1.静态显示
在任意时刻,每位数码管都有电流流过。
如图3所示,有8位数码管,显示“07-05-12”,每位数码管都有8根引线与专门电路相连,向其提供“段选码”。
它的显示是同时的、稳定的。
其优点是原理简单、编程较易;缺点是引线太多、耗电太大。
2.动态显示
参考图4,仍是8位数码管,但它们各自的8根引线并联在一起引出,所以,无论是几位数码管显示,总共只有8根“段选码”引出线;每位数码管的公共端单独引出,构成了8根“位选码”的引出线。
其工作原理如下:
设从右往左显示,首先送2的显示代码(即段选码),然后将com0变为低电平,其它为高电平(即位选码),延时1-2ms;其次送1的显示代码,再将com1变为低电平,仍延时1-2ms;以此类推,当最左边数码管的0显示完毕后,这称为扫描了一遍,共需时8-16ms;不断地重复此过程,就叫“动态显示”技术。
可知,1秒钟能扫描50到100多遍,由于视觉暂留缘故,我们就看到了稳定的显示。
它的优点显而易见,引线数大为减少,省电(任意时刻,仅有一位数码管在显示),只是编程稍麻烦一点,但其难度仅为1课时的学习而已。
四、数码管的编程
;************************************************************
;*************数码管显示一遍子程序*********************
;************************************************************
;设数据显示区从78H-7FH,与8位数码管一一对应
;单片机P0口接数码管的段选口;P2口接数码管的位选口
smg_disp:
movdptr,#disp_tab;指向显示代码表
movr0,#78h;指向数据显示区
movr7,#0feh;显示模式(即“位选码”)
disp_loop:
mova,@r0;取一个数据
movca,@a+dptr;转换成显示代码
movp0,a;送P0口(“段选码”)
mova,r7;取显示模式
movp2,a;送P2口(“位选码”)
incr0;指向下一数据
rla;移向下一位
movr7,a;并保存
lcallys1ms
cjnea,#0feh,disp_loop;扫描一遍了吗?
Ret
;延时1ms子程序
ys1ms:
movr6,#2
ys0:
movr5,#250
djnzr5,$
djnzr6,ys0
ret
;数据区数据显示代码表
disp_tab:
db3fh,06h,5bh,4fh,66h,6dh,7dh,07h,7fh
db6fh,77h,7ch,39h,5eh,79h,71h,76h,73h
db40h,80h
;思考题:
1.若从左往右显示,怎样修改以上程序?
;2.若只显示两位(任意选取,如最右边两位),怎样改?
;3.若编写“跑马灯”程序,怎样修改?
;************************************************************
五、简单按键的输入法
按键作为一种简单的输入器件,其实牵涉到它的技术却是不简单的。
有这样几个问题需要解决。
即1.单片机的并行口为准双向口,故输入时是有限制的,须先向该口写“1”;2.要考虑按键的抖动问题,硬件的解决办法是另外用“触发器”;软件的解决办法是延时若干ms,待按键稳定下来;3.对按键进行处理,判断是功能键还是数字键,具体键值是多少?
是单个按键值输入还是连续按键值输入?
4.按键松开没有,是否等待按键释放?
这些问题在编程时都必须考虑!
下图,是我们的单片机最小系统里简单按键的连接图。
当把跳线JMP1上的短路帽插上时,可以做外部中断的扩展实验(见下讲)。
实验1:
4按键的识别实验1
为简单起见,我们将按键情况用P0口的发光管直接显现出来(求反后送)。
;************************************************************
;*******************四按键识别实验1*********************
;************************************************************
Org0000H
Main:
movp0,#0H;关闭P0口8只发光管
Movp3,#0ffH;为读入P3口的按键做准备
Loop:
mova,p3;读入P3口状态送A寄存器
Cpla;求反,因P0口发光管高电平点亮
Movp0,a;将按键情况送P0口显示
Sjmploop
End
;***********************************************************
实验2:
4按键的识别实验2
用上边刚学到的数码管知识,这次我们将识别后的按键引脚号直接送数码管显示,如显示“P3.5”。
;************************************************************
;******************四按键识别实验2********************
;************************************************************
;主程序
Org0000H
Main:
mov78h,#18
Mov79h,#18
Mov7ah,#18
Mov7bh,#18;没有按键按下时,首先显示“――――”
Loop:
lcallsmg_disp;调用数码管显示子程序(只显示4位)
Lcallkey_check;调用按键检查子程序
Sjmploop
;按键检查子程序
Key_check:
movp3,#0ffh;为读入P3口内容做准备
Mova,p3;读入P3口内容到A
Cpla
Jnzkey_value;有键按下跳去处理
Key_end:
Ret
Key_value:
lcallsmg_disp
lcallsmg_disp;数码管显示两遍,延时若干ms抗干扰
Mova,p3;再次读入P3口内容到A
Cpla
Jzkey_end;无键按下返回
Jbacc.4,key_p34;判是P3.4脚接的按键吗?
Jbacc.5,key_p35;判是P3.5脚接的按键吗?
Jbacc.6,key_p36;判是P3.6脚接的按键吗?
Jbacc.7,key_p37;判是P3.7脚接的按键吗?
Sjmpkey_end
Key_p34:
mov78h,#4
Mov79h,#19;送小数点的查表值
Mov7ah,#3
Mov7bh,#17;送P的查表值
Sjmpkey_wait
Key_p35:
mov78h,#5
Mov79h,#19;送小数点的查表值
Mov7ah,#3
Mov7bh,#17;送P的查表值
Sjmpkey_wait
Key_p36:
mov78h,#6
Mov79h,#19;送小数点的查表值
Mov7ah,#3
Mov7bh,#17;送P的查表值
Sjmpkey_wait
Key_p37:
mov78h,#7
Mov79h,#19;送小数点的查表值
Mov7ah,#3
Mov7bh,#17;送P的查表值
Key_wait:
lcallsmg_disp;等候按键释放并保持数码管的显示不
;断续
movp3,#0ffh
Mova,p3;再次读入P3口内容到A
Cpla
Jnzkey_wait;等候按键释放
Ret
End
;此处省略了两个子程序(即数码管显示子程序和1ms延时子程序)以及显
;示代码表,调试程序时请添加上,另外需修改数码管显示子程序为右边
;4位显示。
;请认真体会程序里是如何抗按键抖动的、如何判断键值的、如何等候按键
;释放的?
;************************************************************
六、矩阵键盘的扫描法
简单按键的连接容易,程序的编写也较容易,但它的缺点是占用引脚资源过多,若采用矩阵式键盘,则16个按键只需8根引线,或64个按键只需16根引线。
显然,它的优点就是引线少,编程复杂一些。
对于矩阵式键盘,一般分两步来处理。
第一步:
扫描键盘,判断有无按键按下;第二步:
在有按键按下的情况下,确定是何键?
即键值判断。
图6是矩阵式键盘的示意图,为简单起见,我们假定P1口和P3口作为矩阵式键盘的行线和列线的连接口。
可见,它们的交叉点共有64个,可接64个按键。
判断有无按键按下,采用扫描法,其基本方法是:
将行线(或列线)置为低电平,然后读回列线(或行线)的值,显然,若无按键按下,读回的值应全部为高电平,否则,就一定会有低电平(被按键拉低的缘故)。
;************************************************************
;****************矩阵键盘扫描子程序*****************
;************************************************************
Key_scan:
Movp1,#0;将行线置为低电平
Movp3,#0ffh;为读入列线的值做准备
Nop
Mova,p3;读入列线的值到A寄存器
Cpla;目的以A是否为0来作判断,
Ret;便于使用指令JZ或JNZ。
;返回值在A寄存器里,若不为0则一定有按键按下。
;思考题:
为什么要将A取反?
好处在哪里?
;************************************************************
上图为实际的按键接线图。
上边的扫描子程序同样适用于此接线图。
七、矩阵键盘的键值识别法(以图7为例)
1.传统识别法(逐行扫描法):
行线输出,列线输入。
行线逐行输出0,将列线读回。
若该行有按键按下,则列线输入有0;若无按键按下,列线输入全部为1。
程序流程图如下:
参考程序如下,需说明的是这样编程较复杂。
Key_Value:
Lcallsmg_disp
Lcallsmg_disp;延时16ms以抗抖动
Lcallkey_scan;再次检查按键情况
jnzkey_H;有键按下则跳转处理
LjmpKey_ret;无键按下返回
Key_H:
movp1,#0feh;第1排行线置0
movp3,#0ffh;为读入P3列线情况先置“1”
mova,p3
cpla
jnzvalue_0;是第一排按键吗?
是跳转至Value_0
movp1,#0fdh
mova,p3
cpla
jnzvalue_4;是第二排按键吗?
是跳转至Value_4
movp1,#0fbh
mova,p3
cpla
jnzvalue_8;是第三排按键吗?
是跳转至Value_8
movp1,#0f7h
mova,p3
cpla
jnzvalue_C;是第四排按键吗?
是跳转至Value_C
LjmpKey_ret
Value_0:
movr4,#00h;赋行首键值0
ajmpKey_V
Value_4:
movr4,#04h;赋行首键值4
ajmpKey_V
Value_8:
movr4,#08h;赋行首键值8
ajmpKey_V
Value_C:
movr4,#0Ch;赋行首键值C
Key_V:
jbacc.0,V_0;是第一列按键吗?
是跳至V_0
jbacc.1,V_1;是第二列按键吗?
是跳至V_1
jbacc.2,V_2;是第三列按键吗?
是跳至V_2
jbacc.3,V_3;是第四列按键吗?
是跳至V_3
LjmpKey_ret
V_0:
mova,#0;赋列号0
ajmpkey_add
V_1:
mova,#1;赋列号1
ajmpkey_add
V_2:
mova,#2;赋列号2
ajmpkey_add
V_3:
mova,#3;赋列号3
Key_add:
adda,r4;“行首键值+列号值”送A
movr0,#78h
Exchange:
xcha,@r0;键值送显示区,整个显示区数据前移
;一字节
incr0
cjner0,#80h,exchange
Wait:
acallsmg_disp
acallkey_scan
jnzwait;等候按键释放
Key_ret:
ret
2.行列反转法
可用行、列交换法结合查表法迅速获得键值。
行列线交换输入、输出,两步获取按键键值。
;************************************************************
;键值判断子程序(要克服按键抖动、要使数码管显示无闪烁、
;要正确读出键值、要等候按键松开。
。
。
)
Key_Value:
lcallsmg_disp
lcallsmg_disp;延时16ms抗按键抖动
lcallkey_scan;再次判断是否按键按下?
jnzrd_value;有则去读值
ljmpkey_ret
;以下采用两次交叉键盘扫描方法,通过查表唯一确定键值
rd_value:
movp1,#0ffh
movp3,#0f0h;首先将列线置0,读回行线值
nop
mova,p1
cpla
movdptr,#H_tab
movca,@a+dptr;查表获得“行首键值”
movb,a;暂存第一次扫描的“行首键值”
movp3,#0ffh
movp1,#0f0h;其次将行线置0,读回列线值
nop
mova,p3
cpla
movdptr,#V_tab
movca,@a+dptr;查表得到第二次扫描的“列线号值”
adda,b;“行首键值+列线号值”=键值
movr0,#78h
xch_data:
xcha,@r0;保存键值到显示数据区
incr0
cjner0,#80h,xch_data;将数据区字节逐字节上移movp1,#0ffh
wait:
lcallsmg_disp
lcallkey_scan
jnzwait;等待按键释放
Key_ret:
ret
思考题:
1.“行首键值”转换表是如何得到的?
2.“列线号值”转换表是如何得到的?
3.转换表里的16是何含义?
可否用别的数据?
;************************************************************
;“行首键值”转换表
H_tab:
db16,0,4,16,8,16,16,16,12,16,16,16,16,16,16,16
;************************************************************
;“列线号值”转换表
V_tab:
db16,0,1,16,2,16,16,16,3,16,16,16,16,16,16,16
;************************************************************
;数据区数据显示代码表
disp_tab:
db3fh,06h,5bh,4fh,66h,6dh,7dh,07h,7fh
db6fh,77h,7ch,39h,5eh,79h,71h,40h,40h
db40h,40h,40h,40h,40h,40h,40h,40h,40h
db40h,40h,40h,40h,40h,40h,40h,40h,40h
;************************************************************
八、数码管和键盘的联合实验
该实验的任务是:
1.数码管动态扫描显示;
2.对矩阵式按键进行扫描,判断有无按键按下。
若有按键按下,则判断键值并送显示区,实现“计算器式”输入显示。
无输入位数限制。
;************************************************************
;这是数码管显示与键盘输入程序
;主程序
org0000h
main:
movr0,#30h
mova,#0
ram_0:
mov@r0,a
incr0
cjner0,#80h,ram_0;数据区30H-7FH清0
main_loop:
lcallsmg_disp;调数码管显示一遍子程序
lcallkey_scan;调键盘扫描一遍子程序
jzmain_loop;无键按下返回
lcallkey_value;调键值判断子程序
ljmpmain_loop
;************************************************************
;数码管显示一遍子程序
smg_disp:
movdptr,#disp_tab;指向显示代码表
movr0,#78h;指向数据显示区
movr7,#0feh;显示模式(即“位选码”)
disp_loop:
mova,@r0;取一个数据
movca,@a+dptr;转换成显示代码
movp0,a;送P0口(“段选码”)
mova,r7;取显示模式
movp2,a;送P2口(“位选码”)
lcallys1ms
incr0;指向下一数据
rla;移向下一位
movr7,a;并保存
cjnea,#0feh,disp_loop;扫描一遍了吗?
ret
;思考题:
1.若从左往右显示,怎样修改以上程序?
;2.若只显示两位(任意选取,如最右边两位),怎样改?
;3.若编写“跑马灯”程序,怎样修改?
;************************************************************
;键盘扫描一遍子程序(仅仅判断有无按键按下!
)
key_scan:
movp1,#0f0h;将键盘的4根行线变低电平
movp3,#0ffh
nop
mova,p3;读回P3口的值送a
cpla;取反返回
movp1,#0ffh
ret
;************************************************************
;键值判断子程序(要克服按键抖动、要使数码管显示无闪烁、
;要正确读出键值、要等候按键松开。
。
。
)
key_value:
lcallsmg_disp
lcallsmg_disp;延时16ms抗按键抖动
lcallkey_scan;再次判断是否按键按下?
jnzrd_value;有则去读值
ljmpkey_ret
;以下采用两次交叉键盘扫描方法,通过查表唯一确定键值
rd_value:
movp1,#0ffh
movp3,#0f0h;首先将列线置0,读回行线值
nop
mova,p1
cpla
movdptr,#H_tab
movca,@a+dptr;查表获得“行首键值”
movb,a;暂存第一次扫描的“行首键值”
movp3,#0ffh
movp1,#0f0h;再将行线置0,读回列线值
nop
mova,p3
cpla
movdptr,#V_tab
movca,@a+dptr;得到第二次扫描的“列线号值”
adda,b;“行首键值+列线号值”=键值
movr0,#78h
xch_data:
xcha,@r0;保存键值到显示数据区
incr0
cjner0,#80h,xch_data;将数据区字节逐字节上移
movp1,#0ffh
wait:
lcallsmg_disp
lcallkey_scan
jnzwait;等待按键松开
Key_ret:
ret
;************************************************************
;延时1ms子程序
ys1ms:
movr6,#2
ys0:
movr5,#250
djnzr5,$
djnzr6,ys0
ret
;************************************************************
;“行首键值”转换表
H_tab:
db16,0,4,16,8,16,16,16,12,16,16,16,1