|
来阿莫论坛有一段时间了,一直在潜水,最近一个项目用到AD按键,于是根据马潮老师的程序改了个程序。大牛不喜勿喷。。。
这段程序共识别4个按键,4个按键短按,按键1具有长按、双击、3击,按键2,按键3实现连加。AD按键唯一的好处就是连线少,时间长了会出现误触等乱七八糟的情况。
需要注意的是:1、按键按下前3个值是不稳的,在AD采样时需要扔掉前3个值。
2、某个按键对应的AD值要留出一定的范围,因为AD键盘的电阻是有误差的。
3、Read_adc_value(2)是采集AD值的程序,这个用CVAVR能生成类似的程序。
#define KEY_AD 180 //AD按键门槛值
#define N_key 0//无键
#define S_key 1//短按
#define Key1_S_key 2//按键1短按
#define Key2_S_key 3//按键2短按
#define Key3_S_key 4//按键3短按
#define Key4_S_key 5//按键4短按
#define Key1_L_key 6//按键1长按
#define Key2_L_key 7//按键2长按
#define Key3_L_key 8//按键3长按
#define Key1_D_key 9//按键1双击
#define Key1_DD_key 10//按键1 3击
#define Key_L_Timer 50//长按1S的时间 20*50
#define Key_TimerOut 10//单击超时时间 200ms 20*15
volatile unsigned int key_AD_value=0;
volatile unsigned char ALL_Key_state=N_key;
unsigned char Key_driver(void)
{
static unsigned char key_state=0, key_timer=0;
static unsigned int Key_AD_buf[4]={0,0,0,0};//存取按键AD值
unsigned char key_return=N_key;
Key_AD_buf[key_state]=Read_adc_value(2);
switch (key_state)
{
case 0:
if(Key_AD_buf[0]>KEY_AD) key_state=1;//检测到按键被按下
break;
case 1://比对上一次AD值跟本次检测到的AD值是否差太大 若差别大则认为是一次抖动
if(Key_AD_buf[0]>Key_AD_buf[1])
{
if((Key_AD_buf[0]-Key_AD_buf[1])<=10)
{
key_AD_value = (Key_AD_buf[0]+Key_AD_buf[1])/2;
key_state=2;
}
else key_state=0;
}
else if(Key_AD_buf[1]>Key_AD_buf[0])
{
if((Key_AD_buf[1]-Key_AD_buf[0])<=10)
{
key_AD_value = (Key_AD_buf[0]+Key_AD_buf[1])/2;
key_state=2;
}
else key_state=0;
}
else
{
key_AD_value = Key_AD_buf[1];
key_state=2;
}
key_timer=0;
break;
case 2:
if(Key_AD_buf[2]<KEY_AD)
{
key_return = S_key;//此时按键松开,说明是是一次短按
key_state=0;
}
else if(++key_timer>=Key_L_Timer)//20ms执行一次
{
key_timer=0;
if((key_AD_value>=190)&&(key_AD_value<400))key_return = Key1_L_key;//按键大于1S,说明是是一次长按 只识别KEY1长按
else key_return=N_key;
key_state=3;
}
break;
case 3://此处检测长按按键 用以长按实现连加或连减
if((key_AD_value>=500)&&(key_AD_value<650))key_return =Key2_L_key;
else if((key_AD_value>=750)&&(key_AD_value<850))key_return =Key3_L_key;
if(Key_AD_buf[3]<KEY_AD) key_state=0;//按键已释放
break;
}
return key_return;
}
unsigned char key_read(void)
{
static unsigned char key_m=0,key_timer_1=0;
unsigned char key_return=N_key,key_temp=0;
static unsigned char key_cnt=0;
key_temp = Key_driver();
switch (key_m)
{
case 0:
if(key_temp == S_key)
{
key_cnt=0;//按键次数清0
key_timer_1=0;//第一次单击,不返回,到下个状态去判断
key_m = 1;
}
else key_return = key_temp;
break;
case 1:
if(key_temp == S_key)
{
if(++key_cnt==3)
{
key_cnt=0;
if((key_AD_value>=190)&&(key_AD_value<400))key_return = Key1_DD_key;//只识别KEY1按键3击
key_m = 0;
}
key_timer_1=0;
}
else
{
if(++key_timer_1>=Key_TimerOut)//按键超时若超过200ms按键未响应被认为是一次短按 我认为200ms比较好
{
if(key_cnt==1)
{
key_cnt = 0;
if((key_AD_value>=190)&&(key_AD_value<400))key_return = Key1_D_key;//只识别KEY1长按按键双击
}
else
{//判断是哪个按键被按下
if((key_AD_value>=190)&&(key_AD_value<400))key_return =Key1_S_key;
else if((key_AD_value>=500)&&(key_AD_value<650))key_return =Key2_S_key;
else if((key_AD_value>=750)&&(key_AD_value<850))key_return =Key3_S_key;
else if((key_AD_value>=900)&&(key_AD_value<1000))key_return =Key4_S_key;
}
key_m = 0;
}
}
break;
}
return key_return;
}
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
// Place your code here
TCNT0 = 0x83;
key_Timer20ms++;
}
在主程序里程序如下:
void main(void)
{
while(1)
{
if(key_Timer20ms>=5)//20ms 扫描一次
{
key_Timer20ms=0;
ALL_Key_state=key_read();
}
//在需要按键的地方 读取ALL_Key_state。如下:
if(ALL_Key_state == Key2_S_key)
{
ALL_Key_state=N_key; //这里需要清0,否则会多次进入按键程序
//...
}
} |
阿莫论坛20周年了!感谢大家的支持与爱护!!
一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。
|