最近发现GPIO的中断功能有点问题,查了两天确实也没查出来为什么,毕竟中断管理也不没那么容易,所有暂且用扫描的办法来解决,下面这个算法很经典,记下,备以后参考.
--------------------------------------------file "key.h"----------------------------------------------
#ifndef KEY_H
#define KEY_H
/*----------------key definition--------------*/
#define NO_KEY 0x00
#define PLAY_KEY 0x01 /* vcd key */
#define STOP_KEY 0x02
#define NEXT_KEY 0x03
#define PREV_KEY 0x04
#define REPEAT_KEY 0x05
#define PROGRAM_KEY 0x06
#define REMAIN_KEY 0x07
#define VOCAL_ASSIST_KEY 0x08
#define VOLUME_UP_KEY 0x09
#define VOLUME_DOWN_KEY 0x0a
#define TV_MODE_KEY 0x0b
#define EJECT_KEY 0x0c
#define FB_KEY 0x0d
#define FF_KEY 0x0e
#define POWER_KEY 0x20 /* common key */
#define CLOCK_KEY 0x21
#define SLEEP_KEY 0x22
#define FUNCTION_KEY 0x23
#define TONE_KEY 0x24
#define EQ_KEY 0x25
#define SBASS_KEY 0x26
#define RADIO_KEY 0x27
#define TAPE_KEY 0x28
#define AUX_KEY 0x29
#define VCD_KEY 0x30
#define MEM_KEY 0x31 /* radio key */
#define MEM_MINUS_KEY 0x32
#define MEM_PLUS_KEY 0x33
#define AM_STEP_KEY 0x34
#define BAND_KEY 0x35
#define SEARCH_UP_KEY 0x36
#define SEARCH_DOWN_KEY 0x37
#define AUTO_SEARCH_UP_KEY 0x38
#define AUTO_SEARCH_DOWN_KEY 0x39
/*---------------end key definition-----------*/
#define KEY_IDLE_STATE 0
#define KEY_SHAKE_STATE 1
#define KEY_COMPLEX_STATE 2
#define KEY_REPEAT_STATE 3
#define KEY_WAIT_UP 4
extern unsigned char shake_cancel_timer;
extern unsigned char complex_key_timer;
extern unsigned char repeat_key_timer;
extern unsigned char current_key;
extern unsigned char current_state;
extern void scan_key();
extern void process_panel_key();
extern unsigned char is_repeat_key(unsigned char);
#endif
------------------------------------------------file "key.c"-----------------------------------------------
#include "key.h"
#include "display.h"
unsigned char current_state; /* RADIO / VCD /TAPE /AUX */
unsigned char current_key;
unsigned char key;
unsigned char is_repeat_key(unsigned char);
void scan_key();
void process_panel_key();
/*====================================================================================================
扫描面板按键程序
====================================================================================================*/
void scan_key()
{
set_row1;
set_row2;
set_row3;
set_row4;
key = NO_KEY;
clear_col1;
set_col2;
set_col3;
set_col4;
if (check_row1_low) key = SEARCH_DOWN_KEY;
if (check_row2_low) key = SEARCH_UP_KEY;
if (check_row3_low) key = BAND_KEY;
if (check_row4_low) key = EJECT_KEY;
set_col1;
clear_col2;
set_col3;
set_col4;
if (check_row1_low) key = MEM_MINUS_KEY;
if (check_row2_low) key = MEM_PLUS_KEY;
if (check_row3_low) key = MEM_KEY;
if (check_row4_low) key = AM_STEP_KEY;
set_col1;
set_col2;
clear_col3;
set_col4;
if (check_row1_low) key = SLEEP_KEY;
if (check_row2_low) key = SBASS_KEY;
if (check_row3_low) key = CLOCK_KEY;
if (check_row4_low) key = VOLUME_DOWN_KEY;
set_col1;
set_col2;
set_col3;
clear_col4;
if (check_row1_low) key = POWER_KEY;
if (check_row2_low) key = FUNCTION_KEY;
if (check_row3_low) key = TONE_KEY;
if (check_row4_low) key = VOLUME_UP_KEY;
}
/*====================================================================================
处理面板按键程序
=====================================================================================*/
unsigned char shake_cancel_timer;
unsigned char complex_key_timer;
unsigned char repeat_key_timer;
unsigned char scan_key_state;
unsigned char key_bak;
unsigned char repeat_key;
void process_panel_key()
{
scan_key();
switch (scan_key_state)
{
case KEY_IDLE_STATE: //按键空闲状态
if (key!=NO_KEY) //如果有按键按下,则进入按键消抖状态。
{
key_bak = key;
shake_cancel_timer = 1; //消抖时间设定为20ms
scan_key_state = KEY_SHAKE_STATE;
}else //如果没有按键按下,继续为空闲检测状态。
{
scan_key_state = KEY_IDLE_STATE;
}
break;
case KEY_SHAKE_STATE: //按键去抖状态
if (!shake_cancel_timer)
{
if (key == key_bak) //消抖后,如果按键未变,进入复合检测状态。
{
scan_key_state = KEY_COMPLEX_STATE;
complex_key_timer = 100; //复合判断时间为200ms 小于200ms为原功能,大于200ms为复合功能。
}else //确认为按键抖动。
{
scan_key_state = KEY_IDLE_STATE;
}
}
break;
case KEY_COMPLEX_STATE: //按键复合处理状态
if (!complex_key_timer)
{
if (key == key_bak) //复合检测时间到,按键仍按下。
{
if (key == SEARCH_UP_KEY) //执行next的复合功能。
{
current_key = AUTO_SEARCH_UP_KEY;
}else if (key == SEARCH_DOWN_KEY) //执行prev的复合功能。
{
current_key = AUTO_SEARCH_DOWN_KEY;
}else //执行没有复合功能的按键。
{
current_key = key;
}
if (is_repeat_key(key)) //检测为可重复按键时,进入重复状态。
{
repeat_key = current_key;
scan_key_state = KEY_REPEAT_STATE;
repeat_key_timer = 20; // 按键重复时间为200ms,如果连续按键,每200ms执行重复按键操作。
}else //检测为不可重复按键时,进入按键抬起等待状态。
{
scan_key_state = KEY_WAIT_UP;
}
}else //按键已经抬起,执行未复合功能。
{
current_key = key_bak;
scan_key_state = KEY_IDLE_STATE;
}
}else
{
if (key != key_bak) //按键抬起,执行未复合功能。
{
current_key = key_bak;
scan_key_state = KEY_IDLE_STATE;
}
}
break;
case KEY_REPEAT_STATE: //按键重复处理状态
if (key == key_bak)
{
if (!repeat_key_timer) //按键重复时间到,再次执行按键功能。
{
repeat_key_timer = 20; // 按键重复时间为200ms,如果连续按键,每200ms执行重复按键操作。
current_key = repeat_key;
}
}else //按键抬起,回到按键空闲检测状态。
{
scan_key_state = KEY_IDLE_STATE;
}
break;
case KEY_WAIT_UP: //按键等待抬起状态
if (key!= key_bak)
{
scan_key_state = KEY_IDLE_STATE; //按键抬起,返回按键空闲检测状态。
}
break;
}
}
/*------------------------------------------------------------------------------------------------*/
unsigned char is_repeat_key(unsigned char r_key) //重复按键检测通行函数。
{
if ((r_key == VOLUME_UP_KEY)||(r_key == VOLUME_DOWN_KEY)||(r_key == SEARCH_UP_KEY)||(r_key == SEARCH_DOWN_KEY))
{
return 1;
}else
{
return 0;
}
}
/*-----------------------------------------------------------------------------------------------*/