搜索
bottom↓
回复: 13

AVR AD键盘(模仿马潮老师的按键)一个按键具有多功能

[复制链接]

出0入0汤圆

发表于 2014-9-3 14:03:42 | 显示全部楼层 |阅读模式
来阿莫论坛有一段时间了,一直在潜水,最近一个项目用到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周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入0汤圆

发表于 2014-9-3 17:29:27 | 显示全部楼层
啥没有图纸啊?

出0入0汤圆

 楼主| 发表于 2014-9-4 08:22:52 | 显示全部楼层

这个电路百度都大把的,现在贴出来我在用的这个

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2014-9-4 08:38:07 | 显示全部楼层
mark!!!!~~~~~~~

出0入0汤圆

发表于 2014-9-4 10:08:26 | 显示全部楼层
研究研究。

出0入8汤圆

发表于 2014-9-4 13:41:49 | 显示全部楼层
原来是用AD采样来识别按键呀~

出0入0汤圆

发表于 2014-10-11 14:42:12 | 显示全部楼层
AD+状态机!

出0入0汤圆

发表于 2014-10-16 22:10:25 | 显示全部楼层
我是来拿经验的!!!!!

出0入0汤圆

发表于 2014-10-18 22:45:38 | 显示全部楼层
按键处理LCD菜单还有诸多不明白的地方。。。学习先

出0入0汤圆

发表于 2014-10-20 18:04:23 | 显示全部楼层
收着,后用。谢谢

出0入0汤圆

发表于 2016-3-18 20:12:08 | 显示全部楼层
不错,学习一下。

出0入0汤圆

发表于 2016-5-16 17:29:59 | 显示全部楼层
switch case 里还可以套if,get了

出0入4汤圆

发表于 2016-5-24 16:09:48 | 显示全部楼层
这个电路真让人醉了,想问一下,真的用过?按一次就永远是VCC了。

出0入0汤圆

发表于 2016-9-24 09:35:30 | 显示全部楼层
电路图。。。,估计楼主的意思是把R53拉下来接地。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-3-29 19:23

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表