此按键程序也是自己在一个网站上看到的,发现对小白来说还是比较好理解的,废话后面再说,先上代码
#define KEY_FILTER_TIME ?25 ? ? //按键滤波的“稳定时间”25ms #define KEY_INTERVAL_TIME ?250 ?//连续两次单击之间的最大有效时间250ms #define KEY_LONG_TIME ?500 ? ? ?//按键的“长按”兼“滤波”的“稳定时间”500ms
volatile unsigned char vGu8CombinationKeySec=0; ?//组合按键的触发序号
volatile unsigned char vGu8_SingleKey1Sec=0; ?//单击按键1的触发序号 volatile unsigned char vGu8_DoubleKey1Sec=0; ?//双击按键1的触发序号
volatile unsigned char vGu8_SingleKey2Sec=0; ?//单击按键2的触发序号 volatile unsigned char vGu8_DoubleKey2Sec=0; ?//双击按键2的触发序号
void KeyScan(void) ?//此函数放在定时中断里每1ms扫描一次 { ? ?static unsigned char Su8CombinationKeyLock; ?//组合按键的自锁 ? ?static unsigned int ?Su16CombinationKeyCnt; ?//组合按键的计时器 ? ? /****************************************************************/ ?? ? ?static unsigned char Su8_Key1Lock1; ? ? ? ? ? ?static unsigned int ?Su16_Key1Cnt1; ? ? ?static unsigned char Su8_Key1ShortFlag = 0; ?//按键“短按”触发的标志 ? ? ? ? ?static unsigned char Su8_DoubleKey1Lock1; ? ? ? ? ? ?static unsigned int ?Su16_DoubleKey1Cnt1;? ? ?static unsigned char Su8_Key1TouchCnt1; ? ? ? //1号按键的次数记录 ? ?static unsigned int ?Su16_Key1IntervalCnt1; ? //1号按键的间隔时间计数器 /********************************************************************/ ? ?static unsigned char Su8_Key2Lock2; ? ? ? ? ? ?static unsigned int ?Su16_Key2Cnt2; ? ? ?static unsigned char Su8_Key2ShortFlag = 0; ?//按键“短按”触发的标志 ? ? ? ? ?static unsigned char Su8_DoubleKey2Lock2; ? ? ? ? ? ?static unsigned int ?Su16_DoubleKey2Cnt2;? ? ?static unsigned char Su8_Key2TouchCnt2; ? ? ? //1号按键的次数记录 ? ?static unsigned int ?Su16_Key2IntervalCnt2; ? //1号按键的间隔时间计数器 ?/***********************************************************************/
? ?//K1按键与K2按键的组合触发 ? ?if(0!=key1||0!=key2)//两个按键只要有一个按键没有按下,处于“非组合按键”的状态。 ? ?{ ? ? ? Su8CombinationKeyLock=0; //组合按键解锁 ? ? ? Su16CombinationKeyCnt=0; ?//组合按键去抖动延时计数器清零。 ? ? ? ? ?} ? ?else if(0==Su8CombinationKeyLock)//两个按键被同时按下。 ? ?{ ? ? ? Su16CombinationKeyCnt++; //累加定时中断次数 ? ? ? if(Su16CombinationKeyCnt>=KEY_FILTER_TIME) //滤波的“稳定时间”KEY_FILTER_TIME。 ? ? ? { ? ? ? ? ?Su8CombinationKeyLock=1; ?//组合按键的自锁,避免一直触发 ? ? ? ? ?vGu8CombinationKeySec=1; ? //触发K1与K2的组合键操作 ? ? ? } ? ?} /******************************************************************/ //按键1 ? if(0 != key1)?? ??? ??? ??? ?//1按键没有按下,及时清零一些标志。 ? ?{ ? ? ? Su8_Key1Lock1=0; //按键解锁 ? ? ? Su16_Key1Cnt1=0; ?//去抖动延时计数器清零 ? ? ?? ? ? ? Su8_DoubleKey1Lock1=0; ? ? ? Su16_DoubleKey1Cnt1=0; ?//长短按 ? ? ? ? ? if(1==Su8_Key1ShortFlag) ?//松手的时候,如果“短按”标志有效就触发一次“短按” ? ? ? { ?? ??? ?Su8_Key1ShortFlag=0; ? ? //先清零“短按”标志避免一直触发。 ?? ??? ?vGu8_SingleKey1Sec=1; ? ?//触发“短按” ?? ? ?}? //双击?? ? ? ?? ? ?if(Su8_Key1TouchCnt1>=1) //之前已经有按键触发过一次,再来一次就构成双击 ? ? ? ?{ ? ? ? ? ? ? Su16_Key1IntervalCnt1++; //按键间隔的时间计数器累加 ? ? ? ? ? ?if(Su16_Key1IntervalCnt1>=KEY_INTERVAL_TIME) //达到最大允许的间隔时间 ? ? ? ? ? ?{ ??? ??? ??? ??? ?Su16_Key1IntervalCnt1 = 0; //时间计数器清零 ? ? ? ? ? ? ? ? Su8_Key1TouchCnt1 = 0; ? ? //清零按键的按下的次数 ? ? ? ? ? ?} ? ? ? ?} ? ?} ?? ? //双击 ? ? ? else if(0==Su8_DoubleKey1Lock1)//有按键按下,且是第一次被按下。 ? ?{ ? ? ? Su16_DoubleKey1Cnt1++; //累加定时中断次数 ? ? ? if(Su16_DoubleKey1Cnt1>=KEY_FILTER_TIME) //滤波的“稳定时间”KEY_FILTER_TIME,长度是25ms。 ? ? ? { ? ? ? ? ?Su8_DoubleKey1Lock1=1; ?//按键的自锁,避免一直触发 ? ? ? ? ?Su16_DoubleKey1Cnt1=0; ? //按键有效间隔的时间计数器清零 ? ? ? ? ?Su8_Key1TouchCnt1++; ? ? ? //记录当前单击的次数 ? ? ? ? ?if(Su8_Key1TouchCnt1>=2) ?//连续按了两次以上 ? ? ? ? ?{ ? ? ? ? ? ? ? Su8_Key1TouchCnt1=0; ? ?//统计按键次数清零 ?? ??? ??? ? ?vGu8_DoubleKey1Sec=1; ? //双击任务 ? ? ? ? ?} ? ? ? } ? ?} ? //长短按 ?? ? ?? ?else if(0==Su8_Key1Lock1)//按键1被按下 ? ?{ ? ? ? Su16_Key1Cnt1++; //累加定时中断次数
? ? ? if(Su16_Key1Cnt1>=KEY_FILTER_TIME) //“短按”兼“滤波”的“稳定时间”KEY_SHORT_TIME ? ? ? { ? ? ? ? ? ? Su8_Key1ShortFlag=1; ? ?//“短按”标志有效,待松手时触发。 ? ? ? }
? ? ? if(Su16_Key1Cnt1>=KEY_LONG_TIME) //“长按”兼“滤波”的“稳定时间”KEY_LONG_TIME ? ? ? { ? ? ? ? ? ? Su8_Key1Lock1=1; ? ? ?//此时“长按”触发才“自锁” ?? ??? ??? ?Su8_Key1ShortFlag=0; ?//既然此时“长按”有效,那么就要废除潜在的“短按”。 ? ? ? ? ? ? vGu8_SingleKey1Sec=2; //触发“长按” ? ? ? } ? ?} ? /***************************************************************/ ?? ? /******************************************************************/ //按键2 ? if(0 != key2)?? ??? ??? ??? ?//1按键没有按下,及时清零一些标志。 ? ?{ ? ? ? Su8_Key2Lock2=0; //按键解锁 ? ? ? Su16_Key2Cnt2=0; ?//去抖动延时计数器清零 ? ? ?? ? ? ? Su8_DoubleKey2Lock2=0; ? ? ? Su16_DoubleKey2Cnt2=0; ?//长短按 ? ? ? ? ? if(1==Su8_Key2ShortFlag) ?//松手的时候,如果“短按”标志有效就触发一次“短按” ? ? ? { ?? ??? ?Su8_Key2ShortFlag=0; ? ? //先清零“短按”标志避免一直触发。 ?? ??? ?vGu8_SingleKey2Sec=1; ? ?//触发“短按” ?? ? ?}? //双击?? ? ? ?? ? ?if(Su8_Key2TouchCnt2>=1) //之前已经有按键触发过一次,再来一次就构成双击 ? ? ? ?{ ? ? ? ? ? ? Su16_Key2IntervalCnt2++; //按键间隔的时间计数器累加 ? ? ? ? ? ?if(Su16_Key2IntervalCnt2>=KEY_INTERVAL_TIME) //达到最大允许的间隔时间 ? ? ? ? ? ?{ ??? ??? ??? ??? ?Su16_Key2IntervalCnt2 = 0; //时间计数器清零 ? ? ? ? ? ? ? ? Su8_Key2TouchCnt2 = 0; ? ? //清零按键的按下的次数 ? ? ? ? ? ?} ? ? ? ?} ? ?} ?? ? //双击 ? ? ? else if(0==Su8_DoubleKey2Lock2)//有按键按下,且是第一次被按下。 ? ?{ ? ? ? Su16_DoubleKey2Cnt2++; //累加定时中断次数 ? ? ? if(Su16_DoubleKey2Cnt2>=KEY_FILTER_TIME) //滤波的“稳定时间”KEY_FILTER_TIME,长度是25ms。 ? ? ? { ? ? ? ? ?Su8_DoubleKey2Lock2=1; ?//按键的自锁,避免一直触发 ? ? ? ? ?Su16_DoubleKey2Cnt2=0; ? //按键有效间隔的时间计数器清零 ? ? ? ? ?Su8_Key2TouchCnt2++; ? ? ? //记录当前单击的次数 ? ? ? ? ?if(Su8_Key2TouchCnt2>=2) ?//连续按了两次以上 ? ? ? ? ?{ ? ? ? ? ? ? ? Su8_Key2TouchCnt2=0; ? ?//统计按键次数清零 ?? ??? ??? ? ?vGu8_DoubleKey2Sec=1; ? //双击任务 ? ? ? ? ?} ? ? ? } ? ?} ? //长短按 ?? ? ?? ?else if(0==Su8_Key2Lock2)//按键1被按下 ? ?{ ? ? ? Su16_Key2Cnt2++; //累加定时中断次数
? ? ? if(Su16_Key2Cnt2>=KEY_FILTER_TIME) //“短按”兼“滤波”的“稳定时间”KEY_SHORT_TIME ? ? ? { ? ? ? ? ? ? Su8_Key2ShortFlag=1; ? ?//“短按”标志有效,待松手时触发。 ? ? ? }
? ? ? if(Su16_Key2Cnt2>=KEY_LONG_TIME) //“长按”兼“滤波”的“稳定时间”KEY_LONG_TIME ? ? ? { ? ? ? ? ? ? Su8_Key2Lock2=1; ? ? ?//此时“长按”触发才“自锁” ?? ??? ??? ?Su8_Key2ShortFlag=0; ?//既然此时“长按”有效,那么就要废除潜在的“短按”。 ? ? ? ? ? ? vGu8_SingleKey2Sec=2; //触发“长按” ? ? ? } ? ?} ? /***************************************************************/
}
void CombinationKeyTask(void) ? ?//组合按键任务函数,放在主函数内 { ?? ?if(0==vGu8CombinationKeySec) ?? ?{ ?? ??? ?return; //按键的触发序号是0意味着无按键触发,直接退出当前函数,不执行此函数下面的代码 ?? ?}
?? ?switch(vGu8CombinationKeySec) //根据不同的按键触发序号执行对应的代码 ?? ?{ ?? ? ? case 1:? ? ?? ??? ??? ??? ?vGu8CombinationKeySec=0; ?//响应按键服务处理程序后,按键编号必须清零,避免一致触发 ?? ??? ??? ?break; ?? ?}
}
void SingleKey1Task(void) ? ?//按键1任务函数 { ?? ?if(0==vGu8_SingleKey1Sec) ?? ?{ ?? ??? ?return; ?? ??? ??? ? ?? ?} ?? ? ?? ?switch(vGu8_SingleKey1Sec) ?? ??? ??? ??? ?//1为按键1短按,2为按键1长按 ?? ?{ ?? ? ? case 1: ? ?? ? ? ?? ??? ??? ?vGu8_SingleKey1Sec=0; ?? ? ? ?? ??? ?break; ?? ? ? case 2:?? ?? ? ? ?? ??? ??? ?vGu8_SingleKey1Sec=0; ?? ? ? ?? ??? ?break;?? ? ?? ?} }
void DoubleKey1Task(void) ? ?//按键1双击任务函数 { ?? ?if(0==vGu8_DoubleKey1Sec) ?? ?{ ?? ??? ?return; ?? ??? ??? ? ?? ?} ?? ? ?? ?switch(vGu8_DoubleKey1Sec) ?? ??? ??? ??? ? ?? ?{ ?? ? ? case 1: ? ?? ? ? ?? ??? ??? ?vGu8_DoubleKey1Sec=0; ?? ? ? ?? ??? ?break; ?? ?} }
void SingleKey2Task(void) ? ?//按键2任务函数 { ?? ?if(0==vGu8_SingleKey2Sec) ?? ?{ ?? ??? ?return; ?? ??? ??? ? ?? ?} ?? ? ?? ?switch(vGu8_SingleKey2Sec) ?? ??? ??? ??? ?//1为按键2短按,2为按键2长按 ?? ?{ ?? ? ? case 1: ? ?? ? ? ?? ??? ??? ?vGu8_SingleKey2Sec=0; ?? ? ? ?? ??? ?break; ?? ? ? case 2:? ?? ? ? ?? ??? ??? ?vGu8_SingleKey2Sec=0; ?? ? ? ?? ??? ?break;?? ? ?? ?} }
void DoubleKey2Task(void) ? ?//按键2双击任务函数 { ?? ?if(0==vGu8_DoubleKey2Sec) ?? ?{ ?? ??? ?return; ?? ??? ??? ? ?? ?} ?? ? ?? ?switch(vGu8_DoubleKey2Sec) ?? ??? ??? ??? ? ?? ?{ ?? ? ? case 1: ? ?? ? ? ?? ??? ??? ?vGu8_DoubleKey2Sec=0; ?? ? ? ?? ??? ?break; ?? ?} }
keyscan()函数放定时器中断服务函数里(我设置的定时器是1ms), 其他的放在主循环即可。
文章记录自己学习单片机的过程,记录一些自己所见识到的比较好用的程序,也算是一个总结,方便今后遇到相同的问题可以快速解决,今年3月中旬开始接触C语言,稀里糊涂学了一个月,然后开始学习51单片机,接着6月份正式去一个小公司上班,自己还是小小小白,如有错误的地方还请多多指点,感谢!
程序比较臃肿,如果四个,八个按键相同的功能时候按照这样写那也太多了,其实两个按键很多功能都重复的,该怎样优化呢,搞完之后再想这个问题,想法是有,但是用代码实现以目前自己的水平还是很难实现的。
第一次写这样的文章,谢谢谢谢!!
|