第4章 键盘输入与中断.docx
- 文档编号:12891746
- 上传时间:2023-04-22
- 格式:DOCX
- 页数:68
- 大小:1.25MB
第4章 键盘输入与中断.docx
《第4章 键盘输入与中断.docx》由会员分享,可在线阅读,更多相关《第4章 键盘输入与中断.docx(68页珍藏版)》请在冰豆网上搜索。
第4章键盘输入与中断
第4章键盘输入及中断
4.1概述
键盘是计算机最基本、最重要的输入设备之一,作为微型计算机,单片机也不例外。
键盘的工作任务大体可分为以下三项:
①按键识别,即判断有无按键按下;②求键值,即在确认有按键按下时,具体判断是哪个按键被按下,并求得相应的键值;③执行操作,即依据键值,执行对应的操作或任务。
键盘可分为编码键盘和非编码键盘两大类。
我们熟悉的台式计算机或笔记本电脑使用的键盘属于编码键盘,它由多个按键与专用驱动芯片组合而成,其按键识别和键值的获得,全部依靠硬件来完成。
而单片机应用系统中使用的键盘,绝大多数属于非编码键盘,其按键与单片机直接连接,而按键识别和键值的获得,必须通过单片机的软件来完成。
图4-1是单片机应用系统中经常使用的非编码键盘的实物图,其中图(a)是一个按钮,在单片机术语中被称为“独立按键”;图(b)是将16个独立按键排成4行4列的矩阵形式,在单片机的术语中被称为行列式键盘或矩阵键盘。
本章重点介绍独立按键和矩阵键盘。
图4-1单片机应用系统中常用的非编码键盘
中断,是单片机应用系统开发中一个非常重要的概念,也是单片机最重要的功能之一。
本章在引入中断概念之后,将中断与键盘、中断与数码管结合,借助这些综合性的应用实例,介绍51单片机的外部中断、定时/计数器中断的特点及具体使用方法。
4.2独立按键
独立按键,是指每个按键占用一根I/O口线,如图4-2所示,8个独立按键占用了8根I/O引脚。
图(a)中每个按键连接一个上拉电阻,用来保证在无键按下时,单片机I/O口引脚处于可靠的高电平状态,以防止各种干扰可能引起的误操作。
51单片机引脚悬空时即为高电平状态,所以在某些要求不高的场合,上拉电阻也可以不接,如图4-2(b)所示。
(a)(b)
图4-2独立按键的连接方式
独立按键适用于按键数量较少的场合,其特点是各按键相互独立,电路配置灵活,软件结构简单。
当按键数量较多时,I/O口线的占用就较多,电路结构的复杂度也会提高。
4.2.1独立按键的结构
单片机系统中常用的独立按键是轻触按键,其实物如图4-3(a)所示,在电路中的符号如图4-3(b)所示,图4-3(c)则是其内部结构图。
图4-3(a)轻触按键实物图图4-3(b)轻触按键电气符号图4-3(c)轻触按键结构图
不难发现,轻触按键电路符号为2个引脚,而实物却是4个引脚。
从其结构图4-3(c)可以看出,实物按键的4个引脚分为两组,引脚1和2为一组,引脚3和4为一组,每组引脚在按键内部彼此连通。
实际应用时,从两组引脚中各任意选择一只引脚,组合使用即可。
例如,选择引脚1和3,或者选择引脚2和4,来作为开关按钮均可。
在单片机硬件电路设计中,为保证整个按键在电路安装或焊接时的机械强度,并允许大电流通过,四个引脚一般都会使用。
4.2.2独立按键实例1——按键计数
功能说明:
两个独立按键K1和K2,K1每按下一次,数码管上显示的数值就加1;K2每按下一次,数码管上显示的数值就减1。
数码管显示的数值范围是0~9。
当数码管当前显示数值为9时,再按下K1键,数码管显示数值0;当数码管当前显示数值为0时,再按下K2键,数码管显示数值9。
硬件说明:
1、硬件电路连接如图4-4所示。
按键选用轻触按键,按键K1和K2分别连接单片机的P3.2和P3.3两只引脚;
2、数码管选用共阴极数码管,使用74HC573驱动段码数据,公共端直接接地。
图4-4独立按键计数硬件连接图
软件说明:
1、通过不断读取并查看按键连接端口引脚P3.2和P3.3的状态,实现按键识别;
2、按键识别后,通过设置计数器来记录按键次数,并将数据及时送到P0口显示。
程序清单如下:
#include
#defineuintunsignedint
#defineucharunsignedchar
sbitk1=P3^2;
sbitk2=P3^3;
ucharcodetable[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
charnum=0;
//************************************************************
voiddelay(uchari)//延时子函数
{
ucharj,k;
for(k=0;k
for(j=0;j<110;j++);
}
//************************************************************
main()
{
while
(1)
{
if(k1==0)//读按键K1状态,若为0,初步判断按键K1按下
{
delay(10);//延时去抖动
if(k1==0)//再次判断,仍为0,说明按键K1确实按下
{
num++;//计数器值加1
if(num==10)//若计数器值等于10,则清0,保证0~9显示
num=0;
while(k1==0);//等待按键释放
P0=table[num];
}
}
if(k2==0)
{
delay(10);
if(k2==0)
{
num--;
if(num==-1)
num=9;
while(k2==0);//等待按键释放
P0=table[num];
}
}
}
}
C语言知识:
if语句
程序设计中的三大结构分别是顺序结构、选择结构和循环结构。
选择结构也称为分支结构,if语句属于选择结构。
在程序中,if语句用来判定给定的条件是否满足,并根据判定结果(逻辑真或假),在所给两种操作中,选择其中一种操作来执行。
1.if语句的三种形式
(1)if语句的第一种形式为:
if(表达式)
语句
其执行流程如图4-5所示。
例如:
if(x>y)
x--;
图4-5if语句形式1的执行流程
(2)if语句的第二种形式为:
if(表达式)
语句1
else
语句2
其执行流程如图4-6所示。
图4-6if语句形式2的执行流程
例如:
if(x>y)
x--;
else
x++;
(3)if语句的第三种形式为:
if(表达式1)
语句1
elseif(表达式2)
语句2
elseif(表达式3)
语句3
……
elseif(表达式m)
语句m
else
语句m+1
其执行流程如图4-7所示。
图4-7if语句形式3的执行流程
例如:
if(number>500)NUM=1;
elseif(number>300)NUM=2;
elseif(number>100)NUM=3;
elseif(number>50)NUM=4;
elseNUM=0;
说明:
1)if语句中的“表达式”,一般为关系表达式或逻辑表达式,但并不仅局限于这两种。
需要注意的是,C语言中,0代表“假”,非0则代表“真”。
例如:
if(‘A’)i++;语句中,i++;一定会被执行,原因是字符‘A’作为表达式时,被判断的是该字符对应的ASCII码值,‘A’的ASCII码值为十进制数65,自然是非0的,所以表达式’A’的结果为逻辑“真”。
2)else子句不能单独使用,它是if语句的一部分,必须与if配对使用。
3)在if和else的语句1或者语句2中,可以只包含一条操作语句,也可以包含多条。
如果是多条操作语句,这些多条操作语句必须用大括号(花括号)括起来,构成所谓的语句块或复合语句。
复合语句中的每条语句也许都用分号结束,但复合语句的大括号外不再需要分号。
例如:
if(x+y>z&&y+z>a&&z+x>y)
{
s=2*(x+y+z);
area=sqrt(s*(s-x)*(s-y)*(s-z));
display(area);
}
else
printf(“itisnotatriangle”);
2.if语句的嵌套
if语句的嵌套,就是if语句的if块或else块中,又包含一个或多个if语句。
其一般形式为:
if(…)
if(…)
语句1;
else
语句2;
else
if(…)
语句3;
else
语句4;
在实际程序编写中,应当注意if与else的配对关系:
else总是与它上面最近的、且未配对的if配对;尤其是在if/else子句数目不相等(if子句数量大于或等于else子句数量)时,应特别注意if与else的配对。
在if语句使用中,经常会出现与编程者预期结果不同的现象,通常可以用下面两种方法解决if与else的匹配问题:
(1)利用“空语句”占位,使if子句数量与else子句数量相同。
所谓“空语句”,就是什么功能都没有、仅仅由一个分号构成的语句。
在程序设计中,其作用就是为了使程序结构完整、规范,不出现歧义,避免不必要的错误。
例如:
if(…)
if(…)
语句1
else
;//此行中的分号即为空语句
else
if(…)
语句2
else
语句3
(2)利用复合语句。
将没有else子句的if语句用大括号括起来,构成复合语句,使原有的语句1或者语句2从整体上查看时,呈现出语句块结构。
例如:
if(…)
{
if(…)
语句1
}
else
{
if(…)
语句2
else
语句3
}
在单片机C语言编程时,常有“if…else包打天下”的说法,虽有些夸张,但也从一个侧面反映了if语句应用的广泛性与功能的多样性。
我们建议读者熟练运用if语句,同时尽量掌握多种语句形式,灵活运用。
比如,本章后面实例中出现的switch语句,就可以在很多场合替换if语句,更有层次分明、可读性好的优点。
单片机知识:
按键的去抖动
我们常用的按键都是机械按键,如图4-8(a)所示,键在按下或释放时,由于机械弹性的影响,触点会发生机械抖动,与按键连接的芯片引脚就会发生如图4-8(b)所示电平波动或抖动现象。
这种抖动可能造成CPU错误判定外部引脚上电平的高低,从而导致误操作或者一次按键多次处理的问题。
因此,实际使用中,要通过某种方法消除抖动产生的不良后果,这就是按键的去抖动。
目前,较为常用的有硬件去抖动和软件去抖动。
图4-8按键操作和按键抖动
图4-8(b)中,前沿抖动或后沿抖动持续的时间一般为5~10ms。
由于抖动现象不可避免,势必引起电平信号波动,
1.硬件去抖动
图4-9硬件消抖电路
硬件去抖动,就是使用硬件电路消除按键的抖动。
常用的硬件电路如图4-9所示,其中图(a)是用两个与非门构成的双稳态触发器来消除按键抖动;图(b)是使用单稳态集成触发器74121来消除按键抖动;图(c)是利用电阻和电容构成的RC滤波电路去抖动,图(c)电路结构简单,实用效果好,运用较多。
2.软件去抖动
为了便于理解软件去抖动的原理,此处,我们分析一次完整按键的过程细节,如图4-8(b)所示。
首先,按键被按下,由于机械弹性原因出现前沿抖动,抖动持续时间一般为5~10ms;前沿抖动结束后,引脚电平就稳定在低电平状态;低电平持续一段时间后,按键被松开弹起,此时又出现后沿抖动,抖动持续时间一般也是5~10ms;后沿抖动结束,一次完整的按键操作随之结束。
软件去抖动,就是首先检测引脚电平是否为低电平,若检测到低电平,说明按键可能被按下,但还不能完全确定按键是否真被按下;然后延时5~10ms,目的就是要避开前沿抖动这一时段;延时结束后,按理引脚电平已稳定在低电平状态,此时再检测引脚电平,如果是低电平,则可以确认按键的确被按下。
相反,若延时之后,再次检测到的电平是高电平,则说明刚才检测到的低电平是误判,按键没有真正被按下。
如果确认按键的确被按下,则CPU执行相关按键按下的处理程序;否则CPU不予理睬,继续执行原有程序。
由以上分析可见,软件去抖动的核心,就是延时及延时前后两次连续的检测和判断。
软件去抖动的程序示例如下:
if(k2==0)//若检测到低电平,初步判断按键被按下,但还未完全确认
{
delay(10);//延时10ms去抖动
if(k2==0)//延时后再次检测,若检测到低电平,则可以确认按键的确被按下
num--;//有按键按下,则进行相关处理
}
4.2.3独立按键实例2——多个按键识别
功能要求:
实现8个独立按键K0~K7的识别,并用一位数码管显示被按下按键对应的键号。
硬件说明:
1、硬件连接原理图如图4-10所示。
8个按键分别与单片机P2口的8只引脚连接,8个按键的公共端接地。
2、采用共阴极数码管显示键号,通过74HC573驱动段码数据,公共端直接接地;
图4-10独立按键多键识别硬件连接图
软件说明:
独立按键的程序设计,一般都采用查询方式,即逐位查询每根I/O口引脚线的电平状态。
如果软件去抖动之后,检测到某根I/0口线引脚依旧为低电平,则可以确认与该I/O端口引脚连接的按键被按下,之后就可以转入该按键对应的处理程序。
程序清单如下:
#include
#defineuintunsignedint
#defineucharunsignedchar
ucharcodetable[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
ucharnum;
//************************************************************
voiddelay(uchari)//延时函数
{
ucharj,k;
for(k=0;k
for(j=0;j<110;j++);
}
//************************************************************
ucharkeyscan()
{
ucharb;
P2=0xff;//P2口作为输入口,置全1
b=P2;
if(b==0)//循环判断是否有键按下
{
delay(10);//有键按下,延时10ms去抖
if(b==0)
{
b=P2;//读按键状态
b=~b;//按键状态取反
}
}
switch(b)//根据键值调用不同的处理函数
{
case0x01:
num=1;break;//取得按键1键值
case0x02:
num=2;break;//取得按键2键值
case0x04:
num=3;break;//取得按键3键值
case0x08:
num=4;break;//取得按键4键值
case0x10:
num=5;break;//取得按键5键值
case0x20:
num=6;break;//取得按键6键值
case0x40:
num=7;break;//取得按键7键值
case0x80:
num=8;break;//取得按键8键值
default:
break;
}
returnnum;
}
main()
{
while
(1)
{
P0=table[keyscan()];
}
}
C语言知识:
switch语句
如前所述,嵌套的if语句可以实现多分支,但分支过多,if语句嵌套的层数就多,致使程序冗长,可读性变差,此时,可考虑使用switch语句实现。
C语言中,switch语句是多分支选择语句,其一般形式为:
switch(表达式)
{
case常量表达式1:
语句1
case常量表达式2:
语句2
………
case常量表达式n:
语句n
default:
语句n+1
}
switch语句中,各个case语句可以通过使用break语句终止。
说明:
(1)switch括号内的表达式,允许为任何类型。
(2)当“表达式”的值与某个case后面的常量表达式的值相等时,就执行此case后面的语句。
如果表达式的值与所有常量表达式都不相等,就执行default后面的语句。
(3)各个常量表达式的值必须互斥,不允许相同,否则会出现逻辑矛盾。
(4)case,default出现的顺序不影响执行结果。
(5)执行完一个case后面的语句后,流程控制转移到下一个case中的语句继续执行。
此时,“case常量表达式”只起到语句标号的作用,并不在此处进行条件判断。
执行一个分支后,可以使用break语句,使流程跳出switch结构,即终止switch语句的执行(最后一个分支可以不用break语句)。
(6)case后面如果有多条语句,不必用大括号括起来。
(7)多个case可以共用一组执行语句,此时应注意break使用的位置。
4.2.4独立按键实例3——一键多功能按键识别
功能要求:
用一个按键实现多个按键的功能。
具体要求为:
系统上电的时候,仅接在P2.0引脚上的发光二极管D1在闪烁,其它发光二极管D2、D3和D4都熄灭;如果按一下开关K,即开关K被按下了一次,此时接在P2.1管脚上的发光二极管D2开始闪烁,而D1、D3和D4都熄灭;如果再按一下开关K,即开关K已累计被按下了2次,此时,接在P2.2管脚上的发光二极管D3开始闪烁,而D1、D2和D4都熄灭;如果再按下开关K,即开关K已累计被按下了3次,此时,接在P2.3管脚上的发光二极管D4开始闪烁,而D1、D2和D3都熄灭;如果再次按下开关K,即开关K已累计被按下了4次,此时D1开始闪烁,而D2、D3和D4都熄灭,……,依次类推,随着按键次数的增加,四个发光二极管被轮流选中,闪烁发光。
硬件说明:
电路原理图如图4-11所示,开关K接在P2.7引脚上,P2口的低四位分别接有四个发光二极管D0,D1,D2和D3。
图4-11一键多功能识别硬件连接图
软件说明:
从上面的要求可以看出,发光二极管D1到D4轮流闪烁的时段受开关K控制,给发光二极管单独闪烁的各个时段分配不同的ID号:
仅当D1在闪烁时,ID=0;仅当D2在闪烁时,ID=1;仅当D3在闪烁时,ID=2;仅当D4在闪烁时,ID=3。
很显然,每次按下开关K时,ID值加1,根据当前ID号,选择不同的任务去执行,而ID号则以数值3封顶,即ID号加1等于4时,ID号就清0。
本实例的程序设计框图如图4-12所示。
图4-12一键多功能程序流程
程序清单如下:
#include
sbitK=P2^7;
sbitD1=P2^0;
sbitD2=P2^1;
sbitD3=P2^2;
sbitD4=P2^3;
unsignedcharID=0;
//************************************************************
voiddelay(unsignedchari)//延时1ms
{
unsignedcharj,k;
for(k=0;k
for(j=0;j<110;j++);
}
//************************************************************
voiddelay02s(void)//延时200ms=0.2s函数
{
unsignedcharx;
for(x=20;x>0;x--)
delay(10);
}
//************************************************************
main()
{
while
(1)
{
if(K==0)
{
delay(10);
if(K==0)
{
ID++;//确定有按键按下,每次ID加1记录
if(ID==4)//当ID值为4时,重新开始记录
ID=0;
while(K1==0);
}
}
switch(ID)
{
case0:
D1=~D1;delay02s();break;
case1:
D2=~D2;delay02s();break;
case2:
D3=~D3;delay02s();break;
case3:
D4=~D4;delay02s();break;
default:
break;
}
}
}
4.3矩阵键盘
4.3.1矩阵键盘
在独立按键电路中,每一个按键都要占一根I/O口引脚。
按键数量较多时,如果依旧采用独立按键,必然使很多I/O口引脚被占用。
由于51单片机I/O口引脚数量原本就有限,这样留做它用的I/O口引脚数量就会更少,以致具体应用中出现I/O口引脚不够用的尴尬局面。
所以,在按键数量较多的情况下,就不宜再使用独立按键,取而代之的便是矩阵键盘。
矩阵键盘由多个行线和多个列线交织组成,其中使用的按键依旧是独立按键,但各个独立按键都位于行线和列线的交叉点上,如图4-13所示。
此图所示矩阵键盘,共有16个按键,分别位于4根行线和4根列线的交叉点上。
从图中可以看到,若依照独立按键的形式连接,16个独立按键就需要16根I/O口引脚线;若采用矩阵键盘,则仅占用8根I/O口引脚线,节省下来的I/O引脚线数量还是相当可观的。
在节省了I/O引脚、硬件电路得以优化的同时,也导致软件编程复杂度的提高。
图4-13矩阵键盘结构
实际应用中,常见的矩阵键盘有两种,如图4-14所示,
(a)普通矩阵键盘(b)薄膜矩阵键盘
图4-14常用矩阵键盘实物
图4-14(a)为独立按键与设计好的PCB电路构成的矩阵键盘。
制作时,要先设计PCB印刷电路板,再在PCB板上焊接按键、电阻和接口等元件,使用时直接将接口与单片机I/O连接即可。
图4-14(b)为薄膜键盘,它是近年来国际流行的一种集装饰性与功能性为一体的矩阵键盘。
由于薄膜键盘具有可定制、体积小、厚度薄、重量轻、密封性强、防潮、防尘、耐酸碱、抗震、使用寿命长、耐弯折等优点,已广泛应用在智能化电子测量仪器、医疗仪器、计算机控制、数控机床、邮电通讯、复印机、电冰箱、微波炉、电风扇、洗衣机、电子游戏机等各类工业及家用电器产品及相关领域。
无论PCB矩阵键盘还是薄膜矩阵键盘,其电路原理是一样的。
为了方便读者制作验证,图4-15给出了矩阵键盘的电路原理图。
图4-15矩阵键盘电路原理图
4.3.2矩阵键盘应用实例
功能要求:
4×4矩阵键盘连接到51单片机的P2口,P2.0-P2.3作为列线,P2.4-P2.7作为行线;某一按键被按之后,在数码管上显示其对应的序号。
矩阵键盘面板序号的排列如图4-16所示。
选择51单片机的P0口作为共阴极数码管段码的输出口,公共端直接接地。
硬件连接如图4-17所示。
图4-16矩阵键盘面板序号排列
图4-17矩阵按键硬件连接图
软
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 第4章 键盘输入与中断 键盘输入 中断