打印

按键检测的疑问

[复制链接]
5902|26
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
ycz9999|  楼主 | 2011-9-26 20:30 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
请教,如何检测一个按键在30s内一直都是按下状态呢?CPU是ARM7的LPC2106(ZLG的),纠结的是这个CPU没有边沿触发,只有低电平触发,且触发方式不可选。所以不可用中断检测按键,我想检测这个按键在30s内一直都是按下的状态,该如何规划下呢?

相关帖子

沙发
老鱼探戈| | 2011-9-26 20:55 | 只看该作者
检测为按下-----计时30s------松手清计数

使用特权

评论回复
板凳
流行音乐| | 2011-9-26 21:13 | 只看该作者
这要看你的要求具体有多严格,如果只是普通的按键功能,每 10ms 查询一次按键即可。

使用特权

评论回复
地板
ycz9999|  楼主 | 2011-9-26 21:20 | 只看该作者
恩  我原本是打算1s检测一次  但是有个疑问:  用什么去衡量30s内一直按下了呢?

使用特权

评论回复
5
ycz9999|  楼主 | 2011-9-26 21:21 | 只看该作者
2# 老鱼探戈 鱼哥的意思是开始检测到了的话  就计时30s  计时结束后再次检测吗?

使用特权

评论回复
6
lyjian| | 2011-9-26 22:17 | 只看该作者
定时扫描,如3楼说的10ms一次(10ms~100ms一次应该都没什么问题,看你的要求),定义一个hold计数器,每次扫描按键如果是按下的话,hold计数器加一,如果按键不是按下的话,hold计数器清零。当hold计数器>=3000d的话,就表示30s内一直都是按下状态。

使用特权

评论回复
评分
参与人数 1威望 +1 收起 理由
ycz9999 + 1
7
ycz9999|  楼主 | 2011-9-26 22:30 | 只看该作者
6# lyjian 恩  谢谢指点了 我写代码时考虑下这个方法

使用特权

评论回复
8
lixiaoxu2meng| | 2011-9-27 08:09 | 只看该作者
六楼的方法 和我想说的一样

使用特权

评论回复
9
ayb_ice| | 2011-9-27 08:17 | 只看该作者
都用上ARM了,还在问这样的问题

使用特权

评论回复
10
chenczy| | 2011-9-27 10:01 | 只看该作者
现在很多就算是用ARM,也不一定就代表做过很多项目,所以问这个问题也不奇怪

使用特权

评论回复
11
ayb_ice| | 2011-9-27 10:34 | 只看该作者
现在很多就算是用ARM,也不一定就代表做过很多项目,所以问这个问题也不奇怪
chenczy 发表于 2011-9-27 10:01

看来搞MCU的工资普遍不高,是有道理的

使用特权

评论回复
12
linbei1988| | 2011-9-27 10:48 | 只看该作者
看来搞MCU的工资普遍不高,是有道理的
ayb_ice 发表于 2011-9-27 10:34

有道理。。

使用特权

评论回复
13
ycz9999|  楼主 | 2011-9-27 12:13 | 只看该作者
9# ayb_ice 额  我是刚接手这个  而且要用一款我以前不熟悉的ARM  所以 我还要熟悉CPU的各个功能模块呀  。。  另外  我没工资  还在求学

使用特权

评论回复
14
yewuyi| | 2011-9-27 12:15 | 只看该作者
有定时中断即可,ms级别的查询即可按键状态即可。

使用特权

评论回复
15
ycz9999|  楼主 | 2011-9-27 12:17 | 只看该作者
14# yewuyi 恩 谢谢大侠指点  我也刚玩这个CPU2天  今天在熟悉定时器  虽然以前熟悉ARM9  但是与ARM7的寄存器还是有点区别   所以  我得先熟悉硬件 才敢写代码

使用特权

评论回复
16
sysdriver| | 2011-9-27 12:29 | 只看该作者
谁都有提高的一个过程,不管是单片机还是ARM

如果从RAM起跑,估计会有点困难。

使用特权

评论回复
17
lixiaoxu2meng| | 2011-9-27 12:56 | 只看该作者
我这有个按键的历程 C文件

/****************************************************************************
* Copyright (C), 2009-2010, www.armfly.com
*
* 文件名: sysytick.c
* 内容简述: 本模块实现7个按键的检测,具有滤波机制,支持按下,弹起和长按动作。
*                        通过GetKey()函数可以读取键值
* 文件历史:
* 版本号  日期       作者    说明
* v0.1    2009-12-27 armfly  创建该文件
*
*/
/* Includes ------------------------------------------------------------------*/
#include "includes.h"
#include <stdio.h>

static BUTTON_T s_BtnUser;                /* USER 键 */
static BUTTON_T s_BtnTamper;                /* TAMPER 键 */
static BUTTON_T s_BtnWakeUp;                /* WAKEUP 键 */
static BUTTON_T s_BtnUp;                /* 摇杆UP键 */
static BUTTON_T s_BtnDown;                /* 摇杆DOWN键 */
static BUTTON_T s_BtnLeft;                /* 摇杆LEFT键 */
static BUTTON_T s_BtnRight;                /* 摇杆RIGHT键 */
static BUTTON_T s_BtnOk;                /* 摇杆OK键 */

static KEY_FIFO_T s_Key;                /* 按键FIFO变量,结构体 */

/*
        安富莱STM32F103ZE-EK 按键口线分配:
        USER键     : PG8  (低电平表示按下)
        TAMPEER键  : PC13 (低电平表示按下)
        WKUP键     : PA0  (!!!高电平表示按下)
        摇杆UP键   : PG15 (低电平表示按下)
        摇杆DOWN键 : PD3  (低电平表示按下)
        摇杆LEFT键 : PG14 (低电平表示按下)
        摇杆RIGHT键: PG13 (低电平表示按下)
        摇杆OK键   : PG7 (低电平表示按下)

        定义7个函数,判断按键是否按下,返回值1 表示按下,0表示未按下
*/
static u8 IsKeyDownUser(void)                 {if (GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_8) == Bit_SET) return 0; return 1;}
static u8 IsKeyDownTamper(void)         {if (GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_13) == Bit_SET) return 0; return 1;}
static u8 IsKeyDownWakeUp(void)         {if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == Bit_SET) return 1; return 0;}
static u8 IsKeyDownUp(void)                 {if (GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_15) == Bit_SET) return 0; return 1;}
static u8 IsKeyDownDown(void)                 {if (GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_3) == Bit_SET) return 0; return 1;}
static u8 IsKeyDownLeft(void)                 {if (GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_14) == Bit_SET) return 0; return 1;}
static u8 IsKeyDownRight(void)           {if (GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_13) == Bit_SET) return 0; return 1;}
static u8 IsKeyDownOk(void)                 {if (GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_7) == Bit_SET) return 0; return 1;}
                                                                                                                                                                                  
/*******************************************************************************
        函数名: InitButtonVar
        输  入:
        输  出:
        功能说明:初始化所有的按键变量,这个函数需要在systic中断启动前调用1次
*******************************************************************************/
void InitButtonVar(void)
{
        /* 对按键FIFO读写指针清零 */
        s_Key.Read = 0;
        s_Key.Write = 0;

        /* 初始化USER按键变量 */
        s_BtnUser.IsKeyDownFunc = IsKeyDownUser;        /* 判断按键按下的函数 */
        s_BtnUser.FilterTime = BUTTON_FILTER_TIME;        /* 按键滤波时间 */
        s_BtnUser.LongTime = BUTTON_LONG_TIME;                /* 长按时间 */
        s_BtnUser.LongCount = 0;
        s_BtnUser.Count = s_BtnUser.FilterTime / 2;        /* 计数器设置为滤波时间的一半 */
        s_BtnUser.State = 0;                                /* 按键缺省状态,0为未按下 */
        s_BtnUser.KeyCodeDown = KEY_DOWN_USER;                /* 按键按下的键值代码 */
        s_BtnUser.KeyCodeUp = KEY_UP_USER;                        /* 按键弹起的键值代码 */
        s_BtnUser.KeyCodeLong = KEY_HOLD_USER;                /* 按键被持续按下的键值代码 */

        /* 初始化TAMPER按键变量 */
        s_BtnTamper.IsKeyDownFunc = IsKeyDownTamper;        /* 判断按键按下的函数 */
        s_BtnTamper.FilterTime = BUTTON_FILTER_TIME;        /* 按键滤波时间 */
        s_BtnTamper.LongTime = 0;                                                /* 长按时间, 0表示不检测 */
        s_BtnTamper.Count = s_BtnTamper.FilterTime / 2;        /* 计数器设置为滤波时间的一半 */
        s_BtnTamper.State = 0;                                                        /* 按键缺省状态,0为未按下 */
        s_BtnTamper.KeyCodeDown = KEY_DOWN_TAMPER;                /* 按键按下的键值代码 */
        s_BtnTamper.KeyCodeUp = 0;                                                /* 按键弹起的键值代码 */
        s_BtnTamper.KeyCodeLong = 0;                                        /* 按键被持续按下的键值代码 */

        /* 初始化WAKEUP按键变量 */
        s_BtnWakeUp.IsKeyDownFunc = IsKeyDownWakeUp;        /* 判断按键按下的函数 */
        s_BtnWakeUp.FilterTime = BUTTON_FILTER_TIME;        /* 按键滤波时间 */
        s_BtnWakeUp.LongTime = 0;                                                /* 长按时间 */
        s_BtnWakeUp.Count = s_BtnWakeUp.FilterTime / 2;        /* 计数器设置为滤波时间的一半 */
        s_BtnWakeUp.State = 0;                                                        /* 按键缺省状态,0为未按下 */
        s_BtnWakeUp.KeyCodeUp = 0;                                                /* 按键弹起的键值代码,0表示不检测 */
        s_BtnWakeUp.KeyCodeDown = KEY_DOWN_WAKEUP;                /* 按键按下的键值代码 */
        s_BtnWakeUp.KeyCodeLong = 0;                                        /* 按键被持续按下的键值代码,0表示不检测 */

        /* 初始化UP按键变量 */
        s_BtnUp.IsKeyDownFunc = IsKeyDownUp;                /* 判断按键按下的函数 */
        s_BtnUp.FilterTime = BUTTON_FILTER_TIME;        /* 按键滤波时间 */
        s_BtnUp.LongTime = 0;                                                /* 长按时间 */
        s_BtnUp.Count = s_BtnUp.FilterTime / 2;                /* 计数器设置为滤波时间的一半 */
        s_BtnUp.State = 0;                                                        /* 按键缺省状态,0为未按下 */
        s_BtnUp.KeyCodeDown = KEY_DOWN_JOY_UP;                /* 按键按下的键值代码 */
        s_BtnUp.KeyCodeUp = 0;                                                /* 按键弹起的键值代码,0表示不检测 */
        s_BtnUp.KeyCodeLong = 0;                                        /* 按键被持续按下的键值代码,0表示不检测 */

        /* 初始化DOWN按键变量 */
        s_BtnDown.IsKeyDownFunc = IsKeyDownDown;        /* 判断按键按下的函数 */
        s_BtnDown.FilterTime = BUTTON_FILTER_TIME;        /* 按键滤波时间 */
        s_BtnDown.LongTime = 0;                                                /* 长按时间 */
        s_BtnDown.Count = s_BtnDown.FilterTime / 2;        /* 计数器设置为滤波时间的一半 */
        s_BtnDown.State = 0;                                                /* 按键缺省状态,0为未按下 */
        s_BtnDown.KeyCodeDown = KEY_DOWN_JOY_DOWN;        /* 按键按下的键值代码 */
        s_BtnDown.KeyCodeUp = 0;                                        /* 按键弹起的键值代码,0表示不检测 */
        s_BtnDown.KeyCodeLong = 0;                                        /* 按键被持续按下的键值代码,0表示不检测 */

        /* 初始化LEFT按键变量 */
        s_BtnLeft.IsKeyDownFunc = IsKeyDownLeft;        /* 判断按键按下的函数 */
        s_BtnLeft.FilterTime = BUTTON_FILTER_TIME;        /* 按键滤波时间 */
        s_BtnLeft.LongTime = 0;                                                /* 长按时间 */
        s_BtnLeft.Count = s_BtnLeft.FilterTime / 2;        /* 计数器设置为滤波时间的一半 */
        s_BtnLeft.State = 0;                                                /* 按键缺省状态,0为未按下 */
        s_BtnLeft.KeyCodeDown = KEY_DOWN_JOY_LEFT;        /* 按键按下的键值代码 */
        s_BtnLeft.KeyCodeUp = 0;                                        /* 按键弹起的键值代码,0表示不检测 */
        s_BtnLeft.KeyCodeLong = 0;                                        /* 按键被持续按下的键值代码,0表示不检测 */

        /* 初始化RIGHT按键变量 */
        s_BtnRight.IsKeyDownFunc = IsKeyDownRight;        /* 判断按键按下的函数 */
        s_BtnRight.FilterTime = BUTTON_FILTER_TIME;        /* 按键滤波时间 */
        s_BtnRight.LongTime = 0;                                        /* 长按时间 */
        s_BtnRight.Count = s_BtnRight.FilterTime / 2;/* 计数器设置为滤波时间的一半 */
        s_BtnRight.State = 0;                                                /* 按键缺省状态,0为未按下 */
        s_BtnRight.KeyCodeDown = KEY_DOWN_JOY_RIGHT;/* 按键按下的键值代码 */
        s_BtnRight.KeyCodeUp = 0;                                        /* 按键弹起的键值代码,0表示不检测 */
        s_BtnRight.KeyCodeLong = 0;                                        /* 按键被持续按下的键值代码,0表示不检测 */

        /* 初始化OK按键变量 */
        s_BtnOk.IsKeyDownFunc = IsKeyDownOk;                /* 判断按键按下的函数 */
        s_BtnOk.FilterTime = BUTTON_FILTER_TIME;        /* 按键滤波时间 */
        s_BtnOk.LongTime = 0;                                                /* 长按时间 */
        s_BtnOk.Count = s_BtnOk.FilterTime / 2;                /* 计数器设置为滤波时间的一半 */
        s_BtnOk.State = 0;                                                        /* 按键缺省状态,0为未按下 */
        s_BtnOk.KeyCodeDown = KEY_DOWN_JOY_OK;                /* 按键按下的键值代码 */
        s_BtnOk.KeyCodeUp = 0;                                                /* 按键弹起的键值代码,0表示不检测 */
        s_BtnOk.KeyCodeLong = 0;                                        /* 按键被持续按下的键值代码,0表示不检测 */
}

/*******************************************************************************
        函数名: PutKey
        输  入: 键值
        输  出:
        功能说明:将1个键值压入按键FIFO缓冲区
*******************************************************************************/
void PutKey(u8 _KeyCode)
{
        s_Key.Buf[s_Key.Write] = _KeyCode;

        if (++s_Key.Write  >= KEY_FIFO_SIZE)
        {
                s_Key.Write = 0;
        }
}

/*******************************************************************************
        函数名: GetKey
        输  入:
        输  出: 返回键值, KEY_NONE ( = 0) 表示无键按下
        功能说明:从按键FIFO取1个键值
*******************************************************************************/
u8 GetKey(void)
{
        u8 ret;

        if (s_Key.Read == s_Key.Write)
        {
                return KEY_NONE;
        }
        else
        {
                ret = s_Key.Buf[s_Key.Read];

                if (++s_Key.Read >= KEY_FIFO_SIZE)
                {
                        s_Key.Read = 0;
                }
                return ret;
        }
}

/*******************************************************************************
        函数名:DetectButton
        输  入: 按键结构变量指针
        输  出:
        功能说明:检测指定的按键
*******************************************************************************/
static void DetectButton(BUTTON_T *_pBtn)
{
        /* 如果没有初始化按键函数,则报错
        if (_pBtn->IsKeyDownFunc == 0)
        {
                printf("Fault : DetectButton(), _pBtn->IsKeyDownFunc undefine");
        }
        */

        if (_pBtn->IsKeyDownFunc())
        {
                if (_pBtn->Count < _pBtn->FilterTime)
                {
                        _pBtn->Count = _pBtn->FilterTime;
                }
                else if(_pBtn->Count < 2 * _pBtn->FilterTime)
                {
                        _pBtn->Count++;
                }
                else
                {
                        if (_pBtn->State == 0)
                        {
                                _pBtn->State = 1;

                                /* 发送按钮按下的消息 */
                                if (_pBtn->KeyCodeDown > 0)
                                {
                                        /* 键值放入按键FIFO */
                                        PutKey(_pBtn->KeyCodeDown);
                                }
                        }

                        if (_pBtn->LongTime > 0)
                        {
                                if (_pBtn->LongCount < _pBtn->LongTime)
                                {
                                        /* 发送按钮持续按下的消息 */
                                        if (++_pBtn->LongCount == _pBtn->LongTime)
                                        {
                                                /* 键值放入按键FIFO */
                                                PutKey(_pBtn->KeyCodeLong);
                                        }
                                }
                        }
                }
        }
        else
        {
                if(_pBtn->Count > _pBtn->FilterTime)
                {
                        _pBtn->Count = _pBtn->FilterTime;
                }
                else if(_pBtn->Count != 0)
                {
                        _pBtn->Count--;
                }
                else
                {
                        if (_pBtn->State == 1)
                        {
                                _pBtn->State = 0;

                                /* 发送按钮弹起的消息 */
                                if (_pBtn->KeyCodeUp > 0)
                                {
                                        /* 键值放入按键FIFO */
                                        PutKey(_pBtn->KeyCodeUp);
                                }
                        }
                }

                _pBtn->LongCount = 0;
        }
}

  


/*******************************************************************************
        函数名:KeyPro
        输  入:
        输  出:
        功能说明:检测所有的按键,这个函数要被systic的中断服务程序调用
*******************************************************************************/
void KeyPro(void)
{
        DetectButton(&s_BtnUser);        /* USER 键 */
        DetectButton(&s_BtnTamper);        /* TAMPER 键 */
        DetectButton(&s_BtnWakeUp);        /* WAKEUP 键 */
        DetectButton(&s_BtnUp);                /* 摇杆UP键 */
        DetectButton(&s_BtnDown);        /* 摇杆DOWN键 */
        DetectButton(&s_BtnLeft);        /* 摇杆LEFT键 */
        DetectButton(&s_BtnRight);        /* 摇杆RIGHT键 */
        DetectButton(&s_BtnOk);                /* 摇杆OK键 */
}


头文件

/****************************************************************************
* Copyright (C), 2009-2010, www.armfly.com
*
* 文件名: button.h
* 内容简述: 头文件
*
* 文件历史:
* 版本号  日期       作者    说明
* v0.1    2009-12-28 armfly  创建该文件
*
*/

/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __BUTTON_H
#define __BUTTON_H

/* 按键滤波时间50ms, 单位10ms
只有连续检测到50ms状态不变才认为有效,包括弹起和按下两种事件
*/
#define BUTTON_FILTER_TIME         5
#define BUTTON_LONG_TIME         100                /* 持续1秒,认为长按事件 */

/*
        每个按键对应1个全局的结构体变量。
        其成员变量是实现滤波和多种按键状态所必须的
*/
typedef struct
{
        /* 下面是一个函数指针,指向判断按键手否按下的函数 */
        u8 (*IsKeyDownFunc)(void); /* 按键按下的判断函数,1表示按下 */
        u8 Count;                        /* 滤波器计数器 */
        u8 FilterTime;                /* 滤波时间(最大255,表示2550ms) */
        u16 LongCount;                /* 长按计数器 */
        u16 LongTime;                /* 按键按下持续时间, 0表示不检测长按 */
        u8  State;                        /* 按键当前状态(按下还是弹起) */
        u8 KeyCodeUp;                /* 按键弹起的键值代码, 0表示不检测按键弹起 */
        u8 KeyCodeDown;        /* 按键按下的键值代码, 0表示不检测按键按下 */
        u8 KeyCodeLong;        /* 按键长按的键值代码, 0表示不检测长按 */
}BUTTON_T;

/* 定义键值代码
        推荐使用enum, 不用#define,原因:
        (1) 便于新增键值,方便调整顺序,使代码看起来舒服点
        (2)        编译器可帮我们避免键值重复。
*/
typedef enum
{
        KEY_NONE = 0,                        /* 0 表示按键事件 */

        /* 为了演示,需要检测USER键弹起事件和长按事件 */
        KEY_DOWN_USER,                        /* User键按下 */
        KEY_UP_USER,                        /* User键弹起 */
        KEY_HOLD_USER,                        /* User键长按 */

        KEY_DOWN_WAKEUP,                /* WakeUp键按下 */
        KEY_DOWN_TAMPER,                /* Tamper键按下 */

        KEY_DOWN_JOY_UP,                /* 摇杆UP键按下 */
        KEY_DOWN_JOY_DOWN,                /* 摇杆DOWN键按下 */
        KEY_DOWN_JOY_LEFT,                /* 摇杆LEFT键按下 */
        KEY_DOWN_JOY_RIGHT,                /* 摇杆RIGHT键按下 */
        KEY_DOWN_JOY_OK                        /* 摇杆OK键按下 */
}KEY_ENUM;

/*
        按键FIFO用到变量
*/
#define KEY_FIFO_SIZE        20
typedef struct
{
        u8 Buf[KEY_FIFO_SIZE];                /* 键值缓冲区 */
        u8 Read;        /* 缓冲区读指针 */
        u8 Write;        /* 缓冲区写指针 */
}KEY_FIFO_T;

void InitButtonVar(void);
void PutKey(u8 _KeyCode);
u8  GetKey(void);
void KeyPro(void);
#endif

楼主只需更改C文件的按键端口就行了
然后在用定时器产生一个10ms左右的时基 在这个时基里调用按键扫描函数即可
然后你想检测30s 只需更改 长按键时间即可

楼主可以参考下

使用特权

评论回复
18
魑魅-魍魉| | 2011-9-27 13:07 | 只看该作者
按下按键,打开定时器,检测按键松开的时候,关闭定时器,

使用特权

评论回复
19
ayb_ice| | 2011-9-27 13:13 | 只看该作者
9# ayb_ice 额  我是刚接手这个  而且要用一款我以前不熟悉的ARM  所以 我还要熟悉CPU的各个功能模块呀  。。  另外  我没工资  还在求学
ycz9999 发表于 2011-9-27 12:13

这种东西本身应该个和硬件无关的问题,简单算法而已
如果这种东西都还要占用一个定时器的话,那做个很简单的项目,估计模块资源都要用完了

使用特权

评论回复
20
lyjian| | 2011-9-27 16:41 | 只看该作者
楼上,如果你不用定时器的话,那你怎么做?
软件死等?
牛!

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1

主题

857

帖子

1

粉丝