2019-11-29 11:04:19 chenkhbest 阅读数 10
  • 按键-第1季第9部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第9个课程,综合解决了独立按键和矩阵式按键的处理方法,涉及到:IO的输入输出、按键抖动和消抖、中断的引入和相关概念、矩阵式键盘的原理和编程等。目的是对单片机常见输入设备按键进行全方位学习。

    2179 人正在学习 去看看 朱有鹏

一、应用场景以及优势

该按键扫描方式用于产品按键较多产品。可以用较少的端口控制较多的按键。

以8个IO口为例子,普通按键扫描最多控制,16个按键(矩形扫描)。采用该方式可以控制28个按键

二、扫描方式

原理图:

IO1输出低IO0输入检测,IO0输入检测到低电平则K01按下。以此类推。IO2输出低,IO0输入检测到低则K02按下,IO1检测到输入低则K03按下,一直扫描完全部按键。

2018-03-25 12:40:26 xhl1123456789 阅读数 7541
  • 按键-第1季第9部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第9个课程,综合解决了独立按键和矩阵式按键的处理方法,涉及到:IO的输入输出、按键抖动和消抖、中断的引入和相关概念、矩阵式键盘的原理和编程等。目的是对单片机常见输入设备按键进行全方位学习。

    2179 人正在学习 去看看 朱有鹏

      首先说一下独立键盘检测,在单片机外围电路中  ,通常用到的按键都是机械弹性开关,当开关闭合时,线路导通,开关断开时,线路断开。单片机检测按键的原理:按键的一端接地,另一端与单片机的某个I/O口相连,开始先给I/O赋一高电平,然后让单片机不断检测该I/O口是否变为低电平,当按键闭合时,相当于I/O口与地相连,就会变为低电平。在单片机检测按键是否被按下时,电压的实际波形与理想波形时有一点=定差别的,波形在按下和释放瞬间都有抖动现象,抖动时间的长短和按键的机械特性有关 。所以单片机在检测键盘是否被按下都要加上去抖操作,所以在编写单片机的键盘检测程序时,一般在检测按下时加入去抖延时。独立键盘与单片机连接时每一个按键都需要一个I/O口,会过多占用I/O口资源。所以就引出了矩阵键盘。

     矩阵键盘的连接方式,每一行将每个按键的一端连接在一起构成行线,每一列将按键的另一端连接在一起构成列线。这样的话,16个按键排成4行4列就只要8根线。它的按键检测,简单点说,就是先送一列低电平,其余均为高电平,然后轮流检测,确认行列。

     这里就要提到另外一个东西,switch-case语句又称开关语句,它是一个专门用于处理多分支结构的条件选择语句。使用switch语句可直接处理多个分支。

    

    

2018-11-17 00:20:10 qq_19799765 阅读数 10137
  • 按键-第1季第9部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第9个课程,综合解决了独立按键和矩阵式按键的处理方法,涉及到:IO的输入输出、按键抖动和消抖、中断的引入和相关概念、矩阵式键盘的原理和编程等。目的是对单片机常见输入设备按键进行全方位学习。

    2179 人正在学习 去看看 朱有鹏


单片机与外界的信息交互主要有两大类,输入信息和输出信息。
之前的博客介绍了通过单片机控制LED灯和数码管向外界输出信息,该教程介绍单片机常用的输入设备——独立按键和矩阵键盘。

一、独立按键

1.1 独立按键的原理

独立按键一共有四个针脚,两个短针脚之间默认不导通,两个长针脚之间默认导通。实物图如图:
在这里插入图片描述

1.2 独立按键的仿真电路

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

1.3 按键消抖

关于按键抖动
通常的按键所用开关为机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开。即单片机在按键被按下的一瞬间检测到的信号是很多次的忽高忽低的电平信号,如图:
在这里插入图片描述
这种信号是不稳定的。因此,我们需要使用按键消抖的算法使单片机获取到正常稳定的信号。
为了避免在最不稳定的时候采集信号,常用的操作是延时,即当检测到低电平输入时,延时若干时间(常用20ms),再次采集信号,如果仍是低电平,则为按键被按下。
示例程序如下:

/**************************
* 说明: 按键被按下时led灯灭
**************************/
#include <reg52.h>
#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<xms; ++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 <reg52.h>
#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<xms; ++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;
}

2016-10-08 23:19:13 newcong0123 阅读数 5042
  • 按键-第1季第9部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第9个课程,综合解决了独立按键和矩阵式按键的处理方法,涉及到:IO的输入输出、按键抖动和消抖、中断的引入和相关概念、矩阵式键盘的原理和编程等。目的是对单片机常见输入设备按键进行全方位学习。

    2179 人正在学习 去看看 朱有鹏

按键去抖


这里写图片描述

由上图可以看出理想波形与实际波形之间是有区别的,实际波形在按下和释放的瞬间都有抖动的现象,抖动时间的长短和按键的机械特性有关,一般为5~10ms。通常我们手动按键然后释放,这个动作中稳定闭合的时间超过了20ms。因此单片机在检测键盘是否按下时都要加上去抖动操作,有专用的去抖动电路,也有专门的去抖动芯片,但通常我们采用软件延时的方法就可以解决抖动问题。


/*   软件去抖  */                                                                                                                                  
if (0 == K1)         //如果有键按下                                                                                                                  
{                                                                                                                                             
    delay_ms(8);     //延时一段时间去抖                                                                                                    
    if (0 == K1)     //如果真的有键按下,检测到得是稳定闭合状态                                                                                       
    {                                                                                                                               
        ...          //按键以后需要做的事情                                                                                
    }                                                                                                                              
    while (!K1);     //松手检测,如果按住不放则一直在循环里                                                                                      
}

 

 

2016-07-06 07:39:25 softn 阅读数 709
  • 按键-第1季第9部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第9个课程,综合解决了独立按键和矩阵式按键的处理方法,涉及到:IO的输入输出、按键抖动和消抖、中断的引入和相关概念、矩阵式键盘的原理和编程等。目的是对单片机常见输入设备按键进行全方位学习。

    2179 人正在学习 去看看 朱有鹏
原理搞清楚了,那么下面我们就先编写一个独立按键的程序,把最基本的功能验证一下。
  1. #include <reg52.h>
  2. sbit ADDR0 = P1^0;
  3. sbit ADDR1 = P1^1;
  4. sbit ADDR2 = P1^2;
  5. sbit ADDR3 = P1^3;
  6. sbit ENLED = P1^4;
  7. sbit LED9 = P0^7;
  8. sbit LED8 = P0^6;
  9. sbit LED7 = P0^5;
  10. sbit LED6 = P0^4;
  11. sbit KEY1 = P2^4;
  12. sbit KEY2 = P2^5;
  13. sbit KEY3 = P2^6;
  14. sbit KEY4 = P2^7;
  15. void main(){
  16. ENLED = 0; //选择独立 LED 进行显示
  17. ADDR3 = 1;
  18. ADDR2 = 1;
  19. ADDR1 = 1;
  20. ADDR0 = 0;
  21. P2 = 0xF7; //P2.3 置 0,即 KeyOut1 输出低电平
  22. while (1){
  23. //将按键扫描引脚的值传递到 LED 上
  24. LED9 = KEY1; //按下时为 0,对应的 LED 点亮
  25. LED8 = KEY2;
  26. LED7 = KEY3;
  27. LED6 = KEY4;
  28. }
  29. }
本程序固定在 KeyOut1 上输出低电平,而 KeyOut2~4 保持高电平,就相当于是把矩阵按键的第一行,即 K1~K4 作为 4 个独立按键来处理,然后把这 4 个按键的状态直接送给LED9~6 这 4 个 LED 小灯,那么当按键按下时,对应按键的输入引脚是 0,对应小灯控制信号也是 0,于是灯就亮了,这说明上述关于按键检测的理论都是可实现的。

绝大多数情况下,按键是不会一直按住的,所以我们通常检测按键的动作并不是检测一个固定的电平值,而是检测电平值的变化,即按键在按下和弹起这两种状态之间的变化,只要发生了这种变化就说明现在按键产生动作了。

程序上,我们可以把每次扫描到的按键状态都保存起来,当一次按键状态扫描进来的时候,与前一次的状态做比较,如果发现这两次按键状态不一致,就说明按键产生动作了。当上一次的状态是未按下而现在是按下,此时按键的动作就是“按下”;当上一次的状态是按下而现在是未按下,此时按键的动作就是“弹起”。显然,每次按键动作都会包含一次“按下”和一次“弹起”,我们可以任选其一来执行程序,或者两个都用,以执行不同的程序也是可以的。下面就用程序来实现这个功能,程序只取按键 K4 为例。
  1. #include <reg52.h>
  2. sbit ADDR0 = P1^0;
  3. sbit ADDR1 = P1^1;
  4. sbit ADDR2 = P1^2;
  5. sbit ADDR3 = P1^3;
  6. sbit ENLED = P1^4;
  7. sbit KEY1 = P2^4;
  8. sbit KEY2 = P2^5;
  9. sbit KEY3 = P2^6;
  10. sbit KEY4 = P2^7;
  11. unsigned char code LedChar[] = { //数码管显示字符转换表
  12. 0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
  13. 0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
  14. };
  15. void main(){
  16. bit backup = 1; //定义一个位变量,保存前一次扫描的按键值
  17. unsigned char cnt = 0; //定义一个计数变量,记录按键按下的次数
  18. ENLED = 0; //选择数码管 DS1 进行显示
  19. ADDR3 = 1;
  20. ADDR2 = 0;
  21. ADDR1 = 0;
  22. ADDR0 = 0;
  23. P2 = 0xF7; //P2.3 置 0,即 KeyOut1 输出低电平
  24. P0 = LedChar[cnt]; //显示按键次数初值
  25. while (1){
  26. //当前值与前次值不相等说明此时按键有动作
  27. if (KEY4 != backup){
  28. //如果前次值为 0,则说明当前是由 0 变 1,即按键弹起
  29. if (backup == 0){
  30. cnt++; //按键次数+1
  31. //只用 1 个数码管显示,所以加到 10 就清零重新开始
  32. if (cnt >= 10){
  33. cnt = 0;
  34. }
  35. P0 = LedChar[cnt]; //计数值显示到数码管上
  36. }
  37. backup = KEY4; //更新备份为当前值,以备进行下次比较
  38. }
  39. }
  40. }
先来介绍出现在程序中的一个新知识点,就是变量类型——bit,这个在标准 C 语言里边是没有的。51 单片机有一种特殊的变量类型就是 bit 型。比如 unsigned char 型是定义了一个无符号的 8 位的数据,它占用一个字节(Byte)的内存,而 bit 型是 1 位数据,只占用 1 个位(bit)的内存,用法和标准 C 中其他的基本数据类型是一致的。它的优点就是节省内存空间,8 个bit 型变量才相当于 1 个 char 型变量所占用的空间。虽然它只有 0 和 1 两个值,但也已经可以表示很多东西了,比如:按键的按下和弹起、LED 灯的亮和灭、三极管的导通与关断等等,联想一下已经学过的内容,它是不是能用最小的内存代价来完成很多工作呢?

在这个程序中,我们以 K4 为例,按一次按键,就会产生“按下”和“弹起”两个动态的动作,我们选择在“弹起”时对数码管进行加 1 操作。理论是如此,大家可以在板子上用K4 按键做做实验试试,多按几次,是不是会发生这样一种现象:有的时候我明明只按了一下按键,但数字却加了不止 1,而是 2 或者更多?但是我们的程序并没有任何逻辑上的错误,这是怎么回事呢?于是我们就得来说说按键抖动和消抖的问题了。

单片机独立按键

阅读数 2871

没有更多推荐了,返回首页