OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 3957|回复: 8

请教!这个矩阵键盘不用中断如何修改?

[复制链接]

32

主题

92

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4015
金钱
4015
注册时间
2015-12-21
在线时间
887 小时
发表于 2016-1-17 23:25:06 | 显示全部楼层 |阅读模式
1金钱
请教!这个矩阵键盘不用中断如何修改?
/*
程序功能:
K1单击时num+1;长击num+2;
K2单击时num-1;长击num-2;
K5连击按键 按着num+1;
K6连击按键 按着num-1;
无按键时间4s led亮;有按键,led灭。
*/
//支持单击(短击)、连击,长击,无击
//长击时间到后,立即执行;短击释放后执行
//按键方式(单击,长击)、(只支持单击)、(连击)
//连击实际上包含了单击
#include "reg51.h"
#include "intrins.h"

#define uchar unsigned char
#define uint unsigned int
#define NOP() _nop_()
#define KeyPIN P1
sbit led=P3^7;
uchar num;

uchar key_code[]= {0x7e,0x7d,0x7b,0x77,0xbe,0xbd,0xbb,0xb7,0xde,0xdd,0xdb,0xd7,0xee,0xed,0xeb,0xe7};

struct
{
    uchar state;//按键状态 0-等待阶段;1-闭合抖动阶段;2-有效闭合阶段;3-释放阶段
    uchar type;//0-无按键或者按键已经响应 ;1-单击 ;2-连击 ;3-长击;4-无击
    uchar detect;//按键检测标志 1为检测到按键
    uchar value;//当前键值
    uchar backvalue;//备份键值
    uchar disable;//按键禁止响应标志:按键执行过,则标志为1.主要用于长击。
    uchar scan_en;//按键扫描标志 1为允许扫描
    uchar tmr_no;//无键计数器,用于无击。
    uchar cnt_press;//按键闭合计数器,用于长击。
    uchar delay_con;//连击响应延时时间,用于连击。
#define AN_XD_DL 2//AN_XD_DL*定时器中断20ms
#define AN_LA_DL 10//AN_LA_DL*20ms
#define AN_CJ_DL 5//长击所需时间:AN_CJ_DL*AN_LA_DL*20ms
#define KEY_IDLE 0//按键等待阶段
#define KEY_IS_DOWN 1//闭合抖动阶段
#define KEY_DOWN 2//有效闭合阶段   
#define KEY_IS_UP 3//释放阶段
#define NoKey 0//无键
#define NoKeyTMR 200//无键所需时间:NoKeyTMR*20ms
} key;
unsigned char KeyScan(void);
void KeyInit(void);
void KeyProcess(void);
void KeyShortPress(void);//短击 单击
void KeyLongPress(void);//长击
void KeyContinuePress(void);//连击
void KeyNoPress(void);//无击
void KeyAction(void);//根据按键类型动作 散转程序
void main()
{
    TCON=0x00;
    IE=0x84;
    TMOD=0x01;
    TH0=0xB1;
    TL0=0xE0;
    ET0=1;
    TR0=1;
    EA = 1;
    while(1)
    {
        KeyPIN=0x0f;
        KeyProcess();
        KeyAction();
        P0=num/10;
        P2=num%10;
    }
}
//键盘扫描方法,反转法
uchar KeyScan(void)
{
    uchar temp,keyval=0;
    KeyPIN = 0x0f;
    if (KeyPIN != 0x0f)
    {
        temp=KeyPIN;
        KeyPIN = 0xf0;
        temp|=KeyPIN;
        keyval=1;
        while (key_code[keyval-1] != temp)  //把特征码转换为键号
        {
            keyval++;
            if(keyval>0x0f)
            {
                break;
            }
        }
    }
    return keyval;
}
void KeyProcess()
{
    switch(key.state)
    {
    case KEY_IDLE://等待阶段
    {
        key.disable=0;
        key.delay_con=AN_XD_DL;
        key.cnt_press=0;
        if(key.detect)//有按键才允许扫描
        {
            key.tmr_no=0;//有键按下,无键计数器清零
            key.type=0;
            key.detect=0;
            if(key.scan_en)
            {
                key.scan_en=0;
                key.state=KEY_IS_DOWN;
            }
        }
        else
        {
            if(key.tmr_no==NoKeyTMR)
            {
                key.type=4;
            }
        }
    }
    break;
    case KEY_IS_DOWN:
    {
        key.tmr_no=0;
        if(key.scan_en)
        {
            key.scan_en=0;
            key.value=KeyScan();
            if(key.value==key.backvalue)
            {
                key.state=KEY_DOWN;
            }
            else
            {
                key.backvalue=key.value;
            }
        }
    }
    break;
    case KEY_DOWN:
    {
        key.tmr_no=0;
        if(key.scan_en)
        {
            key.scan_en=0;
            key.backvalue=key.value;//备份当前键值供释放后 单击 使用
            key.value=KeyScan();
            key.delay_con--;
            if(key.delay_con==0)
            {
                key.delay_con=AN_LA_DL;
                key.cnt_press++;
                if(key.cnt_press>AN_CJ_DL)
                {
                    if(!key.disable)//长击执行过一次后,如不释放按键,不执行。
                    {
                        key.type=3;
                    }
                    else
                    {
                        key.type=0;
                    }
                }
                else
                {
                    key.type=2;
                }
            }
            if(key.value==NoKey)
            {
                key.state=KEY_IS_UP;
            }
        }
    }
    break;
    case KEY_IS_UP:
    {
        key.tmr_no=0;
        if(!key.disable)//避免长击释放后 继续执行单击
        {
            key.type=1;
        }
        key.state=KEY_IDLE;
    }
    break;
    }
}
void KeyAction(void)
{
    switch(key.type)
    {
    case 1:
    {
        KeyShortPress();
    }
    break;
    case 2:
    {
        KeyContinuePress();
        key.type=0;
    }
    break;
    case 3:
    {
        KeyLongPress();
    }
    break;
    case 4:
    {
        KeyNoPress();
    }
    break;
    }
}
void KeyNoPress(void)
{
    led=0;
}
void KeyShortPress(void)
{
    led=1;
    switch(key.backvalue)
    {
    case 1:
        num++;
        break;
    case 2:
        num--;
        break;
    }
}
void KeyContinuePress(void)
{
    led=1;
    switch(key.backvalue)
    {
    case 5:
        num++;
        break;
    case 6:
        num--;
        break;
    }
}
void KeyLongPress(void)
{
    led=1;
    switch(key.backvalue)
    {
    case 1:
        num+=2;
        key.disable=1;
        key.type=0;
        break;//此处key.disable和key.type必须这样处理
    case 2:
        num-=2;
        key.disable=1;
        key.type=0;
        break;
    default:
        key.type=2;//因为长击是在按下后时间足够后就触发的,所以为避免连击和长击冲突,必须加此句
    }
}
void timer0() interrupt 1 using 1       //12M晶振 20ms中断
{
    TH0=0xB1;
    TL0=0xE0;
    key.tmr_no++;
    if(key.detect)
    {
        key.scan_en=1;    //有键按下才允许扫描
    }
}
void EXT_INT() interrupt 2 using 1
{
    key.detect=1;
}

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

10

主题

560

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1739
金钱
1739
注册时间
2014-6-27
在线时间
943 小时
发表于 2016-1-18 14:59:04 | 显示全部楼层
你可以放在主函数里面周期性扫描就行了。按键扫描程序应该可以写得更简单些吧
回复

使用道具 举报

32

主题

92

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4015
金钱
4015
注册时间
2015-12-21
在线时间
887 小时
 楼主| 发表于 2016-2-2 15:52:22 | 显示全部楼层
这个程序不用中断如何修改?多谢指点!
回复

使用道具 举报

10

主题

560

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1739
金钱
1739
注册时间
2014-6-27
在线时间
943 小时
发表于 2016-2-2 17:38:14 | 显示全部楼层
zlkj 发表于 2016-2-2 15:52
这个程序不用中断如何修改?多谢指点!

弄个定时器中断,比如5MS一次中断,做个标志,在定时器里面,中断来了就置1,主函数里面,判断这个标志位为1了,调用一次按键扫描程序,同时清标志。
回复

使用道具 举报

32

主题

92

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4015
金钱
4015
注册时间
2015-12-21
在线时间
887 小时
 楼主| 发表于 2016-2-2 22:13:24 | 显示全部楼层
TinyBoy 发表于 2016-2-2 17:38
弄个定时器中断,比如5MS一次中断,做个标志,在定时器里面,中断来了就置1,主函数里面,判断这个标志位 ...

麻烦你改改这个程序,谢谢!
回复

使用道具 举报

10

主题

560

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1739
金钱
1739
注册时间
2014-6-27
在线时间
943 小时
发表于 2016-2-3 09:13:28 | 显示全部楼层
zlkj 发表于 2016-2-2 22:13
麻烦你改改这个程序,谢谢!

我有发到论坛的,你找一下,自己修改下吧,很简单的。
回复

使用道具 举报

32

主题

92

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4015
金钱
4015
注册时间
2015-12-21
在线时间
887 小时
 楼主| 发表于 2016-2-3 19:17:28 | 显示全部楼层
本帖最后由 zlkj 于 2016-2-3 19:21 编辑
TinyBoy 发表于 2016-2-3 09:13
我有发到论坛的,你找一下,自己修改下吧,很简单的。

感谢你的支持。可是你的程序修改C51不成功?如何实现长按、连击请指教!
回复

使用道具 举报

10

主题

560

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1739
金钱
1739
注册时间
2014-6-27
在线时间
943 小时
发表于 2016-2-3 20:11:53 | 显示全部楼层
zlkj 发表于 2016-2-3 19:17
感谢你的支持。可是你的程序修改C51不成功?如何实现长按、连击请指教!

我的例程就有。这个按键扫描没用过在51上,但是51是最简单的。
回复

使用道具 举报

32

主题

92

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4015
金钱
4015
注册时间
2015-12-21
在线时间
887 小时
 楼主| 发表于 2016-2-3 21:07:02 | 显示全部楼层
本帖最后由 zlkj 于 2016-2-3 22:35 编辑

!!!!!!!!!!!
回复

使用道具 举报

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

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-23 13:08

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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