|
#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, 杜汶泽)
|