51单片机教程(十)- 独立按键输入

打印 上一主题 下一主题

主题 998|帖子 998|积分 2994

1、项目分析



  • 单片机也需要人机交互,掌握常用的输入和输出装备非常须要。
  • 本章选取了最常用的输入模块键盘来演示其典范程序的体例方法。
2、技能准备

1 独立键盘输入



  • P3口第二功能表

  • P3.0—P3.7: 双功能口(内置了上拉电阻) 它具有特定的第二功能。
  • 在不利用它的第二功能时它就是平常的通用准双向I/O口。



  • 读端口和读引脚

    • 读端口:就是读Pn端口寄存器;
    • 读引脚:就是读该引脚在Pn端口寄存器中的对应位,通过引用Pn端口寄存器的值,或者引用Pn端口寄存器中的对应位,就可以实现读端口或者读引脚。

2 认识按键



  • 轻触开关是一种电子开关,利用时,轻轻按开关按钮就可使开关接通,当松开手时,开关断开。

3 按键分类



  • 键盘输入检测的基本方法:

    • 轮询法

1. 独立按键



  • 每一个按键对应每一个引脚,相当于一个按键控制一个引脚

2. 矩阵按键



  • 矩阵按键能控制的东西比较多,利用的引脚也比较多,如果每一个按键控制一个引脚,那么需要16个引脚,若利用矩阵式键盘,则仅需1个引脚组即可,但程序计划相对复杂一些。

  • 矩阵式键盘的识别方法
1. 逐列扫描法


  • 判断键盘是否按键按下,方法是向全部列线上输入低电平,再读入全部行信号,如果16个按键中恣意一个按键被按下,则读入的行电平则不全为高;反之如无按键按下,则读入的行电平全为高。若S10被按下,则S10按键所在的行线2与列线1导通,则行线的电平被拉低,读入的行信号为低电平,则表示按键已经被按下(现还无法判断是S9、S10、S11、S12被按下)。
  • 逐列扫描判断具体的按键,方法是向列线上逐列送低电平,现送到列线0,列线1、2、3为高电平,读入的行电平的状态就显示了位于列线0的S1、S5、S9、S13四个按键的按键的状态。若键入的行值为全高,则表示无按键按下;在送到列线1,列线0、2、3为高电平,读入的行电平状态则显示S2、S6、S10、S14四个按键的按键的状态,依次类推,直到全部扫描完毕。
2. 行列反转法


  • 基本原则:通过给行列端口输出两次相反的值,再分别读入的行值和列值进行 求和按位 或 运算,得到每个键的扫描码。

    • 向全部的列线上输入低电平,列线输入2次相反的值。
    • 读入行信号,如果16个按键中恣意一个按键被按下,读入的行信号则不全为高,反之,则行信号则全为高,记录现在的值。
    • 向全部的列线上出高电平,行线输入低电平(行列反转),读入全部的列信号,记录现在的值。
    • 将行和列的值合并成扫描码。通过查找扫描码表的方法得出 “哪个按键被按下”。

  • 具体实现过程:

    • 起首,给P1口输入0xf0,即:11110000,若S10按键被按下,则读入的P1的值为:11010000,在给P1赋相反的值0x0f,即:11110000,此时读入的P1口的值为:00001011,再次把读入的P1的值进行相加或按位 “或” 操作,得到:11011011,即0xdb,这个值是按键S1的扫描码,以此类推,得到别的15个按键的扫描码。


3 按键抖动



  • 按键中有一个金属弹片,当按下按键时会挤压金属弹片来导通电流,而松手时金属弹片会弹归去,在其闭合、断开瞬间均有抖动过程,抖动时间一样寻常在5—10ms。
  • 按下和松手都会让金属弹片有抖动,这个抖动的电流是不稳固的,会影响程序对按键的判断。



  • 解决方法

    • 硬件处理方法:利用另一种没用抖动或者抖动频率小的硬件。
    • 软件处理方法:利用程序来超过这个抖动,也就是用一个延迟函数来将这个按下的抖动时间消除(消抖)。

4 按键原理图






  • 判断按键按下的实现方法


  • 先判断键是否按下,若按下了延时10 ms,跳过按下抖动期。
  • 再判断按键是否按下,若是说明按键真的按下了,否则说明是干扰信号,如果键真的按下了,则等候键开释,如果键开释了,延时10 ms,
  • 再判断键是否开释,若开释了,说明按键真的开释了,否则说明是干扰信号,如果按键真的开释了,说明一次完整的按键过程完成了。
3、项目实现

1 1个按键控制1个LED灯亮灭



  • 实行要求

    • 按下K2 则LED1亮,再次按下LED1灭,如此循环。

  • 实行分析

    • 判断按键是否按下,按下则对LED灯的状态取反。

  • 实行代码
    1. #include <reg52.h>
    2. // 2、定义端口:按键/LED
    3. sbit key = P3^4;
    4. sbit led = P1^0;
    5. void delay(unsigned int v);
    6. void main()
    7. {
    8.    while(1)
    9.    {
    10.            // 3、判断按键是否按下:按下key对应的电平值为0
    11.            if(key == 0)
    12.            {
    13.                    // 消抖 - 10ms
    14.                    delay(1000);
    15.                   
    16.                    // 再次判断按键是否按下
    17.                    if(key == 0)
    18.                    {
    19.                            // 按键是按下:电平值为0趋于稳定
    20.                           
    21.                            // 方法1:判断led的状态,如果是电平值为0,则设置为1,否则设置为0
    22. //                                if(led == 1){
    23. //                                        led = 0;
    24. //                                }else{
    25. //                                        led = 1;
    26. //                                }
    27.                           
    28.                            // 方法2:对LED状态值取反
    29.                            led = !led;
    30.                    }
    31.            }
    32.    }
    33. }
    34. // 延迟函数
    35. void delay(unsigned int v)
    36. {
    37.    while(v--);
    38. }
    复制代码

2 4个按键控制4个LED灯



  • 实行要求

    • 按下第1个独立按键K2 2个赤色的led灯亮
    • 按下第2个独立按键K3 2个绿色的led灯亮
    • 按下第3个独立按键K4 2个黄色的led灯亮
    • 按下第4个独立按键K5 2个蓝色的led灯亮

  • 实行分析

    • 若分别独立判断K2-K5是否按下,则代码冗余,可以编写函数用于扫描哪个按键按下并返回,通过返回值判断,实现LED的亮灭控制。




  • 实行代码
    1. #include <reg52.h>
    2.        
    3. #define uint unsigned int
    4.        
    5. // 定义端口:4个按键/LED
    6. sbit key2 = P3^4;
    7. sbit key3 = P3^5;
    8. sbit key4 = P3^6;
    9. sbit key5 = P3^7;
    10. sbit led1 = P1^0;
    11. sbit led2 = P1^2;
    12. sbit led3 = P1^4;
    13. sbit led4 = P1^6;
    14. // 定义按键的取值
    15. #define KEY2_PRESS 2
    16. #define KEY3_PRESS 3
    17. #define KEY4_PRESS 4
    18. #define KEY5_PRESS 5
    19. #define KEY_UNPRESS 0
    20. uint key_scan(uint mode);
    21. void delay(unsigned int v);
    22. void main()
    23. {
    24.         while(1)
    25.         {
    26.                 // 表示获取哪个按键被按下
    27.                 uint key_value = key_scan(1);   // 返回值:0 2 3 4 5
    28.                
    29.                 // 判断对应的按键来实现LED灯控制
    30.                 switch(key_value){
    31.                         case KEY2_PRESS: led1 = !led1; break;
    32.                         case KEY3_PRESS: led2 = !led2; break;
    33.                         case KEY4_PRESS: led3 = !led3; break;
    34.                         case KEY5_PRESS: led4 = !led4; break;
    35.                 }
    36.         }
    37. }
    38. /*
    39.         功能:按键扫描函数
    40.         参数:
    41.                 mode: 表示按键扫描方式
    42.                         0:单次扫描
    43.                         1:连续扫描
    44.         返回值:
    45.                 2 表示K2按下
    46.                 3 表示K3按下
    47.                 4 表示K4按下
    48.                 5 表示K5按下
    49.                 0 表示无按键按下
    50. */
    51. uint key_scan(uint mode)
    52. {
    53.         // 定义按键的初始状态值
    54.         static uint key = 1;
    55.        
    56.         // 对模式的判断
    57.         if(mode) key=1;
    58.        
    59.         // 判断4个按键中是否按下
    60.         if(key==1 && (key2 == 0 || key3 == 0 || key4 == 0 || key5 == 0))
    61.         {
    62.                 // 消抖
    63.                 delay(1000);
    64.                 key = 0;
    65.                
    66.                 // 判断具体是哪个按键按下
    67.                 if(key2 == 0) return KEY2_PRESS;  // return 2
    68.                 if(key3 == 0) return KEY3_PRESS;  // return 3
    69.                 if(key4 == 0) return KEY4_PRESS;  // return 4
    70.                 if(key5 == 0) return KEY5_PRESS;  // return 5
    71.         }else if(key2 == 1 && key3 == 1 && key4 == 1 && key5 == 1){
    72.                 key = 1;
    73.         }
    74.         return KEY_UNPRESS;
    75. }
    76. // 延迟函数
    77. void delay(unsigned int v)
    78. {
    79.         while(v--);
    80. }
    复制代码
3 按键控制数码管显示



  • 实行要求

    • 按下按键1实现数码管+1;
    • 按下按键2实现数码管-1;
    • 按下按键3清零;

  • 实行分析

    • 先利用2位数码显示00-99,判断按键是否按下,则修改记录数据变量值加1,减1或者为0的设置,同时需当数值减为0则设置为0,当加到99则设置为99。




  • 实行代码
  1. #include <reg52.h>
  2. #include "delay.h"
  3. #define uint unsigned int
  4. // 定义位选与段选
  5. #define pos P2
  6. #define par P0
  7. // 定义端口:4个按键/LED
  8. sbit key2 = P3^4;
  9. sbit key3 = P3^5;
  10. sbit key4 = P3^6;
  11. sbit key5 = P3^7;
  12. // 定义按键的取值
  13. #define KEY2_PRESS 2
  14. #define KEY3_PRESS 3
  15. #define KEY4_PRESS 4
  16. #define KEY5_PRESS 5
  17. #define KEY_UNPRESS 0
  18. // 分别对应:0/1/2/3/4/5/6/7/8/9
  19. uint par_value[] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f};
  20. // 记录数码管显示值
  21. uint number = 3;
  22. uint ge, shi;
  23. uint keyScan(uint mode);
  24. void delay(uint v);
  25. void main()
  26. {
  27.         while(1)
  28.         {       
  29.                 uint key_value = keyScan(0);
  30.                
  31.                 // 判断对应的按键来控制数值是否越界控制
  32.                 if(key_value == KEY2_PRESS)
  33.                 {
  34.                         if(number == 99)
  35.                         {
  36.                                 number = 99;
  37.                         }else{
  38.                                 number++;
  39.                         }
  40.                 }
  41.                 else if(key_value == KEY3_PRESS)
  42.                 {
  43.                         if(number == 0)
  44.                         {
  45.                                 number = 0;
  46.                         }else{
  47.                                 number--;
  48.                         }
  49.                 }
  50.                 else if(key_value == KEY4_PRESS)
  51.                 {
  52.                         number = 0;
  53.                 }
  54.                
  55.                 shi = number / 10;
  56.                 ge = number % 10;
  57.                        
  58.                 // 显示十位
  59.                 pos = 0x18;
  60.                 par = par_value[shi];
  61.                 delay(100);
  62.                
  63.                 // 显示个位
  64.                 pos = 0x28;
  65.                 par = par_value[ge];
  66.                 delay(100);
  67.         }
  68. }
  69. uint keyScan(uint mode)
  70. {
  71.         // 定义按键的初始状态值
  72.         static uint key = 1;
  73.        
  74.         // 对模式的判断
  75.         if(mode) key=1;
  76.        
  77.         // 判断4个按键中是否按下
  78.         if(key==1 && (key2 == 0 || key3 == 0 || key4 == 0 || key5 == 0))
  79.         {
  80.                 // 消抖
  81.                 delay(5000);
  82.                 key = 0;
  83.                
  84.                 // 判断具体是哪个按键按下
  85.                 if(key2 == 0) return KEY2_PRESS;  // return 2
  86.                 if(key3 == 0) return KEY3_PRESS;  // return 3
  87.                 if(key4 == 0) return KEY4_PRESS;  // return 4
  88.                 if(key5 == 0) return KEY5_PRESS;  // return 5
  89.         }else if(key2 == 1 && key3 == 1 && key4 == 1 && key5 == 1){
  90.                 key = 1;
  91.         }
  92.         return KEY_UNPRESS;
  93. }
  94. // 延迟函数
  95. void delay(unsigned int v)
  96. {
  97.         while(v--);
  98. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

农妇山泉一亩田

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表