搜索
bottom↓
回复: 39

写了一个独立按键 支持组合键、单键长按,连发功能的例子

  [复制链接]

出0入76汤圆

发表于 2012-7-5 21:47:20 | 显示全部楼层 |阅读模式
本帖最后由 foxpro2005 于 2012-7-5 21:53 编辑

学习了马老师的《AVR单片机嵌入式系统原理与应用实践书》 第2版,现也写了一个按键扫描的例子(用WINAVR写的)。
独立按键,支持组合键,单键长按,连发功能等应用,已通过实践测试。

KeyScan.h 部分
/********************************************************************************************************
* FileName....:        KeyScan.h
* MCU.........:        ATmega8 at 8MHz
* Compiler....:        WinAVR-20100110
* Author......:        foxpro2005
* Ver.........:        V1.0
* Time........:        2012.07.04
* Description.:        Key scan.
* History.....:        2012.07.04 V1.0
*
******************************************************************************************************/
#ifndef _KeyScan_H_
#define _KeyScan_H_

//------------------------------------------------------------------------------------------------------
#include <avr/io.h>                               

//-------------------------------------------------------------------------------------------------------
/*****************************硬件I/O引脚定义,根据实际应用修改******************************/
#define KEY_PORT        PIND                                                                        // 独立按键所占用端口.

#define K_STOP                (1<<PD3)                                                                // "停止"键
#define K_START        (1<<PD4)                                                                // "启动"键
#define K_SEL                (1<<PD5)                                                                // "选择"键
#define K_ADD                (1<<PD6)                                                                // "+ "键
#define K_DEC                (1<<PD7)                                                                // "- "键

#define OneKeyTime        300                                                                                // 单键长按时长 = OneKeyTime * 10ms
#define MuxKeyTime        500                                                                                // 组合键长按时长 = MuxKeyTime * 10ms
#define RepeatTime        5                                                                                // 单键连发功能重复间隔时间 = RepeatTime * 10ms

#define Key_Mask        (K_STOP|K_START|K_SEL|K_ADD|K_DEC)                        // 按键掩码值

//-------------------------------------------------------------------------------------------------------
#define GetKey()        (KEY_PORT & Key_Mask)                                                // 读取按键端口值

#define key_state_0        0                                                                                // 初始态.
#define key_state_1        1                                                                                // 确认态.
#define key_state_2        2                                                                                // 组合键,长按键确认态.
#define key_state_3        3                                                                                // 长按连发功能确认态.
#define key_state_4        4                                                                                // 等待释放态.

//-------------------------------------------------------------------------------------------------------
/****************************************数据类型定义**************************************/
typedef enum {NO_KEY,STOP,START,SEL,ADD,DEC,SETUP} eKEY;        // 按键返回值类型定义.

//-------------------------------------------------------------------------------------------------------
/*****************************************函数声明****************************************/
eKEY ReadKey(void);                                                                                        //读取按键.                                       

//-------------------------------------------------------------------------------------------------------
#endif


KeyScan.c 部分
/********************************************************************************************************
* FileName....:        KeyScan.c
* MCU.........:        ATmega8 at 8MHz
* Compiler....:        WinAVR-20100110
* Author......:        foxpro2005
* Ver.........:        V1.0
* Time........:        2012.07.04
* Description.:        Key scan.
* History.....:        2012.07.04 V1.0
*
******************************************************************************************************/
//------------------------------------------------------------------------------------------------------
#include "KeyScan.h"

//------------------------------------------------------------------------------------------------------
/***********************************全局变量定义区******************************************/


/********************************************************************************************
* eKEY ReadKey(void);
* 功能: 独立按键扫描,10ms扫描一次.
* 返回值:枚举类型,{NO_KEY,STOP,START,SEL,ADD,DEC,SETUP}.
* 参数:
********************************************************************************************/
eKEY ReadKey(void)
{
        static unsigned int key_time = 0;                                                        // 长按键计时
        static unsigned char key_state = 0;                                                // 记录按键扫当前描状态
        static unsigned char key_press_old = 0;                                        // 记录上一次按键状态
        static eKEY key_value_old = NO_KEY;                                                // 保存上一次按键返回值
        eKEY key_return = NO_KEY;                                                                // 按键功能返回值
        unsigned char key_press;
       
        key_press = GetKey() ^ Key_Mask;                                                // 读按键I/O电平,只保留被按下的键(被按下的键位为1)
        switch (key_state)
        {
                case key_state_0:                                                                // 1.按键初始态
                        if (key_press)
                        {
                                key_state = key_state_1;                                        // 键被按下,状态转换到按键确认态
                                key_press_old = key_press;                                // 保存当前按键状态
                        }
                        break;
                case key_state_1:                                                                // 2.按键确认态
                        if (key_press == key_press_old)                                        // 与初始态的按键状态相同?
                        {
                                key_time = 0;                                                        // 清另按键时间计数器
                                switch(key_press)
                                {
                                        case K_STOP:
                                                key_state  = key_state_4;                         // 转按键释放态
                                                key_return = STOP;                                // "停止"键
                                                break;
                                        case K_START:
                                                key_state  = key_state_4;                         // 转按键释放态
                                                key_return = START;                                // "起动"键                                               
                                                break;       
                                        case K_SEL:
                                                key_state  = key_state_2;                         // 转长按键态
                                                key_return = SEL;                                // "选择"键                                                               
                                                break;       
                                        case K_ADD:
                                                key_state  = key_state_2;                         // 转长按键态
                                                key_return = ADD;                                // "+"键
                                                break;       
                                        case K_DEC:
                                                key_state  = key_state_2;                         // 转长按键态
                                                key_return = DEC;                                // "-"键
                                                break;
                                        case K_STOP|K_SEL:                                        // "组合"键,长按键
                                                key_state  = key_state_2;                         // 组合键按键仍按下,状态转换到计时1
                                                break;       
                                        default:
                                                key_state  = key_state_4;                         // 转按键释放态
                                                break;
                                }
                        }
                        else if (!key_press)
                            key_state = key_state_0;                                        // 按键已抬起(是干扰),转换到按键初始态
                        else
                                key_state = key_state_4;                                        // 按键已发生变化,转到按键释放态
                               
                        key_value_old = key_return;                                        // 保存按键返回值
                        break;
                case key_state_2:                                                                // 3.长按键确认态
                        if (key_press == key_press_old)
                        {
                                ++key_time;                                                        // 按键计时
                                if (key_press == (K_STOP|K_SEL))                        // "配置"键?
                                {
                                        if(key_time >= MuxKeyTime)                        // 组合键长按计时
                                        {
                                                key_state = key_state_4;                        // 按下时间>=MuxKeyTime,转到按键释放状态
                                                key_return = SETUP;                                // 组合键功能,"配置"键
                                        }
                                }
                                else
                                {
                                        if(key_time >= OneKeyTime)                        // 单键长按计时
                                        {
                                                key_state = key_state_3;                        // 按下时间>=OneKeyTime,转到连发功能态,用于触发连发功能
                                                key_time = 0;                                        // 清按键计数器
                                                key_return = key_value_old;                // 返回上一次按键值
                                        }
                                }
                        }
                        else
                                key_state = key_state_4;                                        // 按键已发生变化,转到按键释放态
                        break;
                case key_state_3:                                                                // 4.按键连发功能
                        if (key_press == key_press_old)
                        {
                                if (++key_time >= RepeatTime)                                // 按键时间计数
                                {
                                        key_time = 0;                                                // 按下时间>=0.05s,清0按键计数器
                                        key_return = key_value_old;                        // 返回上一次按键值
                                }                               
                        }
                        else
                            key_state = key_state_4;                                         // 按键已发生变化,转到按键释放态
                        break;
                case key_state_4:                                                                // 5.等待所有按键释放开
                        //if (!key_press)                                                                // 等待所有按键释放,才进入一次新的按键确认过程
                        if (key_press != key_press_old)                                        // 按键发生变化,就进入一次新的确认过程
                            key_state = key_state_0;                                         // 按键已释放,转换到初始态.
                        break;                       
        }       
    return key_return;
}

阿莫论坛20周年了!感谢大家的支持与爱护!!

如果想吃一顿饺子,就得从冰箱里取出肉,剁馅儿,倒面粉、揉面、醒面,擀成皮儿,下锅……
一整个繁琐流程,就是为了出锅时那一嘴滚烫流油的热饺子。

如果这个过程,禁不住饿,零食下肚了,饺子出锅时也就不香了……《非诚勿扰3》

出0入0汤圆

发表于 2012-7-6 18:25:08 | 显示全部楼层
你好,我在调试你贴上的程序,发现单个按键都正常,为什么组合键就不正常呢?代码如下:

#include <iom16v.h>

#define K_STOP                (1<<PA0)                                                                // "停止"键
#define K_START               (1<<PA1)                                                                // "启动"键
#define K_SEL                 (1<<PA2)                                                                // "选择"键
#define K_ADD                 (1<<PA3)                                                                // "+ "键
#define K_DEC                 (1<<PA4)                                                                // "- "键

#define OneKeyTime        300                                                                         // 单键长按时长 = OneKeyTime * 10ms
#define MuxKeyTime        500                                                                         // 组合键长按时长 = MuxKeyTime * 10ms
#define RepeatTime        5                                                                           // 单键连发功能重复间隔时间 = RepeatTime * 10ms

#define Key_Mask        (K_STOP|K_START|K_SEL|K_ADD|K_DEC)                        // 按键掩码值


#define KEY_PORT              PORTA                                                                    // 独立按键所占用端口.
#define KEY_DDR                                  DDRA
#define KEY_PIN                                  PINA
//-------------------------------------------------------------------------------------------------------
#define GetKey()        (KEY_PIN & Key_Mask)                                                // 读取按键端口值

#define key_state_0        0                                                                                // 初始态.
#define key_state_1        1                                                                                // 确认态.
#define key_state_2        2                                                                                // 组合键,长按键确认态.
#define key_state_3        3                                                                                // 长按连发功能确认态.
#define key_state_4        4                                                                                // 等待释放态.

//-------------------------------------------------------------------------------------------------------
/****************************************数据类型定义**************************************/
typedef enum {NO_KEY,STOP,START,SEL,ADD,DEC,SETUP} eKEY;        // 按键返回值类型定义.

//-------------------------------------------------------------------------------------------------------
/*****************************************函数声明****************************************/
eKEY ReadKey(void);                                                                                        //读取按键.                                       

//-------------------------------------------------------------------------------------------------------
unsigned char time_counter,key_stime_counter;                // 时间计数单元
unsigned char point_on, time_1s_ok,key_stime_ok;



/********************************************************************************************
* eKEY ReadKey(void);
* 功能: 独立按键扫描,10ms扫描一次.
* 返回值:枚举类型,{NO_KEY,STOP,START,SEL,ADD,DEC,SETUP}.
* 参数:
********************************************************************************************/
eKEY ReadKey(void)
{

        static unsigned int key_time = 0;                                                        // 长按键计时
        static unsigned char key_state = 0;                                                // 记录按键扫当前描状态
        static unsigned char key_press_old = 0;                                        // 记录上一次按键状态
        static eKEY key_value_old = NO_KEY;                                                // 保存上一次按键返回值
        eKEY key_return = NO_KEY;                                                                // 按键功能返回值
        unsigned char key_press;

        key_press = GetKey() ^ Key_Mask;                                                // 读按键I/O电平,只保留被按下的键(被按下的键位为1)
        
               
                switch (key_state)
        {
                case key_state_0:                                                                // 1.按键初始态
                        if (key_press)
                        {
                                key_state = key_state_1;                                        // 键被按下,状态转换到按键确认态
                                key_press_old = key_press;                                      // 保存当前按键状态
                        }
                                               
                        break;
                case key_state_1:                                                                                                                                // 2.按键确认态
                        if (key_press == key_press_old)                                         // 与初始态的按键状态相同?
                        {
                                key_time = 0;                                                        // 清另按键时间计数器
                                switch(key_press)
                                {
                                        case K_STOP:
                                                key_state  = key_state_4;                         // 转按键释放态
                                                key_return = STOP;     
                                                                                                                           // "停止"键
                                                break;
                                        case K_START:
                                                key_state  = key_state_4;                         // 转按键释放态
                                                key_return = START;                                // "起动"键                                                
                                                break;        
                                        case K_SEL:
                                                key_state  = key_state_2;                         // 转长按键态
                                                key_return = SEL;                                // "选择"键                                                               
                                                break;        
                                        case K_ADD:
                                                key_state  = key_state_2;                         // 转长按键态
                                                key_return = ADD;                                // "+"键
                                                break;        
                                        case K_DEC:
                                                key_state  = key_state_2;                         // 转长按键态
                                                key_return = DEC;                                // "-"键
                                                break;
                                        case K_STOP|K_SEL:                                        // "组合"键,长按键
                                                key_state  = key_state_2;                         // 组合键按键仍按下,状态转换到计时1
                                                break;        
                                        default:
                                                key_state  = key_state_4;                         // 转按键释放态
                                                break;
                                }
                        }
                        else if (!key_press)
                            key_state = key_state_0;                                        // 按键已抬起(是干扰),转换到按键初始态
                        else
                                key_state = key_state_4;                                        // 按键已发生变化,转到按键释放态
                                
                        key_value_old = key_return;                                        // 保存按键返回值
                                               
                        break;
                case key_state_2:                                                                // 3.长按键确认态
                        if (key_press == key_press_old)
                        {
                                ++key_time;                                                        // 按键计时
                                if (key_press == (K_STOP|K_SEL))                        // "配置"键?
                                {
                                        if(key_time >= MuxKeyTime)                        // 组合键长按计时
                                        {
                                                key_state = key_state_4;                        // 按下时间>=MuxKeyTime,转到按键释放状态
                                                key_return = SETUP;                                // 组合键功能,"配置"键
                                        }
                                }
                                else
                                {
                                        if(key_time >= OneKeyTime)                        // 单键长按计时
                                        {
                                                key_state = key_state_3;                        // 按下时间>=OneKeyTime,转到连发功能态,用于触发连发功能
                                                key_time = 0;                                        // 清按键计数器
                                                key_return = key_value_old;                // 返回上一次按键值
                                        }
                                }
                        }
                        else
                                key_state = key_state_4;                                        // 按键已发生变化,转到按键释放态
                        break;
                case key_state_3:                                                                // 4.按键连发功能
                        if (key_press == key_press_old)
                        {
                                if (++key_time >= RepeatTime)                                // 按键时间计数
                                {
                                        key_time = 0;                                                // 按下时间>=0.05s,清0按键计数器
                                        key_return = key_value_old;                        // 返回上一次按键值
                                }                                
                        }
                        else
                            key_state = key_state_4;                                         // 按键已发生变化,转到按键释放态
                        break;
                case key_state_4:                                                                // 5.等待所有按键释放开
                        //if (!key_press)                                                                // 等待所有按键释放,才进入一次新的按键确认过程
                        if (key_press != key_press_old)                                        // 按键发生变化,就进入一次新的确认过程
                            key_state = key_state_0;                                         // 按键已释放,转换到初始态.
                        break;                        
        }   
               
               
    return key_return;
}



void Key_init(void)
{
    KEY_DDR  &=~ (K_STOP)|(K_START)|(K_SEL)|(K_ADD)|(K_DEC);
    KEY_PORT |=  (K_STOP)|(K_START)|(K_SEL)|(K_ADD)|(K_DEC);

}
void Timer0_Init(void)
{
        // T/C0 初始化
        TCCR0 = 0x0C;                        // 内部时钟,64分频(4M/64=62.5KHz),CTC模式
        TCNT0 = 0x00;
        OCR0 = 0x08;                        // OCR0 = 0x7C(124),(124+1)/62.5=2ms
        //TIMSK = 0x02;                        // 允许T/C0比较匹配中断
        TIMSK |=(1<<OCIE0);//允许T/C0比较匹配中断
}


#pragma interrupt_handler Timer0_comp_isr:20
void Timer0_comp_isr(void)
{
    //display();                                                // LED扫描显示
        if (++key_stime_counter >=5)
        {
                key_stime_counter = 0;
                key_stime_ok = 1;                                // 10ms到
                if (++time_counter >= 100)
                {
                        time_counter = 0;
                        time_1s_ok = 1;             // 1s到
                       
                }
        }


}

void main(void)
{
  Buzz_init();
  Key_init();
  Timer0_Init();
  SREG|=0x80;
  
  while(1)
  {
                  if (key_stime_ok)                               
                {

                        key_stime_ok = 0;                                // 10ms到

                        //typedef enum {NO_KEY,STOP,START,SEL,ADD,DEC,SETUP} eKEY;
                        switch (ReadKey())
                        {
                                case STOP:
                                        Beep(1,1);

                                        break;
                                case START:       
                                        Beep(5,5);
                                        break;
                                       
                                case SEL:       
                                        Beep(10,10);
                                        break;
                                case ADD:       
                                        Beep(15,15);
                                        break;
                                case DEC:       
                                        Beep(20,20);
                                        break;
                                case SETUP:       
                                        Beep(130,130);
                                        break;
                        }

                }
  }
}

出0入76汤圆

 楼主| 发表于 2012-7-6 20:52:13 | 显示全部楼层
yupusong@qhd 发表于 2012-7-6 18:25
你好,我在调试你贴上的程序,发现单个按键都正常,为什么组合键就不正常呢?代码如下:

#include

....
#define OneKeyTime        300                                                                         // 单键长按时长 = OneKeyTime * 10ms
#define MuxKeyTime        500                                                                         // 组合键长按时长 = MuxKeyTime * 10ms
#define RepeatTime        5                                                                           // 单键连发功能重复间隔时间 = RepeatTime * 10ms
...

case K_STOP|K_SEL:                                        // "组合"键,长按键
...

本程序中,组合键,只定义了: STOP + SEL 键,并且要长按5S中 才会有效。

出0入0汤圆

发表于 2012-7-6 22:03:03 | 显示全部楼层
好的,多谢提示,我再试试看

出0入0汤圆

发表于 2012-7-7 06:59:38 | 显示全部楼层
好东西,正好要用,呵呵

出0入0汤圆

发表于 2012-7-7 08:45:02 | 显示全部楼层
多谢楼主的程序,已经调试通了,很实用

出0入0汤圆

发表于 2012-7-7 23:07:58 | 显示全部楼层
其实我是进来看看有没有其他平台的版本能借用的。

~伸手党~

出0入0汤圆

发表于 2012-7-31 09:20:01 | 显示全部楼层
你这种风格不好,应该把按键扫描和按键功能执行分开,分别做成模块,

出0入76汤圆

 楼主| 发表于 2012-8-1 10:07:04 | 显示全部楼层
1.在这里只是按键的扫描部分,返回的仅是按键值而已(由枚举类型已定义好的,是只为了方便识别),是只代表是哪个按键按下(相当于一个标识符吧),并没有去具体定义按键的任何功能。
2.具体按键功能的实现(处理),是于由它的上层模块来完成。

出0入0汤圆

发表于 2012-11-27 14:07:05 | 显示全部楼层
我试试看

出0入0汤圆

发表于 2013-9-4 10:23:58 | 显示全部楼层
嘿嘿!做次伸手党,谢谢大神,我好好理解一下!

出0入0汤圆

发表于 2013-9-4 13:19:16 | 显示全部楼层
标记下。。。。

出0入0汤圆

发表于 2013-9-12 20:50:25 | 显示全部楼层
我想知道这个函数执行完了要多长时间,为什么我这个15ms还跑不完呢?

出0入0汤圆

发表于 2013-9-12 20:57:42 | 显示全部楼层
标记下,用的时候再看.

出0入0汤圆

发表于 2013-11-26 13:32:49 | 显示全部楼层
长按键跟短按键值返回都是一样,怎么在应用区别开来呢?

出0入76汤圆

 楼主| 发表于 2013-11-26 17:45:38 | 显示全部楼层
zbazba 发表于 2013-11-26 13:32
长按键跟短按键值返回都是一样,怎么在应用区别开来呢?

长按与短按返回的值不能一样,  而持续按键实现连发功能 与 短按的返回的值是一样的。

出0入0汤圆

发表于 2013-11-27 09:21:49 | 显示全部楼层
foxpro2005 发表于 2013-11-26 17:45
长按与短按返回的值不能一样,  而持续按键实现连发功能 与 短按的返回的值是一样的。

...

短按与长按肯定不能一样.但连发与短按返回值为什么能一样呢.应用怎么调用呢? 这个不解,呵呵.能告诉我下不?
可以这样处理,让短按的键值或上一个数值.返回这个.当然返回的数值不能跟别的冲突了.

出0入76汤圆

 楼主| 发表于 2013-11-27 12:04:20 | 显示全部楼层
连发就是相当于每次扫描的时候,把短按(正常操作)的值返回

出0入0汤圆

发表于 2013-11-28 11:56:04 | 显示全部楼层
学习。。。

出0入0汤圆

发表于 2013-11-28 12:25:45 | 显示全部楼层
foxpro2005 发表于 2013-11-27 12:04
连发就是相当于每次扫描的时候,把短按(正常操作)的值返回

提供一个我写的功能类似的按键程序给大家做参考
传送门:http://www.amobbs.com/forum.php? ... page%3D1#pid7142055

出0入0汤圆

发表于 2013-12-17 09:28:11 | 显示全部楼层
您好,楼主!看了你的程序,有点疑问想请教一下,你的程序是不是一个按键要么只能短按,要么只能长按,而不能一个按键同时具有短按,长按组合按的功能啊?

出0入0汤圆

发表于 2013-12-18 22:39:10 | 显示全部楼层
支持一个啊啊啊啊

出0入0汤圆

发表于 2014-8-18 17:31:04 | 显示全部楼层
谢谢分享.....

出0入0汤圆

发表于 2014-8-20 15:00:38 | 显示全部楼层
谢谢分享,学习学习

出0入0汤圆

发表于 2014-8-20 20:49:21 | 显示全部楼层
参考一下        

出0入0汤圆

发表于 2014-9-8 16:48:07 | 显示全部楼层
组合键时.甜腻问题

出0入0汤圆

发表于 2014-10-17 10:05:08 | 显示全部楼层
这个按键程序遇到一个问题,就是当按键按下就会返回短按的状态,而不是抬起才返回,这样子无法实现短按和长按实现不同的功能

出0入0汤圆

发表于 2014-10-17 10:07:50 | 显示全部楼层
mark,按键少的时候很有用

出0入0汤圆

发表于 2014-10-17 15:31:06 | 显示全部楼层
如果能够区分长按和短按就更好了

出0入0汤圆

发表于 2014-10-17 17:08:39 来自手机 | 显示全部楼层
支持一下!!!!!

出0入0汤圆

发表于 2014-10-17 17:56:33 | 显示全部楼层
谢谢分享。。

出0入0汤圆

发表于 2014-11-11 22:39:16 | 显示全部楼层
  1. #include "Main.h"

  2. eKEY ReadKey(void)        {
  3.         static U16 key_time =0;                //长按键计时
  4.         static U8 key_state = 0;        //记录按键当前扫描状态
  5.         static U8 key_press_old = 0;        //记录上一次按键状态
  6.         static eKEY key_value_old = NO_KEY;        //保存上一次按键返回值
  7.         eKEY key_return = NO_KEY;        //按键功能返回值
  8.         U8 key_press;
  9.        
  10.         key_press = GetKey()^ Key_Mask;        //读按键IO电平,只保留被按下的键(被按下的键位为1)
  11.        
  12.         switch (key_state)        {
  13.                 case key_state_0:        //按键初始态
  14.                         if(key_press)        {
  15.                                 key_state = key_state_1;        //键被按下,状态转换到按键确认态
  16.                                 key_press_old = key_press;        //保存当前按键状态
  17.                         }
  18.                         break;
  19.                 case key_state_1:        //按键确认态
  20.                         if(key_press == key_press_old)        //与初始态按键状态相同?
  21.                         {
  22.                                 key_time = 0;        //清零
  23.                                 switch (key_press)
  24.                                 {
  25.                                         [color=DarkOrange]case OPEN:[/color]        //case:K_OPEN ,这样写编译报错                                       
  26.                                                 key_state = key_state_4;        //转按键释放态
  27.                                                 key_return = OPEN;
  28.                                                 break;
  29.                                        
  30.                                         case CLOSE:                        //case:K_COLSE ,报错
  31.                                                 key_state = key_state_4;        //转按键释放态
  32.                                                 key_return = CLOSE;
  33.                                                 break;
  34.                                        
  35.                                         default:
  36.                                                 key_state = key_state_4;        //转按键释放态
  37.                                                 break;
  38.                                 }
  39.                         }
  40.                         else if(!key_press)       
  41.                                 key_state = key_state_0;        //按键已抬起(干扰),转初始态
  42.                         else
  43.                                 key_state = key_state_4;        //按键已发生变化,转到按键释放态
  44.                        
  45.                         key_value_old = key_return;        //保存按键返回值
  46.                        
  47.                         break;       
  48.                 case key_state_4:        //等待所有按键释放开
  49.                         if(key_press != key_press_old)        //按键发生变化,就进入一次新的确认过程
  50.                                 key_state = key_state_0;        //按键已释放,转换到初始态
  51.                         break;
  52.         }
  53.         return key_return;
  54. }


  55. void LockProc(void)        {
  56.         switch(ReadKey())        {
  57.                 case OPEN:
  58.                                 OpenLockOut();
  59.                         break;
  60.                 case CLOSE:
  61.                                 ClosLockOut();
  62.                         break;
  63.                 case NO_KEY:
  64.                 default:
  65.                                 ResetLock();
  66.         }
  67. }

  68. void T10msEvent(void)        {
  69.         LockProc();
  70. }
复制代码
  1. #ifndef        _PPQC_H
  2. #define        _PPQC_H

  3. #define        OpenLockOut()        do{OpenOut=1;ClosOut=0;}while(0)
  4. #define        ClosLockOut()        do{OpenOut=0;ClosOut=1;}while(0)
  5. #define ResetLock()                do{OpenOut=0;ClosOut=0;}while(0)

  6. #define OneKeyTime        300                // 单键长按时长 = OneKeyTime * 10ms
  7. #define MuxKeyTime  500                // 组合键长按时长 = MuxKeyTime * 10ms
  8. #define RepeatTime        5                // 单键连发功能重复间隔时间 = RepeatTime * 10ms

  9. #define Key_Mask (K_CLOSE|K_OPEN)        //按键掩码值

  10. #define GetKey()        (KEY_PORT & Key_Mask)        //读取按键端口值

  11. #define key_state_0                0        //初始态
  12. #define key_state_1                1        //确认态
  13. #define key_state_2     2        //组合键,长按键确认态
  14. #define key_state_3                3        //长按连发功能确认态
  15. #define key_state_4                4        //等待释放态

  16. typedef enum{NO_KEY,OPEN,CLOSE}eKEY;        //按键返回值类型定义

  17. eKEY ReadKey(void);
  18. void LockProc(void);
  19. void T10msEvent(void);

  20. #endif
复制代码
我把这个应用到PIC16F1824中,编译器9.83,proteus仿真结果不对。不知道哪里出错了。

出0入0汤圆

发表于 2014-11-11 22:56:44 | 显示全部楼层
CLOSEOUT一直有输出,K_CLOSE按下时,OPENOUT反而有输出。

出0入0汤圆

发表于 2014-11-12 09:38:04 | 显示全部楼层
问题解决了。
1、对于CLOSEOUT一直有输出,在端口初始化中,将LATC=0放在TRISC=0前面;
2、对于K_CLOSE按下时,OPENOUT反而有输出。将key_state_1里面的switch语句,case OPEN和case CLOSE改成:case 3,和case 1。
疑问:
1、#define        K_CLOS                (1<<RA2) 和 K_OPEN                (1<<RA1),为什么PICC不能像楼主那样写成case K_CLOS 和K_OPEN;
2、为什么case OPEN和case CLOSE改成:case 3,和case 1就仿真成功?3和1是如何得到的?难道PICC将 K_OPEN                (1<<RA1)转换成了3?

出0入0汤圆

发表于 2014-11-15 17:10:15 | 显示全部楼层
想了几天了,还是不明白#define        K_CLOS                (1<<RA2) ,为什么case :k_CLOS 通不过

出0入76汤圆

 楼主| 发表于 2014-11-15 20:13:53 | 显示全部楼层
zw_7627 发表于 2014-11-15 17:10
想了几天了,还是不明白#define        K_CLOS                (1

case 分支 必须是确定的常量 , 你好像是用的PIC单片机吧, RA2不是常量哦, 而是读取的引脚吧

出0入0汤圆

发表于 2014-11-17 13:03:48 | 显示全部楼层
foxpro2005 发表于 2014-11-15 20:13
case 分支 必须是确定的常量 , 你好像是用的PIC单片机吧, RA2不是常量哦, 而是读取的引脚吧  ...


一语中的。我以为PD3就是端口。查资料得知在AVR宏定义中有#define PD3 3。受教了,明白了。多谢。

出0入0汤圆

发表于 2014-11-17 14:15:28 | 显示全部楼层
本帖最后由 zw_7627 于 2014-11-17 14:16 编辑

发现key_press = GetKey()^ Key_Mask;只对相同电平输入有效,倘若有2路高入和2路低入同时存在,则无法判断。比如:RA1,RA2内部上拉,则PORTA= 000110;
而Key_Mask=110110; key_press = 110000;造成无法识别状态。

出0入0汤圆

发表于 2015-10-13 08:26:29 | 显示全部楼层
不一定好用啊

出0入0汤圆

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

本版积分规则

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

GMT+8, 2024-3-28 16:39

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

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