历史上的今天
返回首页

历史上的今天

今天是: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    for(j = 0; j<110; ++j);

}

在这里插入图片描述
在这里插入图片描述

二、矩阵键盘

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    for(j = 0; j<110; ++j);

}


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;

}

推荐阅读

史海拾趣

AMS公司的发展小趣事

AMS(Austria Microsystems)公司是一家总部位于奥地利的半导体制造商,专注于开发和生产高性能的模拟半导体解决方案。以下是 AMS 公司发展的五个相关故事:

  1. 创立与早期阶段:AMS 公司成立于1981年,最初是一家从事晶圆制造的小型企业。公司创始人团队以其对半导体技术的深刻理解和创新能力,在短时间内取得了一定的成就。早期产品主要包括模拟集成电路(IC)和传感器,为医疗、汽车、工业等领域提供解决方案。

  2. 技术创新与产品扩展:随着市场需求的不断变化和技术的进步,AMS 公司不断进行技术创新,并扩展了产品线。公司致力于开发具有高性能、低功耗和小尺寸的模拟半导体产品,以满足智能手机、消费电子、工业自动化等领域的需求。公司的产品涵盖了光学传感器、环境传感器、声学传感器等多个领域。

  3. 全球化发展与市场拓展:AMS 公司通过不断拓展全球市场,加强与客户和合作伙伴的合作关系,实现了快速的业务增长。公司在欧洲、亚洲和美洲设立了多个销售办事处和生产基地,建立了完善的全球供应链和销售网络。公司的产品销售网络覆盖了全球范围,得到了国内外客户的广泛认可。

  4. 收购与合并:随着公司规模的扩大和市场竞争的加剧,AMS 公司通过收购和合并等方式不断强化自身实力。公司先后收购了一些技术领先的公司,扩大了产品线和市场份额。此举进一步提升了公司在模拟半导体领域的竞争优势,加速了公司的业务增长。

  5. 持续创新与未来展望:AMS 公司将继续致力于技术创新和产品研发,不断提升产品性能和品质水平。公司将关注新兴技术和市场趋势,积极布局未来的发展方向,包括人工智能、物联网、汽车电子等领域。同时,公司还将加强与客户和合作伙伴的合作,共同推动行业的发展和进步。

Amkor公司的发展小趣事

Amkor Technology是一家全球领先的半导体封装和测试服务提供商。以下是关于Amkor公司发展的五个相关故事:

  1. 成立与早期发展:Amkor Technology成立于1968年,总部位于美国亚利桑那州的钱德勒市。公司最初是一家小型半导体封装服务提供商,专注于为集成电路制造商提供先进的封装解决方案。在成立初期,Amkor致力于技术创新和质量控制,赢得了客户的信任和认可。

  2. 技术创新与产品多样化:随着电子行业的发展和技术的进步,Amkor不断进行技术创新,并扩展了产品线。公司推出了一系列新的封装技术和解决方案,包括先进的3D封装、薄型封装、系统封装等。这些技术创新和产品多样化使得Amkor能够满足不同客户的需求,并保持在市场竞争中的领先地位。

  3. 全球布局与生产基地建设:为了更好地服务全球客户,Amkor在全球范围内建立了多个生产基地和分销中心。除了在美国的设施外,公司还在亚洲、欧洲和其他地区建立了生产工厂和研发中心。这种全球布局有助于降低生产成本、提高生产效率,并加强了在全球市场的竞争力。

  4. 合作伙伴关系与客户服务:Amkor与全球各种半导体制造商建立了紧密的合作伙伴关系,共同推动技术创新和产品发展。公司致力于为客户提供优质的封装和测试解决方案,并与客户密切合作,开发定制化的解决方案。Amkor的客户服务团队提供全方位的技术支持和服务,确保客户的满意度和业务成功。

  5. 持续发展与业绩表现:Amkor持续实现了稳健的增长和良好的业绩表现。公司不断投入研发,并提升生产效率和管理水平,以提高盈利能力和市场竞争力。Amkor的业绩稳步增长,为股东创造了可观的价值,并使得公司成为半导体封装和测试服务领域的领先企业之一。

这些故事展示了Amkor Technology从成立初期到如今在技术创新、产品多样化、全球布局、合作伙伴关系建设和持续发展等方面取得的重要进展。

Ecera Comtek Corp公司的发展小趣事

Ecera Comtek Corp公司成立于XX世纪初,由几位热衷于电子通信技术的工程师共同创立。初创时期,公司面临着资金短缺、技术挑战和市场竞争等多重压力。然而,创始人们凭借对技术的热情和执着,不断研发创新产品,逐渐在行业内树立了口碑。他们经常通宵达旦地工作,试验新的设计方案,努力提升产品的性能和稳定性。经过数年的努力,Ecera Comtek Corp公司终于推出了首款具有竞争力的无线通信设备,为公司的发展奠定了坚实的基础。

Andigilog公司的发展小趣事

在竞争激烈的电子行业中,Ecera Comtek Corp公司意识到只有不断创新才能在市场中立足。于是,公司加大了研发投入,引进了一批高端技术人才。经过长时间的研发,Ecera Comtek Corp公司成功研发出了一种新型的信号处理技术,大大提高了无线通信设备的传输速度和稳定性。这一技术突破迅速引起了市场的关注,Ecera Comtek Corp公司的产品在市场上受到了热烈的欢迎,公司的销售额也实现了快速增长。

Good-Ark公司的发展小趣事
确保电源稳定可靠,避免电压波动对电路造成影响。
展恒电子(Broadic)公司的发展小趣事

2011年,展恒电子自主研发的首款485功能芯片——HD588成功问世,并成功应用到电网产品中。这一突破不仅证明了展恒电子在芯片设计领域的实力,也为公司在电力行业的拓展奠定了坚实的基础。随后,公司继续加大研发力度,不断推出更多具有竞争力的产品,逐步在电子行业中树立了良好的口碑。

问答坊 | AI 解惑

问一个关于在论坛里下载资料的问题

为什么我点击下载自己想要的资料,下载到最后提示失败呢,芯币也已经扣除了!昨天就发现有这种情况,当时我以为自己的芯币不够了呢,还反复的下,反复的提示失败,最后本来不多的芯币真就不够了,呵呵 [ 本帖最后由 cqr 于 2008-12-8 09:17 编辑 ]…

查看全部问答>

有关Verilog语言调用全加器做累加器的问题 急急急!

1 利用4位二进制加法器和4位寄存器,实现4位累加器的设计。要求设计的累加器有异步清零控制端和累加使能控制端(高电平累加允许 低电平输出数据保持) 2 利用4位累加器和前面设计的计数器 实现两个二位二进制数的乘法操作。初始时,累加寄存器清零 ...…

查看全部问答>

单片机和上位机通讯(通过无线网卡)

单片机和上位机通讯。 通过gprs方式和上位机通讯的方式已经做出来了。 现在想实现通过无线网卡模块,再通过无线路由器和上位机进行通信。 1.这种方式可行否? 2.单片机和无线网卡模块的开发需要嵌入式操作系统不?这块难度大部? …

查看全部问答>

LM3s8962体验之六……时钟寄存器操作

时钟设置 一、简介     本程序实验使用更改寄存器,设置系统时钟变化。软件延时因系统时钟而改变。进一步促使蜂鸣时间间隔变化。 二、时钟原理 1、时钟源   1)、外部振荡器、0—50MHZ   2)、主振荡器、 ...…

查看全部问答>

关于xilinx的DCM

ISE中有“Wait for DLL Lock”这个选项,目的是设置FPGA是否等待DCM的“lock”信号。 默认设置是nowait。 我现在想设置成为等待模式,但是里面的设置是0、1、2、3、4、5、6、这些数字代表的是什么设置啊?   还有,大家用DCM的时候,是 ...…

查看全部问答>

10.26【每周讨论】你知道这家公司的名字吗

有这么一家公司,它工资高,活儿少,福利好,老板不SB还能学到东西,没事儿就放假,动不动就送东西,年终奖还特丰厚,它是世界上最好的公司,你知道这家公司的名字吗?…

查看全部问答>

求助:不用OS如何让一个长耗时的函数让出CPU时间

是这样的,我在一个函数里面要进行多次擦除FLASH的扇区的工作,擦除一个扇区时间需要要2-3S,而擦除扇区后,该函数接下来还要完成其它的逻辑。我想把等待FLASH时间用来做别的工作。请问该如何实现? [ 本帖最后由 amduron 于 2012-4-25 09:44 编辑 ...…

查看全部问答>

怎么学习

前辈们,小弟很热爱单片机,但是不知道怎么学,能不能给小弟指一条学习430的方法。怎么学习呢,看视频吗?看程序吗?。。。。有没有资源可以分享以下的。谢谢。…

查看全部问答>

坛子最近感觉怎么跟之前不一样了!!

自从注册之后,基本上每天上班第一件事是习惯性的打开论坛然后再看新闻,但最近这段时间好像看不到新的东西,我前几天发的帖没有新的回复居然还至顶,感觉变了!说不出来,有点像现在怀念孩童的时光的那种感觉…… [ 本帖最后由 gh131413 于 2013-7 ...…

查看全部问答>

牛人打造现实版WALL-E机器人

$(\'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 ...…

查看全部问答>