/************************************************************************************************************
* 文 件 名 : bsp_Key.c
* 负 责 人 : lll
* 创建日期 : 2017年11月28日
* 文件描述 : 按键扫描与按键事件处理
* 版权说明 : Copyright (c) 2008-2017 xx xx xx xx 技术有限公司
* 其 他 :
* 修改日志 :
**************************************************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include "bsp_Vacuum260.h"
#include "bsp_Key.h"
#include "bsp_LED.h"
#include "bsp_74hc595.h"
typedef struct
{
void (*KeyEventFunc)(void);
UINT16 LongTime; /* 长按键生效时间,0表示非长按键 */
UINT8 ReentryTime; /* 长按键重复生效时间,0表示键值不重复生效 */
UINT8 FiltTime; /* 去抖滤波时间 */
UINT8 KeyVal; /* 按键起始键值,每个按键有三个键值,enum定义依次为“按下”“弹起”“长按” */
}KeyElem_TypeDef;
// 按键元素表
KeyElem_TypeDef const KeyElem[KEY_QTY] = {
{ Key_StopKey, 600, 0, 4, KEY_0_DOWN },
{ Key_VacuumTimeSet, 0, 0, 4, KEY_1_DOWN },
{ Key_SealTimeSet, 0, 0, 4, KEY_2_DOWN },
{ Key_DigitInc, 150, 20, 4, KEY_3_DOWN },
{ Key_DigitDec, 150, 20, 4, KEY_4_DOWN },
{ Key_HeatLevelSet, 0, 0, 4, KEY_5_DOWN },
{ Key_SealTimeMaxInc, 150, 20, 4, KEY_6_DOWN }, // KEY_0和KEY_3组合
{ Key_SealTimeMaxDec, 150, 20, 4, KEY_7_DOWN } // KEY_0和KEY_4组合
};
KeyMode_TypeDef KeyMode;
KeyMsg_TypeDef KeyMsg;
KeyQueue_TypeDef KeyQueue; /* 键值循环队列结构变量 */
QelemType KeyCode[KEY_QTY]; /* 循环队列键值数组 */
persistent KeyVar_TypeDef KeyVar[KEY_QTY]; /* 按键扫描结构变量 */
persistent volatile UINT8 KeysState;
persistent volatile UINT8 Key_SetPoint;
persistent volatile UINT8 *gParamPtr; /* 读写参数缓存区指针 */
extern UINT8 ByteMod( UINT8 dividend, UINT8 divisor );
extern UINT8 ByteDiv( UINT8 dividend, UINT8 divisor );
/***********************************************************************************************************
* [url=home.php?mod=space&uid=247401]@brief[/url] 按键参数初始化
************************************************************************************************************/
void Key_Init(void)
{
UINT8 i;
KeyQueue.Buf = KeyCode;
KeyQueue.rear = 0;
KeyQueue.front = 0;
for( i = 0; i < KEY_QTY; i++ )
{
KeyVar[i].KeyGet = FALSE;
KeyVar[i].KeyState = KEY_UP;
KeyVar[i].FiltCnt = 0;
KeyVar[i].LongCnt = 0;
KeyVar[i].ReentryCnt = 0;
}
Key_SetPoint = NO;
KeyMode.bMode = 0; //0=直接加减方式,1=位选加减方式
}
/**************************************************************************************************************
* @brief 按键队列压入键值
* @param _KeyCode
**************************************************************************************************************/
void Key_QueueIn( UINT8 _KeyCode )
{
KeyQueue.Buf[KeyQueue.rear] = _KeyCode;
if( ++KeyQueue.rear >= KEY_QTY )
{
KeyQueue.rear = 0;
}
}
/**************************************************************************************************************
* @brief 按键队列弹出键值
* [url=home.php?mod=space&uid=266161]@return[/url] 键值
**************************************************************************************************************/
UINT8 Key_QueueOut( void )
{
UINT8 ret;
if( KeyQueue.front == KeyQueue.rear )
{
return KEY_NONE;
}
else
{
ret = KeyQueue.Buf[KeyQueue.front];
if( ++KeyQueue.front >= KEY_QTY )
{
KeyQueue.front = 0;
}
return ret;
}
}
/**************************************************************************************************************
* @brief 按键扫描,获取按键ID
* 矩阵式扫描,RB7,RB6 为扫描读取口;RB2,RB1,RB0通过NPN三极管反向后作为键盘的扫描口。
* @Param pPORTx:键盘扫描所在端口指针
* pKeyID: 按键ID顺序存放数组指针
* [url=home.php?mod=space&uid=536309]@NOTE[/url] 按键引脚硬件分布
* 矩阵式扫描,RB7,RB6 为扫描读取口;RB2,RB1,RB0通过NPN三极管反向后作为键盘的扫描口。
*
* RB0_____。_____|_____________|____________
* |0 |3
* RB1_____。_____|_____________|____________
* |1 |4
* RB2_____。_____|_____________|____________
* |2 |5
* RB6____________| |
* |
* RB7__________________________|
**************************************************************************************************************/
/* 根据硬件情况,扫描从低位左移,检测从高位右移,因此按键ID表的排列顺序是3,0,4,1, 5,2 */
const UINT8 KeyID_Table[3][2] = { { 3, 0 },{ 4, 1 },{ 5, 2 } };
/* 按键扫描后,按键ID按0-N的排列顺序存入数组 */
UINT8 KeyID[KEY_QTY] = { 0 ,1, 2, 3, 4, 5, 6, 7 };
static void GetKeyID( PORT_TypeDef *pPORTx, UINT8 *pKeyID )
{
UINT8 idx, i, j;
for( i = 0; i < KEY_QTY; i++ )
{
pKeyID[i] = 255; /* 255表示按键未按下 */
}
for( i = 0; i < 3; i++ ) /* 扫描所有按键 */
{
*pPORTx &= ~KEY_SCAN_PINS_SET;
NOP();
NOP();
*pPORTx |= 1 << i;
NOP();
NOP();
for ( j = 0; j < 2; j++ )
{
if( ( *pPORTx & ( 0x80 >> j ) ) == 0 )
{
idx = KeyID_Table[i][j];
pKeyID[idx] = KeyID_Table[i][j]; /* 按键ID按0-N的顺序存入 数组 */
}
}
}
}
/**************************************************************************************************************
* @brief 单个按键扫描
* 完成按键去抖,获取按键“按下”“弹起”“长按”三个键值,并将键值压入队列。
* @Param idx:按键索引,表示扫描哪一个按键
* KeyID:
**************************************************************************************************************/
static void GetKeyValue( UINT8 idx, UINT8 keyID )
{
KeyVar_TypeDef *pKeyVar;
KeyElem_TypeDef const *pKeyElem;
pKeyVar = &KeyVar[idx];
pKeyElem = &KeyElem[idx];
if( keyID != 255 )
{
if( pKeyVar->FiltCnt < pKeyElem->FiltTime )
{
pKeyVar->FiltCnt = KeyElem->FiltTime;
}
if( pKeyVar->FiltCnt < 2 * KeyElem->FiltTime )
{
pKeyVar->FiltCnt++;
}
else
{
/* 如果长按时间设置大于0,说明是长按键 */
if( pKeyElem->LongTime > 0 )
{
if( pKeyVar->LongCnt < pKeyElem->LongTime )
{
if( ++pKeyVar->LongCnt == pKeyElem->LongTime )
{
pKeyVar->KeyState = LONG_DOWN;
Key_QueueIn( pKeyElem->KeyVal + 2 ); /* 获取当前按键“长按”键值,一次按下只获取一次 */
}
}
else
{
/* 如果键值重复生效时间设置大于0,说明需要重复获取键值 */
if( pKeyElem->ReentryTime > 0 )
{
if( ++pKeyVar->ReentryCnt > pKeyElem->ReentryTime )
{
pKeyVar->ReentryCnt = 0;
pKeyVar->KeyState = KEY_DOWN;
Key_QueueIn( pKeyElem->KeyVal ); /* 长按键重复获取“按下”键值 */
}
}
}
}
if( pKeyVar->KeyGet == FALSE ) /* 非长按键一次按下只获取一次“按下”键值 */
{
pKeyVar->KeyGet = TRUE;
pKeyVar->KeyState = KEY_DOWN;
Key_QueueIn( pKeyElem->KeyVal ); /* 当前按键“按下”键值压入按键队列 */
}
}
}
else/* 判断按键释放 */
{
if( pKeyVar->FiltCnt > KeyElem->FiltTime )
{
pKeyVar->FiltCnt = KeyElem->FiltTime;
}
if( pKeyVar->FiltCnt > 0 )
{
pKeyVar->FiltCnt--;
}
else
{
if( pKeyVar->KeyGet == TRUE ) /* 当前按键“弹起”键值只获取一次 */
{
pKeyVar->KeyGet = FALSE;
Key_QueueIn( pKeyElem->KeyVal + 1 ); /* 当前按键“弹起”键值压入按键队列 */
}
pKeyVar->LongCnt = 0;
pKeyVar->ReentryCnt = 0;
pKeyVar->KeyState = KEY_UP;
}
}
}
/**************************************************************************************************************
* @brief 按键扫描函数
* 矩阵式扫描,RB7,RB6 为扫描读取口;RB2,RB1,RB0反向后作为键盘的行扫描。
* @note RB2,RB1,RB0反向后也是数码管和 LED的位驱动口,因此键盘扫描前要先保存
* 扫描端口的位值,扫描结束后还原。
* @Param *PORTx 键盘扫描所在端口
**************************************************************************************************************/
void KeyScan( PORT_TypeDef *pPORTx )
{
UINT8 i;
UINT8 PortKeep;
C595_Pin_OE = 1; /* 关闭 74ls595 三态缓冲输出 */
PortKeep = *pPORTx; /* 保存扫描端口 */
GetKeyID( pPORTx, KeyID ); /* 获取按键ID */
*pPORTx = PortKeep; /* 还原 PORT 口 */
C595_Pin_OE = 0; /* 允许 74595 三态缓冲输出 */
// 组合键ID
if( ( KeyID[0] != 255 ) && ( KeyID[3] != 255 ) )
{
KeyID[6] = 6;
KeyID[3] = 255;
}
if( ( KeyID[0] != 255 ) && ( KeyID[4] != 255 ) )
{
KeyID[7] = 7;
KeyID[4] = 255;
}
KeysState = 0;
for( i = 0; i < KEY_QTY; i++ )
{
GetKeyValue( i, KeyID[i] );
KeysState |= KeyVar[i].KeyState;
}
}
/*************************************************************************************************************
* @brief 按键事件处理函数
* 采用状态机判断键值,根据键值调用相应的按键事件函数,键值由按键队列弹出。
*************************************************************************************************************/
void KeyEventFunc( void )
{
switch( Key_QueueOut( ) ){
case KEY_0_DOWN:
KeyElem[0].KeyEventFunc();
break;
case KEY_0_LONG:
Key_SetPoint = SET_SEAL_MAX;
DispBuffer[DPYCC_C1_TENS] = Segment[ ByteDiv( ParamBuf[P_SEAL_MAX_IDX], 10 ) ] | 0x80;
DispBuffer[DPYCC_C2_UNIT] = Segment[ ByteMod( ParamBuf[P_SEAL_MAX_IDX], 10 ) ];
BeepCtrl = SIGNAL;
break;
case KEY_0_UP:
if( Key_SetPoint == SET_SEAL_MAX )
{
KeyMsg.EnterKey = YES;
Key_SetPoint = NONE;
}
break;
case KEY_1_DOWN:
KeyElem[1].KeyEventFunc();
break;
case KEY_2_DOWN:
KeyElem[2].KeyEventFunc();
break;
case KEY_3_DOWN:
KeyElem[3].KeyEventFunc();
break;
case KEY_4_DOWN:
KeyElem[4].KeyEventFunc();
break;
case KEY_5_DOWN:
KeyElem[5].KeyEventFunc();
break;
case KEY_6_DOWN:
KeyElem[6].KeyEventFunc();
break;
case KEY_7_DOWN:
KeyElem[7].KeyEventFunc();
break;
default:
break;
}
}