最近写了一个矩阵键盘消抖的程序,主要是功能在于实现不中断主频消抖,记录一下。
2021.2.11
之前改了一下,松开判断还是挺重要的,主要能提升用户的按键体验,被干扰触发可能是没什么问题了,但是松开时按键会大幅抖动一下,导致按两下出现。于是设置了两个值,一个按下时间和一个松开时间。也是改到后面,脑中愈发觉得程序正在模拟一个电容按键,不同于的是前后可调。
结构
(1.0)结构图
(1.1)结构图
代码
键盘按下
uchar KeyTemp_Last=0,KeyN_Last=0;
//键盘方案 2021.1.27
//判断占空比,如果接通计数+,断开计数-,再设置两个通断限值
//那么定时器的计数器需要能够加和减
//抬起时间
#define keyUpTime_NOM -10
#define keyUpTime_RE -20
#define keyUpTime (REISwitch?keyUpTime_NOM:keyUpTime_RE)
//按下时间
#define keyDownTime_NOM 8
#define keyDownTime_RE 15
#define keyDownTime (REISwitch?keyDownTime_NOM:keyDownTime_RE)
uchar keydelay_Nstop(uchar temp)//按键不中断滤波
{
static uchar keyUpWait=0;//等待抬起
uchar temp_return=CheckKeyState;//状态和键值
qie[2]=100;//!!!响应误差(0.01s)
if(shi[2]>0)
{
if((KeyTemp_Last|temp)!=KeyTemp_Last)//实时判断,对比数据,用或来消除杂波
{
sub[2]=1;//定时器减法
if(keyUpWait)//按键已触发
{
if(mm[2]<=keyUpTime)//2.判断断开阈值(-)
KeyTemp_Last=mm[2]=shi[2]=0;
}
else if(mm[2]<=0)//1.5 按键未触发,判断接通阈值(-)
KeyTemp_Last=mm[2]=shi[2]=0;
}
else
{
sub[2]=0;//定时器加法
if(mm[2]>=shi[2])//1.判断接通阈值(+)
{
temp_return=KeyTemp_Last;
keyUpWait=1;
mm[2]=shi[2];
}
}
}
else
{
keyUpWait=0;//等待抬起
if(temp!=KeyDT)
{
if((temp|0xEF)==0xEF)KeyTemp_Last=0x0F;//获取键值,一行5个
if((temp|0xF7)==0xF7)KeyTemp_Last=0x17;
if((temp|0xFB)==0xFB)KeyTemp_Last=0x1B;
if((temp|0xFD)==0xFD)KeyTemp_Last=0x1D;
if((temp|0xFE)==0xFE)KeyTemp_Last=0x1E;
if(KeyTemp_Last)
{
shi[2]=keyDownTime+(mo>0)*8;//!!!这里设置时间 0.01S
}
}
else
temp_return=GetKeyState;//键盘选择状态
}
return temp_return;
}
主体
uchar code T_KeyValue[]={0,5,4,9,8,7,6,1,2,3,0,10,11,12,14,13,15,16,17,18,19};
uchar code T_KeyTemp[]={0,5,4,3,3,5,6,7,2,9,10,11,12,13,14,15,1};
void KeyScan_Nstop()//按键主程序
{
static uchar n=0,key=0;
uchar KeyValue;
KeyValue=P2&KeyDT;//获取IO
KeyValue=keydelay_Nstop(KeyValue);//按键判断
if(KeyValue==GetKeyState)//键盘选择,滞后获取
{
if((++n)==4)n=0;
KeyLineOne=(n!=0);
KeyLineTwo=(n!=1);
KeyLineThr=(n!=2);
KeyLineFou=(n!=3);
}
if(KeyValue<=GotKeyState)//获得键值
{
if(keydown==0)
{
key=T_KeyValue[T_KeyTemp[(~KeyTemp_Last)&KeyDT]+n*5];//转换键值
Form_Key(key);
keydown=1;
}
}
else//没有键值
key=keydown=0;
}
定时器
//***************定时器****************************
void tm0_isr()interrupt 1 //定时器0 100T=1S
{
uchar i;
TL0 = 0x00;
TH0 = 0xB8;
for(i=0;i<10;i++)
{
if(shi[i]>0)
{
if(sub[i]==0)//多数判断0,可以少一个jump
mm[i]++;
else
mm[i]--;
if(qie[i]>0) //与主程序响应误差,用倒计时模式,超过则重置检测计数
qie[i]--;
else
mm[i]=0;//shi[i]=
}
}
}