搜索
bottom↓
回复: 20

发我写的3*3矩阵按键扫描程序,可以最多拓展到8*8共64个按键。

[复制链接]

出0入0汤圆

发表于 2007-8-30 14:57:45 | 显示全部楼层 |阅读模式
文件keyboard.h:

/*

按键扫描程序工作原理说明:

按键扫描采取行线扫描输出高电平列线扫描接收的方式进行工作

首先在一根行线上输出一个高电平,然后列线扫描接收,如果其

中有按键按下则按键所在列线上接收到高电平信号否则为低,从

而根据接收到高电平时行列编号可确定按键编号。

*/

#ifndef _KEYBOARD_H_

#define _KEYBOARD_H_

#include <iom16v.h>

#include "define.h"



#define KEYSUM 9                        ///按键数量

#define HANGSUM 3                ///按键行数

#define LIESUM 3                        ///按键列数

#define HANGSTART 0                ///按键行起始端口号

#define LIEEND 6                        ///按键列末位端口号

#define KEYOUT PORTB        ///按键扫描高电平输出端口       

#define KEYIN PINB                ///按键扫描输入端口





struct key

{

uchar keynum; ///按键编号

uchar keyconter; ///按键灵敏度

uchar keyburstmode; ///按键触发方式0为延时电平触发1为按下触发2为抬起触发

}; ///按键键值缓冲区





extern volatile uchar nowkeynum;        ///当前按键编号        无按键按下时为0



/*!

* \brief 按键扫描程序

*

*读入按键键值并写入全局变量nowkeynum

*

* \return 按键键值

*/

uchar keyscan(void);



#endif



**********************************************************************

文件keyboard.c:

#include "keyboard.h"

/*按键记录电平计数缓冲区

每次扫描有按键按下记录缓冲区加1,直到超过按键灵敏度值。如无按键按下则清零。

*/

uchar keytmp[KEYSUM + 1] =

{

  0, 0, 0, 0, 0, 0, 0, 0, 0, 0

};



/*按键记录缓冲区

当使用沿触发方式时记录按键状态

*/

uchar keytmpnow[KEYSUM + 1] =

{

  0, 0, 0, 0, 0, 0, 0, 0, 0, 0

};



/*按键记录历史缓冲区

当使用沿触发方式时记录上一次按键状态

*/

uchar keytmpold[KEYSUM + 1] =

{

  0, 0, 0, 0, 0, 0, 0, 0, 0, 0

};



/*按键声明区

定义各个按键属性

*/

const struct key keyunit[KEYSUM + 1] =

{

  0, 1, 0,  ///

  1, 2, 1,  ///

  2, 5, 0,  ///

  3, 5, 0,  ///

  4, 5, 0,  ///       

  5, 5, 0,  ///

  6, 5, 0,  ///

  7, 5, 0,  ///

  8, 5, 0,  ///

  9, 5, 0,  ///

};



uchar keyscan(void)

{

  uchar loop1 = 0; ///行扫描循环控制

  uchar loop2 = 0; ///列扫描循环控制

  uchar keynumtmp = 0; ///按键编号缓存

  uchar keyloopmasklie = 0; ///列扫描掩码       

  ///列扫描掩码设定

  keyloopmasklie |= (1 << LIEEND);

  KEYOUT = 0x00;

  for (loop1 = 0; loop1 < HANGSUM; loop1++)

  {

    ///置行线

    KEYOUT |= (1 << (loop1 + HANGSTART));



    for (loop2 = 0; loop2 < LIESUM; loop2++)

    {

      keynumtmp = loop1 * LIESUM + loop2 + 1; ///计算出当前正在处理的按键编号



      ///判断按键的触发方式然后执行相应的判断程序

      switch (keyunit[keynumtmp].keyburstmode)

      {

        ///电平触发

        case 0:

          {

            ///如果有键按下相应键值计数器加1

            if ((KEYIN &keyloopmasklie) != 0)

            {

              keytmp[keynumtmp]++;

              ///如果计数器计数超出灵敏度设定值有效按键键值赋值

              if (keytmp[keynumtmp] >= keyunit[keynumtmp].keyconter)

              {

                nowkeynum = keynumtmp;

                ///计数器计数保持最大值

                keytmp[keynumtmp] = keyunit[keynumtmp].keyconter;

                return nowkeynum;

              }

            }

            ///没有按键按下相应按键计数寄存器清零

            else

            {

              keytmp[keynumtmp] = 0;

            }

          }

          break;

        ///按下触发       

        case 1:

        ///抬起触发       

        case 2:

          {

            ///如果有键按下相应键值计数器加1

            if ((KEYIN &keyloopmasklie) != 0)

            {

              keytmp[keynumtmp]++;

            }

            ///没有按键按下相应按键计数寄存器清零

            else

            {

              keytmp[keynumtmp] = 0;

            }



            ///如果计数器计数超出灵敏度设定值按键键值赋高

            if (keytmp[keynumtmp] >= keyunit[keynumtmp].keyconter)

            {

              ///置当前按键电平状态为高

              keytmpnow[keynumtmp] = HIGH;

              ///计数器计数保持最大值

              keytmp[keynumtmp] = keyunit[keynumtmp].keyconter;

              ///按下触发       

              if (keyunit[keynumtmp].keyburstmode == 1)

              {

                ///上升沿

                if (keytmpold[keynumtmp] == LOW && keytmpnow[keynumtmp] == HIGH)

                {

                  nowkeynum = keynumtmp;

                  keytmpold[keynumtmp] = keytmpnow[keynumtmp];

                  return nowkeynum;

                }

              }

            }

            else

            {

              ///置当前按键电平状态为低

              keytmpnow[keynumtmp] = LOW;

              ///抬起触发       

              if (keyunit[keynumtmp].keyburstmode == 2)

              {

                ///下降沿

                if (keytmpold[keynumtmp] == HIGH && keytmpnow[keynumtmp] == LOW)

                {

                  nowkeynum = keynumtmp;

                  keytmpold[keynumtmp] = keytmpnow[keynumtmp];

                  return nowkeynum;

                }

              }

            }

            ///按键记录推移

            keytmpold[keynumtmp] = keytmpnow[keynumtmp];

          }

          break;

      }

      keyloopmasklie >>= 1;

    }



    ///列扫描掩码设定

    keyloopmasklie = 0;

    keyloopmasklie |= (1 << LIEEND);



    ///复位行线到KL1

    KEYOUT = 0x00;

  }

  nowkeynum = 0;

  return nowkeynum;

}

*********************************************************************************

主程序中定义

volatile uchar nowkeynum = 0;         ///当前按键编号        无按键按下时为0

*********************************************************************************



程序说明:

本程序适用于3*3矩阵键盘。输入,输出均使用PB口,也可以改为其他口,和其他行列数,更改

keyboard.h中的声明部分即可。

本按键扫描程序可选择电平触发或者沿触发方式,最后的按键键值存在变量nowkeynum中。

使用时在各位的原文件中包含上面的keyboard.h和keyboard.c文件并在主程序中定义

volatile uchar nowkeynum = 0;

然后就可以调用keyscan();读出键值了。

推荐使用定时器定时调用的方式来完成按键扫描操作。



对程序如有疑问请在后面留言,欢迎各位大虾帮忙测试,大家共同提高。

***********************************************************************************

程序本人原创,版权没有,各位可以随意使用。

如需转载请注明本人ID和OURAVR即可。

出0入0汤圆

 楼主| 发表于 2007-8-30 15:05:25 | 显示全部楼层
程序使用ICCAVR 6.31编译。

器件是mega16.

当然了,用GCC,IAR也没有问题的。改动很小的。要换其他器件的话只要换头文件里面包含的文件名(#include <iom16v.h> )就行了。

出0入0汤圆

发表于 2007-8-30 15:10:16 | 显示全部楼层
这么复杂啊 哈哈

出0入0汤圆

 楼主| 发表于 2007-8-30 15:11:24 | 显示全部楼层
文件define.h中定义了

#define uchar unsigned char

#define HIGH 1                ///高电平

#define LOW 0                ///低电平

出0入0汤圆

 楼主| 发表于 2007-8-30 15:12:33 | 显示全部楼层
是挺复杂的,但是一劳永逸啊,以后只要是8*8以下的按键都可以通吃啦。

出0入0汤圆

发表于 2007-8-30 16:10:40 | 显示全部楼层
谢谢, 学习中

出0入0汤圆

 楼主| 发表于 2007-8-31 10:47:41 | 显示全部楼层
优化了一下程序,增加了一个变量keynumtmp存放当前正在处理的按键编号,不用每次用到这个编号时都要算一次乘法了,运行速度估计能快一些。

排版也调好了,不容易啊。。。。。

为什么帖子里面显示不了制表符呢?

出0入0汤圆

 楼主| 发表于 2007-11-12 22:07:57 | 显示全部楼层
看来最近要键盘程序的人还不少哈,把我做的顶出来!嘿嘿。

出0入0汤圆

发表于 2007-11-13 12:54:56 | 显示全部楼层
如果我需要采集《组合》键呢?嘿嘿!

出0入0汤圆

发表于 2007-11-13 13:17:31 | 显示全部楼层
这也太麻烦了吧,采用行列反转法吧。程序速度快,组合键也非常容易。

出0入0汤圆

发表于 2007-11-13 20:56:07 | 显示全部楼层
前几天写的..4*4按键...

/**********************************************/
/*函 数 名:void key(void)                    */
/*功    能: 按键值读取                        */
/*说    明: key_data:按键值:0~15对应16个按键  */
/*入口参数:无                                */
/*返 回 值:无                                */
/**********************************************/
void key(void)
{
  unsigned char hang,lie;
  for(hang=0;hang<4;hang++)
   {
    PORTC=~(0x01<<hang);
        _delay_us(50);
        lie=PINC&0xf0;
    if(lie!=0xf0)
         {
          key_data=hang*4;
          switch (lie)
           {
            case 0xe0://key_data+=0;
                           break;
               
            case 0xd0: key_data+=1;
                             break;
                                       
            case 0xb0: key_data+=2;
                            break;
                       
            case 0x70: key_data+=3;
                            break;
              }
          }
    }
}

出0入0汤圆

发表于 2007-11-14 09:54:59 | 显示全部楼层
有个电路图就更直观了.

出0入0汤圆

发表于 2007-11-14 11:21:54 | 显示全部楼层
同上!

出0入0汤圆

 楼主| 发表于 2008-4-19 11:39:02 | 显示全部楼层

(原文件名:AA.png)

出0入0汤圆

发表于 2010-9-12 22:12:24 | 显示全部楼层
hyz_avr 红尘你太厉害了,程序简洁明朗

出0入0汤圆

发表于 2010-9-13 07:21:20 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-1-9 21:08:23 | 显示全部楼层
mark!!

出0入0汤圆

发表于 2011-1-9 22:22:55 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-4-8 19:59:04 | 显示全部楼层
好复杂,有没简单点的程序,我是菜鸟,谢谢!
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-6 04:42

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表