C51单片机矩阵键盘扫描去抖程序,新手必读

C51单片机矩阵键盘扫描去抖程序

 

最近有一个C51的项目,用的是新华龙的C51 F020单片机。项目中要实现4*5的矩阵键盘。矩阵电路图如下如示

 

其中,四条列线接在F020P2~P5口线上,5条行线接在P5口线上(F020P5口是不同于普通C51的扩展接口,不能位寻址)。同时4条列线接在一四输入与非门(74LS20)上,门输出接F020的外中断1,这样,任何一键按下,都会产生中断,通知程序进行键盘扫描。

 

托一个新手给写了键盘的扫描程序,基本功能都能实现,但对于键盘的去抖处理总是做不好,表现是或者不能去抖,或者按键响应过慢,或者采集到错误键值。看来新手对于矩阵键盘扫描原理掌握较好(网上资料多),但对于键盘去抖的知识却有所欠缺,基本都是按照书上说的延时一段时间再采集键值,实际应用中,这样的处理是远远不够的,过于简单。实际去抖处理应该这样进行更合理一些,即连续采集键值当采集到的键值在一段时间内是相同的,即认为按键状态已稳定,此键值为真实键值。另外,按键释放时,也会有抖动,导致误采键值,因此在键释放时,也应进行去抖处理,处理方法同时是连续一段时间采集到无键按下状态,才认为按键被释放。根据这个方法,我重写了新手的程序,实际应用中表现极好。

 

现将程序公布如下,供新手参考。

 

Key.h文件内容

#ifndef __key_H__
#define __key_H__
 
#define NULL_KEY 0x0000
#define S1    0x3801
#define S2    0x3401
#define S3        0x3802
#define S4        0x3402
#define S5        0x3804
#define S6        0x3404
#define S7        0x3808
#define S8        0x3408
#define S9        0x3810
#define S10      0x3410
#define S11       0x2C01
#define S12      0x1C01
#define S13      0x2C02
#define S14      0x1C02
#define S15      0x2C04
#define S16      0x1C04
#define S17      0x2C08
#define S18      0x1C08
#define S19      0x2C10
#define S20     0x1C10
 
#define KEY_DELAY 20
 
extern unsigned int Key_Value;
 
extern void Init_Key();
extern void Scan_Key();
 
extern bit Key_Pressed;
extern bit Key_Released;
extern unsigned int idata Keypress_Count;
extern unsigned int idata Keyrelease_Count;
 
#endif<span style="font-family: 'Times New Roman'; background-color: rgb(255, 255, 255);"> </span>


key.c 文件内容

#include <string.h>
#include "key.h"
 
bit Key_Down;                        //是否有键按下的标志
unsigned int idata Keypress_Count;
 
sbit Col_Key0 = P2^2;
sbit Col_Key1 = P2^3;
sbit Col_Key2 = P2^4;
sbit Col_Key3 = P2^5;
 
bit Key_Pressed;
bit Key_Released;
 
unsigned int Key_Value;
 
bit Key_Down;                        //是否有键按下的标志
unsigned int idata Keypress_Count;    //一毫秒增加一次的变量
unsigned int idata Keyrelease_Count; //一毫秒增加一次的变量
 
 
//矩阵键盘使用中断1作为键盘中断
 void Init_Key()
 {
      P5 = 0; //行线全部置为0
       EX1 = 1;                             // 允许外部时钟秒中断
       IT1 = 1;                              // 外部时钟中断设置为边沿触发
 }
 
void Key_Int() interrupt 2
 {
      Key_Pressed = 1;
       EX1 = 0;
}
 
 void Scan_Key()
 {
      unsigned char temp,rowvalue;
       unsigned int key;
       int i;
      
       temp = P2;
       temp &= 0x3C;
      
       if(temp == 0x3C)
       {
              Key_Released = 0;
              Key_Pressed = 0;
              key = NULL_KEY;
              EX1 = 1;
       }
       else
       {
              key = temp;
              key = key<<8;
      
              rowvalue = 0x01;
      
              for(i=0;i<5;i++)
              {
                     P5 = rowvalue<<i;
                     DelayMs(1);
                     temp = P2;
                     temp &= 0x3C;
                     if(temp == 0x3c)
                     {
                            rowvalue = rowvalue<<i;
                            key = key | rowvalue;
                            P5 = 0x00;
                            break;    
                     }
              }
              P5 = 0x00;
              DelayMs(1);
       }
    if(key!=NULL_KEY)              //如果有键按下
   {
        if(key==Key_Value)     //如果按下的是相同的键
        {
              if(Keypress_Count>=KEY_DELAY)
              {
                  Key_Down = 1;
              }
        }
        else if(Key_Down != 1)
        {
              Keypress_Count=0;
              Keyrelease_Count = 0;
              Key_Value=key;
        }
   }
   else                         //如果无键按下
   {
     if(Key_Down)        //如果当前是键释放,返回键值
        {
               if(Keyrelease_Count >= KEY_DELAY)
               {
                     Key_Down=0;
                  Keypress_Count=0;
                  Keyrelease_Count=0;
                     Key_Released = 1;
                     EX1 = 1;
                     return;
               }
        }   
      else
        {
               Keypress_Count=0;
               Keyrelease_Count=0;
               Key_Value = NULL_KEY;
               EX1 = 1;
               return;
        }
   }
 }
<span style="font-family: 'Times New Roman'; font-size: 14px; background-color: rgb(255, 255, 255);"> </span>

main.c中的调用方法为

 
              if(Key_Pressed == 1)
              {
                     //Key_Pressed = 0;
                     Scan_Key();
              }
              if(Key_Released == 1)
              {
                     Key_Released = 0;
                     Ack_Key();
              }
 


其中Ack_Key()函数为具体的键盘响应程序,就不列出了。

 

我在另外使用Arm9的项目中,linux底层扫描键盘的驱动中,也使用了这种去抖方法,同样表现良好。


转载于:http://blog.chinaunix.net/uid-11153816-id-2903467.html

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值