//******************************************************************************
// 独立按键(支持长/短按键)程序库(For msp430)
//
// File : msp430_Key.c
// By : Winged Steed
// Ver : V1.0 (2011/11/29)
//
//******************************************************************************
#include "msp430_Key.h"
#define DISABLE_INT KEY_SR=__get_SR_register();_DINT()
#define RESTORE_INT if(KEY_SR & GIE) _EINT()
unsigned char KEY_SR;
unsigned char Key_IndexW = 0; //按键FIFO的写指针
unsigned char Key_IndexR = 0; //按键FIFO的读指针
unsigned char KeyBuff[KEY_BUFF_SIZE]; //按键FIFO数组
unsigned char Key_Count = 0; //按键FIFO内记录的按键次数
unsigned char KEY_State = 0; //按键状态变量
unsigned char KEY_Record = 0; //键值记录变量
unsigned char Key_Timer_S=0,Key_Timer_L=0;//软件定时器变量
/*******************************************************************************
函数名称:Key_Init()
函数功能:初始化键盘所在的IO口
入口参数:无
出口参数:无
*******************************************************************************/
void Key_Init(void)
{
KEY_DIR &= ~(KEY_BIT); //键盘IO口设置为输入
}
/*******************************************************************************
函数名称:Key_InBuff()
函数功能:将一次键值压入键盘缓冲队列
入口参数:
Key: 被压入缓冲队列的键值
出口参数:无
*******************************************************************************/
void Key_InBuff(unsigned char Key)
{
switch(Key)
{
#if (KEY_NUM >= 1)
case KEY1_VAL: Key = KEY1; break;
case (KEY1_VAL+FIRSTLONG): Key = FIRSTLONG+KEY1; break;
case (KEY1_VAL+LONG): Key = LONG+KEY1; break;
#endif
#if (KEY_NUM >= 2)
case KEY2_VAL: Key = KEY2; break;
case (KEY2_VAL+FIRSTLONG): Key = FIRSTLONG+KEY2; break;
case (KEY2_VAL+LONG): Key = LONG+KEY2; break;
#endif
#if (KEY_NUM >= 3)
case KEY3_VAL: Key = KEY3; break;
case (KEY3_VAL+FIRSTLONG): Key = FIRSTLONG+KEY3; break;
case (KEY3_VAL+LONG): Key = LONG+KEY3; break;
#endif
#if (KEY_NUM >= 4)
case KEY4_VAL: Key = KEY4; break;
case (KEY4_VAL+FIRSTLONG): Key = FIRSTLONG+KEY4; break;
case (KEY4_VAL+LONG): Key = LONG+KEY4; break;
#endif
}
if (Key_Count >= KEY_BUFF_SIZE) return; //若FIFO已满,放弃本次按键
DISABLE_INT;
Key_Count++; //按键次数计数加1
KeyBuff[Key_IndexW] = Key; //通过写指针将键值写入按键FIFO
if (++Key_IndexW >= KEY_BUFF_SIZE)
{
Key_IndexW = 0;
}
RESTORE_INT;
}
/*******************************************************************************
函数名称:Key_GetKey()
函数功能:从键盘缓冲队列内读取一次键值
入口参数:无
出口参数:若无按键,返回0,否则返回一次按键键值。
函数说明:调用一次该函数,会自动删除缓冲队列里一次按键键值。
*******************************************************************************/
unsigned char Key_GetKey(void)
{
unsigned char Key;
if (Key_Count == 0) return(0); //若无按键,返回0
DISABLE_INT;
Key_Count--; //按键次数计数减1
Key = KeyBuff[Key_IndexR]; //通过读指针从按键FIFO中读取一个键值
if (++Key_IndexR >= KEY_BUFF_SIZE)
{
Key_IndexR = 0;
}
RESTORE_INT;
return(Key);
}
/*******************************************************************************
函数名称:Key_WaitKey()
函数功能:从键盘缓冲队列内读取一次键值
入口参数:无
出口参数:若有按键,返回键值,否则等待按键。
函数说明:该函数会阻塞CPU继续执行后面的程序,应用时需注意。
*******************************************************************************/
unsigned char Key_WaitKey(void)
{
unsigned char Key;
while(1)
{
Key = Key_GetKey(); //从键盘缓冲队列读取一次键值
if(Key==0) LPM3; //如果没按键,则停止CPU,等待被唤醒继续读按键
else return(Key); //如果有按键,则返回键值
}
}
/*******************************************************************************
函数名称:Key_ScanIO()
函数功能:扫描键盘IO口并判断按键事件
入口参数:无
出口参数:无,键值压入缓冲队列
应用范例:在1/32秒中断内调用: Key_ScanIO();
函数说明: 该函数需要每隔1/16秒至1/128秒调用一次。最好放在定时中断内执行。
如果中断间隔太长,可能丢键;间隔太短不能消除抖动。
*******************************************************************************/
void Key_ScanIO(void)
{
if(KEY_State == STA_SHORTKEY) Key_Timer_S++; //2s定时器
else Key_Timer_S = 0;
if(KEY_State == STA_LONGKEY) Key_Timer_L++; //0.25s定时器
else Key_Timer_L = 0;
switch (KEY_State)
{
case STA_NOKEY: //处于“未按”状态时
{
if(KEY_IN != KEY_BIT) //若有按键按下
{
KEY_State = STA_SHORTKEY; //按键状态转移到“短按”状态
KEY_Record = KEY_IN; //记录按键值
}
break;
}
case STA_SHORTKEY: //处于“短按”状态时
{
if(KEY_IN == KEY_BIT) //若按键被释放
{
Key_InBuff(KEY_Record); //将短按键键值压入缓冲区
KEY_State = STA_NOKEY; //按键状态转移到“未按”状态
KEY_Record = KEY_IN; //记录按键值
}
else if(Key_Timer_S > SCAN_FREQ*2) //若按键时间超过2s,返回首次长按键
{
Key_InBuff(FIRSTLONG + KEY_Record); //将首次长按键键值压入缓冲区
KEY_State = STA_LONGKEY; //按键状态转移到”长按“状态
}
break;
}
case STA_LONGKEY: //处于“长按”状态时
{
if(KEY_IN == KEY_BIT) //若按键被释放
{
KEY_State = STA_NOKEY; //按键状态转移到“未按”状态
}
else if(Key_Timer_L > SCAN_FREQ/4) //若按键超过0.25s,返回连续长按键
{
Key_InBuff(LONG + KEY_Record); //将连续长按键键值压入缓冲区
Key_Timer_L = 0; //清空定时器
}
break;
}
}
}