先不多说,直接上代码,功能说明啥的都在程序注释里
说明:
/*********************************************************************
* 文件名称: tirgkey.c
* 功能说明: 触发器键盘识别驱动程序,可区分短按与长按
* 版本日期: 2011年12月28日
* 修改记录:
* 声 明:1、该部分程序参照二姨网友XIANSir的程序,具体请见:https://bbs.21ic.com/icview-229561-2-1.html
2、在保持原功能不变的情况下,区分短按与长按,不再买一赠一
***********************************************************************/
KeyScan()/
/**************************************************************************
* 函数名称: KeyScan()
* 功能说明: 扫描按键,并给出按键值,存储在KeyCode中
* 输 入: 无
* 输 出: 无
* 注意事项: 1、按键处理与按键的硬件连接息息相关,本函数当前能够正确处理的按键硬件连接为:
* KEY_1<->GPB.15 KEY_2<->GPB.14
*
****************************************************************************/
void KeyScan(void)
{
uint32_t stat = 0x00; //按键的状态值
static uint32_t trig = 0; //按键触发,按键的下降沿将trig置1,以表示有按键被按下;在下一个检测周期(下一次本函数被调用)tirg会被本函数自动清零
static uint32_t press = 0; //保存stat的状态,表示按键持续按下
static uint32_t count = 0; //记录press值持续时间,以检测长按键
static uint32_t save = 0; //记录按键按下时的按键值,只有短按键抬起时才用到,长按后抬起也被清除
stat = (DrvGPIO_GetPortBits(E_GPB) & 0xC000) ^ 0xC000; //按键的状态值,实际是GPB15和GPB14引脚电平逻辑的按位取反值
if((trig != 0x00) && (stat == press)) //trig置位表示发生了一次按键动作,
{ //stat == press这个判断可以起到“消抖”作用
save=stat; //有按键按下, 暂时保存按键值
}
trig = stat&(stat^press);//实际的核心代码,stat^press保证只有在按键变化时(有键被按下或释放),trig才有机会为1;而stat&部分则保证只有按键被按下才会置位tirg,而按键被释放则不会置位tirg
press = stat; //保存stat的状态,stat与press协同工作构建了一个“软件触发器”
if((press==0)&&(save!=0)) //按键按下且抬起了,判断为短按
{
switch(save) //判断是哪一个按键被按下了
{
case 0x4000:
KeyCode = KEY_1;
break;
case 0x8000:
KeyCode = KEY_2;
break;
default: //多个按键同时被按下的情况当前代码不支持,但如果有需要加入复合键的支持非常容易
KeyCode = NOKEY;
break;
}
save=0; //判断完按键值,清除按键值
}
if(press != 0x00)
{
count++;
if(count == 100) //按键被持续按住长达10ms*100=1s,表示有按键被长按
{
save=0; //清空短按值,防止长按后抬起执行短按功能
count = 50; //将计数器置为50,目的是长按后每隔(100-50)*10ms,连续执行长按实现类似连加的功能。若想仅执行一次长按可将count置大于100的数,如KEY2
switch(stat) //判断是哪一个按键被长按了
{
case 0x4000:
KeyCode = KEY_1L;
break;
case 0x8000:
KeyCode = KEY_2L;
count=101; //将count置大于100的值,屏蔽长按KEY2时连续的执行KEY2功能,
break;
default:
KeyCode = NOKEY; //多个按键同时被按下的情况当前代码不支持,但如果有需要加入复合键的支持非常容易
break;
}
}
if(count>200)
count=101;
}
else
{
count=0;
}
}
main()
/***********************************************************************
* 函数名称: main()
* 功能说明: 根据按键值点亮相应LED。
短按K1:LED1亮/灭;长按K1:LED2亮/灭,若持续按下K1则LED2闪烁;
短按K2:LED3亮/灭;长按K2:LED4亮/灭,若持续按下K2则LED4不再变化,直到抬起后再次长按。
* 输 入: 无
* 输 出: 无
************************************************************************/
int main(void)
{
UNLOCKREG();
SYSCLK->PWRCON.XTL12M_EN = 1;// SYSCLK =>12Mhz
LOCKREG();
DrvGPIO_Open( E_GPA, 2, E_IO_OUTPUT );//设置GPA.2~GPA.5为输出模式
DrvGPIO_Open( E_GPA, 3, E_IO_OUTPUT );
DrvGPIO_Open( E_GPA, 4, E_IO_OUTPUT );
DrvGPIO_Open( E_GPA, 5, E_IO_OUTPUT );
DrvGPIO_ClrBit( E_GPA,2); //做测试LED用
DrvGPIO_SetBit( E_GPA,4);
KeyInit(); //初始化按键相关的端口和定时器。
//PS:开始调试时忘加该函数,导致反复的调试按键都没反应。几天后才通过断点调试发现定时器T0都没有运行。切记切记~~~
while(1)
{
if(KeyCode!= NOKEY)
{
switch (KeyCode)
{
case KEY_1: //短按KEY1,LED1状态取反
if(DrvGPIO_GetBit(E_GPA,2))
{
DrvGPIO_ClrBit(E_GPA,2);
}
else
DrvGPIO_SetBit(E_GPA,2);
KeyCode=0;
break;
case KEY_1L: //长按KEY1,LED2状态取反,若一直按着不放,LED2会闪烁
if(DrvGPIO_GetBit(E_GPA,3))
{
DrvGPIO_ClrBit(E_GPA,3);
}
else
DrvGPIO_SetBit(E_GPA,3);
KeyCode=0;
break;
case KEY_2: //短按KEY2,LED3状态取反
if(DrvGPIO_GetBit(E_GPA,4))
{
DrvGPIO_ClrBit(E_GPA,4);
}
else
DrvGPIO_SetBit(E_GPA,4);
KeyCode=0;
break;
case KEY_2L: //长按KEY2,LED4状态取反,若一直按着不放,就不会再执行了,具体原因见KeyScan()
{
if(DrvGPIO_GetBit(E_GPA,5))
{
DrvGPIO_ClrBit(E_GPA,5);
}
else
DrvGPIO_SetBit(E_GPA,5);
KeyCode=0;
break;
}
default:break;
}
}
}
}
工程文件包:
01_trigkey_zxcscm.rar
(867.93 KB)
作为第四批的园地M0幸运者,由于各种原因现在才开始真正意义上的第一帖笔记,真的很惭愧,对不起自己当初的热情,更对不起菜农大叔的辛苦。俺从园地的第一届助学活动就开始关注,目睹了菜农大叔的各种辛苦,大叔的真诚、热心以及助学活动的信心大家有目共睹,心知肚明的,但是总是有各种怀疑和议论声,我就不明白为什么不能多些理解和支持呢。大叔如此热情的进行这个义务的助学活动,不管是精神上、物质上还是时间上都付出那么多,为的是什么?“挽救失足青年”仅此而已,我们作为学子能做的就是把握机会,好好学习,认真记笔记,我想就是对菜农最大的支持了。
无论如何,从现在开始俺将真正的学习M0,学习嵌入式,争取从51菜鸟转成M0菜农,能在园地里耕作,收获属于自己的果实。
声明一点,俺的基础薄,所以笔记不会有多少含金量的,但俺会一直向各位网友学习,一步一个脚印的学扎实了,同时欢迎各位来拍砖! |