Chinaunix首页 | 论坛 | 博客
  • 博客访问: 300676
  • 博文数量: 101
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 150
  • 用 户 组: 普通用户
  • 注册时间: 2013-12-07 07:42
文章分类

全部博文(101)

文章存档

2016年(12)

2015年(48)

2014年(41)

我的朋友

分类: C/C++

2014-03-18 13:30:12

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

 

key.c 文件内容

 

#include

#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<

                     DelayMs(1);

                     temp = P2;

                     temp &= 0x3C;

                     if(temp == 0x3c)

                     {

                            rowvalue = rowvalue<

                            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;

        }

   }

 }

 

main.c中的调用方法为

 

              if(Key_Pressed == 1)

              {

                     //Key_Pressed = 0;

                     Scan_Key();

              }

              if(Key_Released == 1)

              {

                     Key_Released = 0;

                     Ack_Key();

              }

 

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

 

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

阅读(1819) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~