找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1904|回复: 12
打印 上一主题 下一主题
收起左侧

求教一个单片机矩阵按键的程序调试问题

[复制链接]
跳转到指定楼层
楼主
ID:100982 发表于 2022-7-21 08:40 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
    这段程序是摘录的51hei单片机论坛的教程,这里有个说明中断函数中扫描 KeyIn 输入和切换 KeyOut 输出的顺序与前面提到的顺序不同,程序中我首先对所有的 KeyIn 输入做了扫描、消抖,然后才切换到了下一次的 KeyOut 输出,也就是说我们中断每次扫描的实际是上一次输出选择的那行按键,这是为什么呢?因为任何信号从输出到稳定都需要一个时间,有时它足够快而有时却不够快,这取决于具体的电路设计,我们这里的输入输出顺序的颠倒就是为了让输出信号有足够的时间(一次中断间隔)来稳定,并有足够的时间来完成它对输入的影响,当你的按键电路中还有硬件电容消抖时,这样处理就是绝对必要的了,虽然这样使得程序理解起来有点绕,但它的适应性是最好的,换个说法就是,这段程序足够“健壮”,足以应对各种恶劣情况 。
    这里我不太明白,一开始进入中断的时候,keyout等于0,然后程序往下跑,keyout++,等于1了,case1,打开的是第二行。但是第二行并没有被拉低为0啊,这里不知道是为什么?
        不过我查阅了别的一些51的教程,关于矩阵按键这块,貌似没看到这么操作的,很是纳闷,有这个必要吗?别的程序都没这么写,包括它处理按键去抖的这个方法,哪种才是最优的呢?是这种还是别人直接写个delay()多少毫秒那种呢?

单片机源程序如下:
void InterruptTimer0() interrupt 1
{
unsigned char i;
static unsigned char keyout = 0; //矩阵按键扫描输出索引
static unsigned char keybuf[4][4] = { //矩阵按键扫描缓冲区
{0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF},
{0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF}
};
TH0 = 0xFC;
TL0 = 0x67;
//重新加载初值

//将一行的 4 个按键值移入缓冲区
keybuf[keyout][0] = (keybuf[keyout][0] << 1) | KEY_IN_1;
keybuf[keyout][1] = (keybuf[keyout][1] << 1) | KEY_IN_2;
keybuf[keyout][2] = (keybuf[keyout][2] << 1) | KEY_IN_3;
keybuf[keyout][3] = (keybuf[keyout][3] << 1) | KEY_IN_4;
//消抖后更新按键状态
for (i=0; i<4; i++) //每行 4 个按键,所以循环 4 次
{
if ((keybuf[keyout][ i] & 0x0F) == 0x00)
{ //连续 4 次扫描值为 0,即 4*4ms 内都是按下状态时,可认为按键已稳定的按下
KeySta[keyout]
[ i] = 0;
}
else if ((keybuf[keyout]
[ i] & 0x0F) == 0x0F)
{ //连续 4 次扫描值为 1,即 4*4ms 内都是弹起状态时,可认为按键已稳定的弹起
KeySta[keyout]
[ i] = 1;
[ i]}
[ i]}
//执行下一次的扫描输出
keyout++; //输出索引递增
keyout = keyout & 0x03; //索引值加到 4 即归零
switch (keyout) //根据索引,释放当前输出引脚,拉低下次的输出引脚
{
case 0: KEY_OUT_4 = 1; KEY_OUT_1 = 0; break;
case 1: KEY_OUT_1 = 1; KEY_OUT_2 = 0; break;
case 2: KEY_OUT_2 = 1; KEY_OUT_3 = 0; break;
case 3: KEY_OUT_3 = 1; KEY_OUT_4 = 0; break;
default: break;
}
}  

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:224003 发表于 2022-7-21 10:27 | 只看该作者
找版主的书,这个按键章节部分,你再仔细看看,对照实验,理解它
回复

使用道具 举报

板凳
ID:100982 发表于 2022-7-21 13:56 | 只看该作者
hzxyy 发表于 2022-7-21 10:27
找版主的书,这个按键章节部分,你再仔细看看,对照实验,理解它

看过了,请问有必要这么写吗?我看很多别 的书都不是这么写的。
回复

使用道具 举报

地板
ID:491577 发表于 2022-7-22 10:13 | 只看该作者
楼主是做工控的吧对按键抗干扰有要求,楼主只是考虑了按下的情况,按键释放没有考虑,同时按键也没有考虑,我写有一个按键检测程序,你参考一下。
这是按键检测模块函数:要认真看才能够理解。
void key() //按键处理模块,需要放在10ms中断中运行!!!
/* 说明:1、按键单击,指按下100-1000ms内释放,加入时间限制是为了防止干扰。
             2、按键长按,指按下3-10s内释放,加入时间限制是为了防止干扰。
             3、函数运行后,按键值保存在key1、key2。用户直接调用key1、key2即可。
*/
{
  u16 static kgr[4];    //必须要static,抗干扰时间数组
  u8  static kanggr[4]; //中间变量1
  u8  static anjtem[4]; //按键释放中间变量。
  u8 i;
  u8 L_anj[4];
  L_anj[0]=k1;
  L_anj[1]=k2;
  L_anj[2]=k3;
  L_anj[3]=k4;
  for(i=0;i<3;i++)  //4个按键处理,key1,
   {
         if(L_anj[ i]==0)        //按键按下                                       
          { if(kanggr[ i]==0)        //中间变量1,与下面互锁
             { kgr[ i]=0;                //抗干扰时间清零,每次按键只写1次。
               kanggr[ i]=1;         //中间变量1
               anjtem[ i]=1;         //按键释放中间变量。与下面互锁
            }

           if(anjtem[ i]==1)
           {
                  kgr[ i]++;//10毫秒计时。
                  if(kgr[ i]>1000) //按键按下大于10秒,强制复位,防止误按。
                   { anjtem[ i]=0; //按键释放中间变量。与上面互锁
                     kgr[ i]=0;
                   }
           }
         }

     else    //按键释放
     { kanggr[ i]=0;           //中间变量1,与上面互锁
           if(kgr[ i]>9 && kgr[ i]<99) //按键间隔100--1000毫秒才有效,防止电磁干扰。时间可以修改
                 key1=i+1;   //单击,按键间隔100--1000毫秒,每次释放只写1次。一次只能够按一个按键,不允许同时按键。
           else if(kgr[ i]>300 && kgr[ i]<1000) //按键间隔3000--10000毫秒才有效,防止电磁干扰。时间可以修改
                 key1=(i+1)*10;//长按,按键间隔3--10秒,每次释放只写1次。
     }
  }

//下面是处理:key2是有按键按下就输出键值。        
    for(i=0;i<3;i++)
         { if(L_anj[ i]==0)
           key2=i+1;//一次只能够按一个按键,不允许同时按键。
         }
}

完整的程序参考:http://www.51hei.com/bbs/dpj-208253-1.html

评分

参与人数 1黑币 +15 收起 理由
wpppmlah + 15 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

5#
ID:100982 发表于 2022-7-22 16:35 | 只看该作者
hhh402 发表于 2022-7-22 10:13
楼主是做工控的吧对按键抗干扰有要求,楼主只是考虑了按下的情况,按键释放没有考虑,同时按键也没有考虑, ...

哈,谢谢,不过你的变量全部都是汉语拼音,有点意思。
回复

使用道具 举报

6#
ID:491577 发表于 2022-7-23 13:54 | 只看该作者
本帖最后由 hhh402 于 2022-7-23 14:01 编辑
wifen 发表于 2022-7-22 16:35
哈,谢谢,不过你的变量全部都是汉语拼音,有点意思。

不会英语,不过单片机C语言英文不多,编程核心还是算法,怎么通过已知的几个变量计算出所需要的量。
回复

使用道具 举报

7#
ID:100982 发表于 2022-7-25 07:53 | 只看该作者
hzxyy 发表于 2022-7-21 10:27
找版主的书,这个按键章节部分,你再仔细看看,对照实验,理解它

看了也理解了,就是不知道这种写法优势何在,实际工程中的写法是怎样的呢?
回复

使用道具 举报

8#
ID:190577 发表于 2022-7-25 08:05 | 只看该作者
wifen 发表于 2022-7-21 13:56
看过了,请问有必要这么写吗?我看很多别 的书都不是这么写的。

小宋老师的书写的比较好的,他是利用状态机的思想来写的,释放了单片机,不是用延时函数完成的。每个人的程序写法都是不一样的,没必要纠结,只要别人的程序来过来会改加工完成自己的功能就OK了。
回复

使用道具 举报

9#
ID:190577 发表于 2022-7-25 08:08 | 只看该作者
wifen 发表于 2022-7-25 07:53
看了也理解了,就是不知道这种写法优势何在,实际工程中的写法是怎样的呢?

这种写法就是释放了单片机,单片机有更多的时间去干别的事情,而不是在延时等待,啥事也不干,实际的工程,实时要求不要就用delay函数就行了,对系统实时要求比较高的,就需要用状态机思想编程。
回复

使用道具 举报

10#
ID:1040470 发表于 2022-7-25 14:40 | 只看该作者
我只会按行按列扫描写的这种,新手勿嘲请教一下大神们上述矩阵按键代码是提高稳定性而加的判断嘛?#include <REGX52.H>
#include "Delay.h"
unsigned char MatrixKey()
{
        unsigned char KeyNumber=0;
        P1=0xFF;
        P1_3=0;
        if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=1;}
        if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=5;}
        if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=9;}
        if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=13;}
        P1_2=0;
        if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=2;}
        if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=6;}
        if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=10;}
        if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=14;}
        P1_1=0;
        if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=3;}
        if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=7;}
        if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=11;}
        if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=15;}
        P1_0=0;
        if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=4;}
        if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=8;}
        if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=12;}
        if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=16;}
        return KeyNumber;
}
       
回复

使用道具 举报

11#
ID:100982 发表于 2022-7-25 19:22 | 只看该作者
wuwuwuwuwukk 发表于 2022-7-25 14:40
我只会按行按列扫描写的这种,新手勿嘲请教一下大神们上述矩阵按键代码是提高稳定性而加的判断嘛?#i ...

你这个写法有点繁琐啊
回复

使用道具 举报

12#
ID:213173 发表于 2022-7-25 21:07 | 只看该作者
wifen 发表于 2022-7-25 19:22
你这个写法有点繁琐啊

给你一个简单、实用、可靠、易懂的4*4矩阵按键程序参考。
  1. void key_scan()                                        //4*4矩阵按键扫描程序
  2. {
  3.         static bit sign=0;                        //按键状态标志位变量
  4.         static unsigned int count=0;//计数变量
  5.         P3=0xf0;                                        //赋值P3 1111 0000
  6.         if(P3!=0xf0)                                //检测有按键按下
  7.         {
  8.                 if(++count>=10 && sign==0)//消抖(根据实际应用场景调整计数值,控制在10~20ms)
  9.                 {                       
  10.                         sign=1;                        //按键状态标志置1
  11.                         switch(P3)
  12.                         {
  13.                                 case(0Xe0):KeyValue = 1;break;
  14.                                 case(0Xd0):KeyValue = 2;break;
  15.                                 case(0Xb0):KeyValue = 3;break;
  16.                                 case(0X70):KeyValue = 4;break;
  17.                         }
  18.                         P3=0x0f;                        //赋值P3 0000 1111
  19.                         switch(P3)
  20.                         {
  21.                                 case(0X0e):KeyValue+= 0;break;
  22.                                 case(0X0d):KeyValue+= 4;break;
  23.                                 case(0X0b):KeyValue+= 8;break;
  24.                                 case(0X07):KeyValue+=12;break;
  25.                         }
  26.                 }
  27.         }
  28.         else                                                //键抬起
  29.         {
  30.                 sign=0;                                //按键状态标志清0
  31.                 count=0;                                //消抖计数清0
  32.         }
  33. }
复制代码
回复

使用道具 举报

13#
ID:190577 发表于 2022-7-25 21:45 | 只看该作者
wuwuwuwuwukk 发表于 2022-7-25 14:40
我只会按行按列扫描写的这种,新手勿嘲请教一下大神们上述矩阵按键代码是提高稳定性而加的判断嘛?#i ...

这种写法,容易理解
回复

使用道具 举报

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

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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