搜索
bottom↓
回复: 28

我也发个AD键盘,支持长按键。欢迎找茬

[复制链接]

出0入0汤圆

发表于 2009-6-11 22:31:46 | 显示全部楼层 |阅读模式
#define F_CPU  7372800

/*

按键从左往右排列为:KEY4,KEY3,KEY2,KEY1

VCC=5V
   无按键时电压VK0=[VCC/(39K+40K)]*40K=2.53V
KEY1 按下时电压VK1=[VCC/(39K+30K)]*30K=2.17V
KEY2 按下时电压VK2=[VCC/(39K+20K)]*20K=1.69V
KEY3 按下时电压VK3=[VCC/(39K+10K)]*10K=1.02V
KEY4 按下时电压VK4=[VCC/(39K+00K)]*00K=0.00V

   无按键时采样值ADK0=[VK0/2.56]*1024=2.53/2.56]*1024=1012
KEY1 按下时采样值ADK1=[VK1/2.56]*1024=2.17/2.56]*1024=868
KEY2 按下时采样值ADK2=[VK2/2.56]*1024=1.69/2.56]*1024=676
KEY3 按下时采样值ADK3=[VK3/2.56]*1024=1.02/2.56]*1024=408
KEY4 按下时采样值ADK4=[VK4/2.56]*1024=0.00/2.56]*1024=0

  无按键取值(ADK0-48)~(ADK0+11)  = 964 ~ 1023 实测:1016
KEY1按键取值(ADK1-64)~(ADK1+48)  = 804 ~ 916        实测:873
KEY2按键取值(ADK2-76)~(ADK2+50)  = 600 ~ 726        实测:684
KEY3按键取值(ADK3-105)~(ADK3+85) = 303 ~ 493        实测:403
KEY4按键取值(ADK4-0)~(ADK4+80)  =   0 ~ 80        实测:0

*/

#define ADC_CHA  3    //模数转换通道数
#define ADC_SAV  6    //每通道保存的数据个数

#define KEYMAX0 1023    //用不到
#define KEYMIN0 964     //用不到
#define KEYMAX1 916   //按键1最大
#define KEYMIN1 804   //按键1最小
#define KEYMAX2 726   //按键2最大
#define KEYMIN2 600   //按键2最小
#define KEYMAX3 493   //按键3最大
#define KEYMIN3 303   //按键3最小
#define KEYMAX4 80   //按键4最大
#define KEYMIN4 0   //按键4最小

#define KEY_BUFF_LEN 5  //按键缓冲区长度
#define KEY0 0      //无按键代码
#define KEY1 1      //按键 1代码
#define KEY2 2      //按键 2代码
#define KEY3 3      //按键 3代码
#define KEY4 4      //按键 4代码
#define KEY_NO KEY0 //无按键代码
#define KEY_EXCEED  0XFF  //60秒内无按键代码

#define KEY_MODE  KEY4
#define KEY_SHIFT KEY3
#define KEY_DATA  KEY2
#define KEY_RESET KEY1

volatile unsigned char time_5ms;                //计时  5ms
volatile unsigned char time_200ms;               //计时  200ms
volatile unsigned char time_second;              //计时  1s
volatile unsigned char time_minute;              //计时  1m
volatile unsigned char time_hour;                //计时  1h


volatile unsigned char adc_chanel=0;         //采样通道
volatile unsigned char adc_save  =0;         //数据位置
volatile unsigned int  adc_value[ADC_CHA][ADC_SAV];  //AD转换结果


volatile unsigned char keybuff[KEY_BUFF_LEN];//按键缓冲区
volatile unsigned char keytail=0;      //缓冲区按键键数
volatile unsigned char B_keymark;            //第一次按键标志
volatile unsigned char keypress;             //当前按键
volatile unsigned char keylast;              //上一次按键
volatile unsigned char keylast2;                                       //上上次按键
volatile unsigned char keycontinue=0;        //长按键标志
volatile unsigned char getkeytime;           //按键后计时60秒

/******************************************************************
*                      定时器0:时间                             *
******************************************************************/

SIGNAL(SIG_OVERFLOW0)
{
  // T/C0 开始值
  TCNT0=256-36;
     if (++time_5ms==40){
        time_5ms=0;
        if (++time_200ms==5){
           time_200ms=0;
           if(getkeytime)getkeytime--;
           if (++time_second==60){
              time_second=0;
              if (++time_minute==60){
                 time_minute=0;
                 time_hour++;
              }//minute
           }//second
        }//200ms
     }//20ms
}     //timer0 end

void T0Init(void)
{
  // 产生中断周期 T = TCNT0 * 预分频 / 7.3728MHz
  //  = 36 * 1024 /7.3728 * e6 = 0.005秒
  // T/C0 开始值
  TCNT0=256-36;
  //OCR0=72;   
  // 预分频 ck/256 ,计数允许      
  TCCR0=_BV(CS02)|_BV(CS00);
  //T/C0 中断允许
  TIMSK=_BV(TOIE0);
}
/******************************************************************
*                      A/D 转换完成中断                          *
******************************************************************/


void ClearKeyBuff(void)
{
  keytail=0;
  B_keymark=0;            //第一次按键标志
  keypress=0;             //当前按键
  keylast=0;              //上一次按键
  keycontinue=0;          //长按键标志
  return;
}
//判断按键 ,如需要检测多键更改此函数
unsigned char encode(unsigned int k)
{
      if(k<KEYMAX4) return KEY4;
else if(k<KEYMIN3) return KEY0;
else if(k<KEYMAX3) return KEY3;
else if(k<KEYMIN2) return KEY0;
else if(k<KEYMAX2) return KEY2;
else if(k<KEYMIN1) return KEY0;
else if(k<KEYMAX1) return KEY1;
else               return KEY0;

/*
return (k<KEYMAX4)?KEY4:(k<KEYMIN3)?KEY0:
        (k<KEYMAX3)?KEY3:(k<KEYMIN2)?KEY0:
        (k<KEYMAX2)?KEY2:(k<KEYMIN1)?KEY0:
        (k<KEYMAX1)?KEY1:KEY0;

*/
}
void AdcInit(void)
{
  //控制器设置,内部2.56V 参考电压,0 通道      
  ADMUX=_BV(REFS1)|_BV(REFS0);   
  //使能ADC,中断允许,自动触发, 时钟:ck/64
  ADCSRA=_BV(ADEN)|_BV(ADIE)|_BV(ADATE)|_BV(ADPS0)|_BV(ADPS1);
  //定时器0溢出触发
  SFIOR|=_BV(ADTS2);
  //开始转换
  ADCSRA|=_BV(ADSC);

  ClearKeyBuff();
}
SIGNAL(SIG_ADC)
{
  adc_value[adc_chanel][adc_save]=(unsigned int)ADCW;
  //按键处理,只取最后一次按键  ,15ms
  if(adc_chanel==2 ) // 通道2接按键
  {
    keypress=encode(adc_value[2][adc_save]);
      if (!B_keymark)          //第一次检测到按键
      {
           if(keypress!=KEY0)
           {
              B_keymark=1;
              keycontinue=0;
              keylast=keypress;
           }
      }
      else  //B_keymark
      {
           if(keypress!=KEY0)
           {
                            if(keycontinue==3)keylast=keypress; //保存第三次检测到的按键值
                           if(keycontinue==4)keylast2=keypress;//保存第四次检测到的按键值

             //连续检测到100次为长按键 时间=100×15ms=1。5秒
             if(keycontinue>100)
             {
               if(keytail<KEY_BUFF_LEN && keylast==keypress)keybuff[keytail++]=keylast;
                           //重复间隔 时间=(100-80)×15ms=300毫秒
                           keycontinue=80;
             }
             else keycontinue++;
           }
           else
           {
             B_keymark=0;
             if(keytail<KEY_BUFF_LEN  && keycontinue>4 && keylast==keylast2
                                )
                                 keybuff[keytail++]=keylast;
           }
   
                  getkeytime=60;
      }     // end B_keymark
   
  } //按键处理结束
  adc_chanel= (adc_chanel+1)%ADC_CHA;
  if(adc_chanel==0)adc_save  = (adc_save+1)%ADC_SAV;
  /*
  外部Vref 参考电压      
  ADMUX=adc_chanel;
  */
  //内部2.56V 参考电压        
  ADMUX=(_BV(REFS1)|_BV(REFS0))+adc_chanel;

  return;
}
//读按键,直接返回
unsigned char ReadKey(void)         
{
  if(!getkeytime)return KEY_EXCEED;
  return (!keytail)? KEY0:keybuff[0];
}
//读按键,有按键返回
unsigned char ReadKeyValid(void)   
{
   unsigned char k;
   while((k=ReadKey())==KEY_NO){if(!getkeytime)return KEY_EXCEED;wdt_reset();};
   return k;
}
//取按键,直接返回
unsigned char GetKey(void)           
{
       unsigned char k;
           if(!getkeytime)return KEY_EXCEED;
       if(!keytail)return(KEY0);
       k=keybuff[0];
       memmove((void *)keybuff,(const void *)(keybuff+1),--keytail);
       return(k);

}
//取按键,有按键返回
unsigned char GetKeyValid(void)      
{
   unsigned char k;
   while((k=GetKey())==KEY_NO)
   {
     
         
         wdt_reset();//喂狗
        }
   return k;
}

阿莫论坛20周年了!感谢大家的支持与爱护!!

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出0入0汤圆

发表于 2009-6-12 07:34:06 | 显示全部楼层
不错,参考了,顶

出0入0汤圆

发表于 2009-6-12 08:12:02 | 显示全部楼层
收藏了,我帮顶!

出0入137汤圆

发表于 2009-6-12 08:16:39 | 显示全部楼层
思路以后可以参考

出0入0汤圆

发表于 2009-6-12 08:29:36 | 显示全部楼层
好,学习了

出0入0汤圆

发表于 2009-6-12 09:29:08 | 显示全部楼层
还可以,不过要是同时有几个键按下,就只能测到一个了

出0入0汤圆

 楼主| 发表于 2009-6-12 10:44:42 | 显示全部楼层
是的,电阻是串联的,

换成 8R,4R,2R,1R,并联,改变encode函数 应该可以了

出0入0汤圆

发表于 2009-6-12 13:04:31 | 显示全部楼层

出0入0汤圆

发表于 2009-6-12 13:08:39 | 显示全部楼层
标记

出0入0汤圆

发表于 2009-6-13 01:43:27 | 显示全部楼层
学习

出0入0汤圆

发表于 2009-6-13 11:23:41 | 显示全部楼层
学习,没有电路?

出0入0汤圆

发表于 2009-6-13 11:31:43 | 显示全部楼层
学习学习

出0入0汤圆

发表于 2009-6-13 11:52:00 | 显示全部楼层
学习学习再学习!

出0入0汤圆

发表于 2009-6-13 13:21:53 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-6-21 19:36:23 | 显示全部楼层
学习学习

出0入0汤圆

发表于 2009-8-26 16:23:20 | 显示全部楼层
好,学习了

出0入0汤圆

发表于 2009-8-27 11:12:26 | 显示全部楼层
mark!

出0入10汤圆

发表于 2009-8-27 11:53:52 | 显示全部楼层
不错哦

出0入0汤圆

发表于 2009-8-28 10:25:38 | 显示全部楼层
1.没有看到你按键消抖的部分
2.unsigned char GetKeyValid(void)      
{
   unsigned char k;
   while((k=GetKey())==KEY_NO)
   {
      
  
       wdt_reset();//喂狗
   }
   return k;
}
难道没有按键,就一直在这里死循环?

出0入0汤圆

 楼主| 发表于 2009-8-28 10:35:33 | 显示全部楼层
1.           B_keymark=0;                                                    //按键释放
             if(keytail<KEY_BUFF_LEN  && keycontinue>4 && keylast==keylast2  //消抖
2.      是, 如果没按键返回使用 unsigned char GetKey(void)

出0入0汤圆

发表于 2009-9-8 19:01:22 | 显示全部楼层
顶,顶!!!!!!!!!

出0入0汤圆

发表于 2013-5-7 09:41:59 | 显示全部楼层
再次学习了

出0入17汤圆

发表于 2013-10-17 09:50:14 | 显示全部楼层
mark 学习一下。
这种AD按键的电路,其可靠性与电源,温度,外部干扰都有很大关系。

出0入0汤圆

发表于 2013-10-18 16:29:34 | 显示全部楼层
这个很好,比较实用,在IO吃紧的时候

出0入0汤圆

发表于 2013-10-19 06:32:40 来自手机 | 显示全部楼层
谢谢分享

出0入0汤圆

发表于 2013-10-19 08:30:44 | 显示全部楼层
参考

出0入0汤圆

发表于 2013-10-19 09:49:53 | 显示全部楼层
好,学习了                                                         

出0入0汤圆

发表于 2013-10-19 11:13:45 | 显示全部楼层
收藏了!

出0入95汤圆

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

本版积分规则

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

GMT+8, 2024-7-24 00:31

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

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