zoukankan      html  css  js  c++  java
  • ATmega8仿真——键盘扫描的学习

    1.按键的使用特点

      按键的应用主要是在按键闭合时改变电路的电平,但是一般情况下按键的开关都是机械弹性触点开关,即利用触点的接触和分离来实现电路的通断,所以在按键按下和释放时往往会产生抖动干扰。

    消除抖动干扰的两种方式:

      (1)硬件设计:硬件消抖要在硬件设计上增加消抖电路,如用R-S触发器等,这样就会增加系统成本。

      (2)软件设计:在软件中对按键进行二次测试确认,即当第一次检测到按键被按下后,间隔10 毫秒左右再次检测该按键是否被按下,只有两次都册到按键按下时才确认该按键被按下了,从而消除抖动干扰。

    2.单键盘扫描应用

    用PB口接一个LED数码管,来显示按下按键的次数;

    用PC0端口接一个按键电路;

      实现的功能是每一次按键,LED数码管显示的数据加1,到9回0。

     1 #include <iom8v.h>
     2 #include "Delay.h"
     3 /**
     4   *PB口:连接一个LED数码管
     5   *PC0:连接一个按键电路,按下呈低电平
     6   *
     7   */
     8 unsigned char CountNum; //全局变量,用来计数
     9 
    10 //按键扫描函数
    11 void ScanKey(void)
    12 {
    13     unsigned char key;
    14     
    15     key = PINC; //检测按键状态
    16     if(0x01 == key) //未按下,退出
    17         return;
    18     delay_ms(10);
    19     
    20     key = PINC;  //再次检测,防抖动
    21     if(0x01 == key) //未按下,退出
    22         return;
    23     CountNum++;
    24     while(0 == key&0x01) //等到按键释放
    25         key = PINC;
    26 }
    27 
    28 //主函数,扫描按键显示数据
    29 void main()
    30 {
    31     unsigned char num[10] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
    32     //初始化端口
    33     DDRB = 0xFF; //设置B口为输出模式
    34     PORTB = 0xFF; //置高电平
    35     DDRC = 0x00; //设置C口为输入模式
    36     
    37     CountNum = 0; //初始化全局变量
    38     while(1)
    39     {
    40         ScanKey(); //扫描按键
    41         if(CountNum >= 10)
    42             CountNum -= 10;
    43         PORTB = num[CountNum];
    44     }
    45 }
    46 
    47 //按键长按的情况
    48 void ScanKey_Long(void)
    49 {
    50     unsigned char key;
    51     
    52     key = PINC; //检测按键状态
    53     if(0x01 == key) //未按下,退出
    54         return;
    55     delay_ms(10);
    56     
    57     key = PINC;  //再次检测,防抖动
    58     if(0x01 == key) //未按下,退出
    59         return;
    60         
    61     while(0x00 == key) //按键长按,不断加加
    62     {
    63         CountNum++;
    64         key = PINC;
    65     }
    66 }
    按键一次LED加一

     问:上面的程序没有考虑长按的情况,如果向我们使用的键盘一样,长时间按下一个按键,在屏幕上就不断的打印该字符,在这个例子里怎样实现:若长时间按下按键,CountNum就不断加加?

    答:只需要更改ScanKey函数,更改结果如下

     1 //按键长按的情况
     2 void ScanKey_Long(void)
     3 {
     4     unsigned char key;
     5     
     6     key = PINC; //检测按键状态
     7     if(0x01 == key) //未按下,退出
     8         return;
     9     delay_ms(10);
    10     
    11     key = PINC;  //再次检测,防抖动
    12     if(0x01 == key) //未按下,退出
    13         return;
    14         
    15     while(0x00 == key) //按键长按,不断加加
    16     {
    17         CountNum++;
    18         key = PINC;
    19     }
    20 }
    长按按键不断加加

    3.矩阵按键(键盘)扫描的应用

      按键太多的情况下,为了节省I/O资源,通常采用矩阵式的接口。矩阵键盘由行和列组成,每个键都有它的行值和列值,行值和列值的组合就是识别每个键盘的编码。

    确定是哪个按键的流程:(???)

    (1)在行和列的一个口中输出高电平,在另一个行列口读取一个扫描码;

    (2)在后一个行列口中输出高电平,在前一行列口读取第二个扫描码;

    (3)查表确定哪个按键被按下。

    电路图如下:

    程序实现步骤:

    (1)确定有无按键按下;

    (2)确定是哪个按键;

    (3)返回该按键值或处理对应的任务;

    (4)再加上,考虑抖动消除,等待按键的断开。

    要实现每按下一个按键,就在LED数码管显示出该按键对应的值,按键断开后或默认显示“-”:

      1 #include <iom8v.h>
      2 #include "Delay.h"
      3 /**
      4   *PB口:连接一个LED数码管
      5   *PC0-PC5:连接9个按键电路,按下呈低电平
      6   *        PC0-PC2:按键的行
      7   *        PC3-PC5:按键的列
      8   *
      9   *1:确定有无按键按下,main函数两次判断实现;
     10   *2:确定是哪个按键,ScanKey函数实现;
     11   *3:返回该键值或处理对应的任务,main函数中处理。
     12   */
     13   
     14 
     15 //按键扫描函数,确定是哪个按键,返回按键的值
     16 unsigned char ScanKey(void)
     17 {
     18     unsigned char tempH,tempL,key;
     19     
     20     tempH = PINC & 0x07; //取PC0-PC2用于判断行
     21     switch (tempH)
     22     {
     23         case 0x06:
     24             DDRC = 0x07; PORTC = 0x38;//将PC3-PC5(列)置为输入模式
     25             delay_us(1);
     26             tempL = PINC & 0x38; //取PC3-PC5用于判断列
     27             switch (tempL)
     28             {
     29                 case 0x30: key = 0x01; //得到键值
     30                     break;
     31                 case 0x28: key = 0x02;
     32                     break;
     33                 case 0x18: key = 0x03;
     34                     break;
     35                 default:   key = 0;
     36                     break;
     37             }
     38             DDRC = 0x38; PORTC = 0x07;//输入完毕恢复默认输出模式
     39             break;
     40             
     41         case 0x05:
     42             DDRC = 0x07; PORTC = 0x38;//将PC3-PC5(列)置为输入模式
     43             delay_us(1);
     44             tempL = PINC & 0x38; //取PC3-PC5用于判断列
     45             switch (tempL)
     46             {
     47                 case 0x30: key = 0x04; //得到键值
     48                     break;
     49                 case 0x28: key = 0x05;
     50                     break;
     51                 case 0x18: key = 0x06;
     52                     break;
     53                 default:   key = 0;
     54                     break;
     55             }
     56             DDRC = 0x38; PORTC = 0x07;//输入完毕恢复默认输出模式
     57             break;
     58             
     59         case 0x03:
     60             DDRC = 0x07; PORTC = 0x38;//将PC3-PC5(列)置为输入模式
     61             delay_us(1);
     62             tempL = PINC & 0x38; //取PC3-PC5用于判断列
     63             switch (tempL)
     64             {
     65                 case 0x30: key = 0x07; //得到键值
     66                     break;
     67                 case 0x28: key = 0x08;
     68                     break;
     69                 case 0x18: key = 0x09;
     70                     break;
     71                 default:   key = 0;
     72                     break;
     73             }
     74             DDRC = 0x38; PORTC = 0x07;//输入完毕恢复默认输出模式
     75             break;
     76             
     77         default:
     78             key = 0;
     79             break;
     80     }
     81     return (key);
     82     
     83 }
     84 
     85 //主函数,扫描按键显示数据
     86 void main()
     87 {
     88     unsigned char temp,keynum;
     89     unsigned char num[10] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
     90     //初始化端口
     91     DDRB = 0xFF; //设置B口为输出模式
     92     PORTB = 0xFF; //置高电平
     93         //将PC0-PC2(行)置为输入模式
     94     DDRC = 0x38;
     95     PORTC = 0x07;
     96     
     97     while(1) //两次检测行中有没有按下
     98     {
     99         PORTC = 0x40; //没有按键时,LED默认显示-
    100         //第一次检验
    101         temp = PINC & 0x07;
    102         if(0x07 == temp)
    103             continue;
    104         delay_ms(10);
    105         //第二次检验
    106         temp = PINC & 0x07;
    107         if(0x07 == temp)
    108             continue;
    109         
    110         //有按下,LED显示键值
    111         keynum = ScanKey();
    112         PORTB = num[keynum];
    113         //等到按键被释放
    114         while(0x07 != temp)
    115             temp = PINC & 0x07;
    116     }
    117 }
    矩阵键盘,LED显示其值

    代码总结:

      主函数:判断是否有按键按下,并消除抖动干扰,若有则将获得的键值显示在LED数码管中;

      ScanKey函数:得到扫描码确定是哪个按键,等待按键释放,返回该按键的值。

    方法扩展:

    (1)除了像上面的对按键的接口不停的扫描,

    (2)还可以使用定时扫描,例如用一个定时器,每隔10MS 对按键接口进行扫描,看是否有按键按下;

    (3)也可以使用中断的方式去扫描,当按键按下时由硬件电路产生一个中断,MCU 响应该中断,确定哪个按键被按下,处理相应函数。

  • 相关阅读:
    javascript封装与多态的体现
    js事件处理、事件对象
    对js中this的一点点理解
    js中的位运算
    css中的各种单位简述以及ios10下safari禁止缩放的问题
    js变量提升
    Web Worker javascript多线程编程(一)
    MongoDB数据库备份和恢复
    什么是Git及Git的诞生
    MongoDB安装过程
  • 原文地址:https://www.cnblogs.com/Christal-R/p/6912229.html
Copyright © 2011-2022 走看看