不管是IO扫键,还是AD扫键,其核心点是在有按键的时候,状态会发生变化,所以在写扫键的时候,基本上都会使用状态机机制
显而易见的是这四个状态分别为
c_ADC_Key_Status_IDLE空闲状态
c_ADC_Key_Status_DB 消抖
c_ADC_Key_Status_PressDown 确认按键按下
c_ADC_Key_Status_PressUp确认按键松开
另外,在扫AD按键的时候,都有AD值,所以推荐针对不同的AD值的时候,应该做一个对于该AD值的按键掩码
这样做的好处有,可以根据不同的掩码值,来设置该按键的不同信息,和索引值,、
然后根据索引值来建立一个表格,
故在确认按键状态的时候,可以根据索引去动态的修改,这样程序的可维护性和健壮性会大大的加强,
具体AD扫键代码和思维如下
/*
描述:
AD扫键使用状态机机制
作者:GHOUL
*/
#include "adc_key.h"
u8 g_adc_key_buffer; //AD缓存寄存器
u8 g_adc_key_status; //AD扫键状态标记
u8 g_Flag_adc_timer; //AD扫描定时器标志,外部使用64HZ
u8 g_adc_DBtimerCnt; //消抖计数
u8 g_adc_hold_keyTimerCnt; //用于长按计数
/*
函数名字:ADC_Key_Init
形参:无
返回:无
功能:AD按键初始化
*/
void ADC_Key_Init(void)
{
ADC_ChannelInit(); //AD寄存器初始化
g_adc_key_status = c_ADC_Key_Status_IDLE; //设置扫键初始状态
g_adc_key_buffer = 0; //设置缓冲器
g_adc_DBtimerCnt = 0;
g_adc_hold_keyTimerCnt = 0;
}
/*
函数名字:ADC_ChannelGetKeyIdx
形参:无
返回:u32 按键索引值
功能:根据读取到的AD值,计算按键在表格中的索引值
*/
static u32 ADC_ChannelGetKeyIdx(void)
{
u16 t_adc_value;
u8 t_adc_value_idx;
t_adc_value = ADC_GetValue(); //读取AD值
//根据AD值,得出该按键在键值索引表中的位置
if(t_adc_value >= (c_AD_Accuracy_Value - (c_AD_Accuracy_Value / c_AD_Key_Num) / 2))
{
return c_Key_Null;
}
t_adc_value_idx = (Val + (c_AD_Accuracy_Value / c_AD_Key_Num) / 2) * c_AD_Key_Num / c_AD_Accuracy_Value + 1;
//返回索引值
return t_adc_value_idx;
}
/*
函数名字:ADC_Key_GetIdx
形参:无
返回:u16 按键索引值
功能:根据读取到的AD值,计算按键在表格中的索引值,并确认状态
*/
u16 ADC_Key_GetIdx(void)
{
u8 tw_adc_key_idx;
if(!g_Flag_adc_timer) //定时器标志判断
{
return c_Key_Null;
}
g_Flag_adc_timer = c_Clear; //释放定时器标志
tw_adc_key_idx = ADC_ChannelGetKeyIdx(); //获取索引值
switch(g_adc_key_status)
{
case c_ADC_Key_Status_IDLE: //AD接口空闲状态
{
if(tw_adc_key_idx == c_Key_Null) //无按键
{
return c_Key_Null;
}
else
{
g_adc_key_buffer = tw_adc_key_idx; //保存临时键值
g_adc_key_status = c_ADC_Key_Status_DB; //键值发生变化,进入消抖过程
g_adc_DBtimerCnt = c_AD_Key_DB; //设置消抖时间
}
}
break;
case c_ADC_Key_Status_DB: //消抖过程
{
if(g_adc_key_buffer != tw_adc_key_idx) //键值发生变化从新扫描
{
g_adc_key_status = c_ADC_Key_Status_IDLE;
return c_Key_Null;
}
else
{
g_adc_DBtimerCnt-- //未变化,继续消抖
if(g_adc_DBtimerCnt < 1)
{
g_adc_key_status = c_ADC_Key_Status_PressDown; //消抖时间到,进入按键确认状态
}
}
}
break;
case c_ADC_Key_Status_PressDown:
{
if(g_adc_key_buffer != tw_adc_key_idx) //获取当前按键
{
g_adc_key_status = c_ADC_Key_Status_IDLE;
return (g_adc_key_buffer | KEY_STAT_PRESS);
}
else
{
g_adc_key_status = c_ADC_Key_Status_PressUp; //保持状态,说明进入长按模式
return (g_adc_key_buffer | KEY_STAT_LPRESS_DOWN);
}
}
case c_ADC_Key_Status_PressUp:
{
if(g_adc_key_buffer != tw_adc_key_idx) //在进入长安模式下,变化,说明按键松开
{
g_adc_key_status = c_ADC_Key_Status_IDLE;
return (g_adc_key_buffer | KEY_STAT_LPRESS_UP);
}
else
{
g_adc_key_status = c_ADC_Key_Status_PressUp;
return (g_adc_key_buffer | KEY_STAT_LPRESS_CONTINUE);//按键长按状态确认
}
}
default:
{
g_adc_key_status = c_ADC_Key_Status_IDLE; //保留值,进入初始化状态
}
break;
}
return c_Key_Null;
}
/*
函数名字:ADC_Key_GetIdx
形参:无
返回:u16 按键索引值
功能:根据索引值,确认按键,并且返回按键状态
*/
u16 ADC_Key_Get(void)
{
u16 tw_key_msg;
u8 tw_keyIdx = ADC_Key_GetIdx();
if(c_Key_Null == tw_keyIdx) //无按键返回0
{
return 0;
}
else
{
tw_key_msg = T_ADC_Key_Map[tw_keyIdx &~ 0xf000]; //根据索引值,返回按键键值和按键状态
return tw_key_msg;
}
}