历史上的今天
今天是:2025年06月14日(星期六)
2020年06月14日 | 51单片机入门教程(4)——按键控制
2020-06-14 来源:eefocus
单片机与外界的信息交互主要有两大类,输入信息和输出信息。
之前的博客介绍了通过单片机控制LED灯和数码管向外界输出信息,该教程介绍单片机常用的输入设备——独立按键和矩阵键盘。
一、独立按键
1.1 独立按键的原理
独立按键一共有四个针脚,两个短针脚之间默认不导通,两个长针脚之间默认导通。实物图如图:

1.2 独立按键的仿真电路
在Proteus中对按键进行了简化,只有两个接线针脚。按键的一端接到单片机的IO口上,另一端与GND连接。当按键按下时,单片机的IO口与GND连接,端口电平被拉低。因此通过读取端口电平即可获知按键状态。
仿真电路如图:

1.3 按键消抖
关于按键抖动:
通常的按键所用开关为机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开。即单片机在按键被按下的一瞬间检测到的信号是很多次的忽高忽低的电平信号,如图:

这种信号是不稳定的。因此,我们需要使用按键消抖的算法使单片机获取到正常稳定的信号。
为了避免在最不稳定的时候采集信号,常用的操作是延时,即当检测到低电平输入时,延时若干时间(常用20ms),再次采集信号,如果仍是低电平,则为按键被按下。
示例程序如下:
/**************************
* 说明: 按键被按下时led灯灭
**************************/
#include #define uint unsigned int #define uchar unsigned char //定义按键端口 sbit key = P1^0; //定义LED灯端口 sbit led = P2^0; //延时函数声明 void delay(uint xms); //程序入口 void main(){ while(1){ //第一次判断 if(key == 0){ //延时20ms 消除抖动 delay(20); //第二次判断 if(key == 0){ led = 0; //灯灭 } else { led = 1; //灯亮 } //等待按键被松开 while(!key); //当按键未松开时,key为0,执行该死循环。 } } } void delay(uint xms) { uint i,j; for(i = 0; i } 二、矩阵键盘 2.1 矩阵键盘原理 矩阵键盘是单片机外部设备中所使用的排布类似于矩阵的键盘组。在键盘中按键数量较多时,为了减少I/O口的占用,通常将按键排列成矩阵形式。其实物图如图: 2.2 矩阵键盘扫描原理 在Proteus上搭建矩阵键盘仿真电路如图: 首先搞清楚电路是怎样接的: 4×4的矩阵键盘,对于每一行,左端连在一起,四行按键因此引出四组线,接在P2_0 - P2_3上。如图: 同理,对于每一列,右端连在一起,四列按键因此引出四组线,接在P2_4 - P2_7上。如图: 组合起来就得到了第一张图片。 因此可以通过读取按键输入哪一行,哪一列从而确定按键的位置。 首先得到被按下的按键属于哪一行: 把P2_0 - P2_3 端口置为高电平,P2_4 - P2_7置为低电平,如果其中一行的某一个按键被按下,那么对应的P2_0 - P2_3 端口就会有一个端口被拉低,通过判断即可确定被按下按键属于哪一行。 如图,第一行有按钮被按下(端口红色为高电平,蓝色为低电平) 代码段如下: P2 = 0x0f; //P2_0 - P2_3 端口置为高电平,P2_4 - P2_7置为低电平 if (P2 != 0x0f) //如果不为0x0f,说明有按键被按下 { delay(20); //读出端口从读出值来判断是哪一行 switch (P2) { case 0x0e: x = 0; break; //0000 1110 case 0x0d: x = 1; break; //0000 1101 case 0x0b: x = 2; break; //0000 1011 case 0x07: x = 3; break; //0000 0111 default: break; } 读取被按下的按键属于哪一列: 类似地:把P2_0 - P2_3 端口置为低电平,P2_4 - P2_7置为高电平,如果其中一列的某一个按键被按下,那么对应的P2_4 - P2_7 端口就会有一个端口被拉低,通过判断即可确定被按下按键属于哪一列。 如图,第三列有按钮被按下 代码段如下: P2 = 0xf0; //P2_0 - P2_3 端口置为低电平,P2_4 - P2_7置为高电平 if (P2 != 0xf0){ //如果不为0xf0,说明有按键被按下 switch (P2) { case 0xe0: y = 0; break; case 0xd0: y = 1; break; case 0xb0: y = 2; break; case 0x70: y = 3; break; default: break; } } 2.3 矩阵键盘扫描程序 将读取到的矩阵键盘值(0 - F)显示在数码管上: 仿真电路如图: 代码如下: /************************** * 读取矩阵键盘值并显示至数码管上 **************************/ #include #define uint unsigned int #define uchar unsigned char //共阳数码管编码表 uchar code table[] = {0xc0,0xf9,0xa4,0xb0, 0x99,0x92,0x82,0xf8, 0x80,0x90,0x88,0x83, 0xc6,0xa1,0x86,0x8e}; //函数声明 void delay(uint xms); //延时函数 void display(uchar x); //数码管显示函数,输入0-15,在数码管上显示0-F uchar getKey(); //读取矩阵键盘函数,返回0-15 //程序入口 void main(){ uchar keyValue; while(1){ keyValue = getKey(); //读取键盘值 display(keyValue); //数码管显示 } } void delay(uint xms){ uint i,j; for(i = 0; i } void display(uchar x){ P0 = table[x]; } uchar getKey(){ uchar x = 0, y = 0; uchar result = 0; // 第1回合第1步 P2 = 0x0f; // 从IO口输出,写IO口 if (P2 != 0x0f)// 从IO口输入,读IO口 { // 读出的不是0x0f说明有按键被按下 delay(20); // 第1回合第2步:读出端口从读出值来判断是哪一行 switch (P2) { case 0x0e: x = 0; break; case 0x0d: x = 1; break; case 0x0b: x = 2; break; case 0x07: x = 3; break; default: break; } delay(10); // 第2回合第1步 P2 = 0xf0; if (P2 != 0xf0){ switch (P2) { case 0xe0:y = 0; break; case 0xd0: y = 1; break; case 0xb0: y = 2; break; case 0x70: y = 3; break; default: break; } // 经过2个回合后行x和列y都知道了,然后根据x和y去计算键值即可 } } result = x * 4 + y; return result; } 








史海拾趣
|
为什么我点击下载自己想要的资料,下载到最后提示失败呢,芯币也已经扣除了!昨天就发现有这种情况,当时我以为自己的芯币不够了呢,还反复的下,反复的提示失败,最后本来不多的芯币真就不够了,呵呵 [ 本帖最后由 cqr 于 2008-12-8 09:17 编辑 ]… 查看全部问答> |
|
1 利用4位二进制加法器和4位寄存器,实现4位累加器的设计。要求设计的累加器有异步清零控制端和累加使能控制端(高电平累加允许 低电平输出数据保持) 2 利用4位累加器和前面设计的计数器 实现两个二位二进制数的乘法操作。初始时,累加寄存器清零 ...… 查看全部问答> |
|
单片机和上位机通讯。 通过gprs方式和上位机通讯的方式已经做出来了。 现在想实现通过无线网卡模块,再通过无线路由器和上位机进行通信。 1.这种方式可行否? 2.单片机和无线网卡模块的开发需要嵌入式操作系统不?这块难度大部? … 查看全部问答> |
|
时钟设置 一、简介 本程序实验使用更改寄存器,设置系统时钟变化。软件延时因系统时钟而改变。进一步促使蜂鸣时间间隔变化。 二、时钟原理 1、时钟源 1)、外部振荡器、0—50MHZ 2)、主振荡器、 ...… 查看全部问答> |
|
ISE中有“Wait for DLL Lock”这个选项,目的是设置FPGA是否等待DCM的“lock”信号。 默认设置是nowait。 我现在想设置成为等待模式,但是里面的设置是0、1、2、3、4、5、6、这些数字代表的是什么设置啊? 还有,大家用DCM的时候,是 ...… 查看全部问答> |
|
有这么一家公司,它工资高,活儿少,福利好,老板不SB还能学到东西,没事儿就放假,动不动就送东西,年终奖还特丰厚,它是世界上最好的公司,你知道这家公司的名字吗?… 查看全部问答> |
|
是这样的,我在一个函数里面要进行多次擦除FLASH的扇区的工作,擦除一个扇区时间需要要2-3S,而擦除扇区后,该函数接下来还要完成其它的逻辑。我想把等待FLASH时间用来做别的工作。请问该如何实现? [ 本帖最后由 amduron 于 2012-4-25 09:44 编辑 ...… 查看全部问答> |
|
自从注册之后,基本上每天上班第一件事是习惯性的打开论坛然后再看新闻,但最近这段时间好像看不到新的东西,我前几天发的帖没有新的回复居然还至顶,感觉变了!说不出来,有点像现在怀念孩童的时光的那种感觉…… [ 本帖最后由 gh131413 于 2013-7 ...… 查看全部问答> |
|
$(\'swf_bIY\').innerHTML=AC_FL_RunContent(\'width\', \'550\', \'height\', \'400\', \'allowNetworking\', \'internal\', \'allowScriptAccess\', \'never\', \'src\', encodeURI(\'http://player.youku.com/player.php/sid/XNTkyMTU3OTYw/v.sw ...… 查看全部问答> |




