unsigned char Trg;
unsigned char Cont;
void KeyRead( void )
{
unsigned char ReadData =GPIO_ReadInputDataBit(GPIO*,GPIO_Pin)^0xff; // 1
Trg = ReadData & (ReadData ^Cont); // 2
Cont=ReadData; // 3
}
作为一个新手来说,还是要具体其分析分析的:
我们就按键开始为高电平 ,按下为低电平,进行分析。
程序解读:
Trg(triger) 代表的是触发,Cont(continue)代表的是连续按下。
1:GPIO_ReadInputDataBit()这个函数,就是读取按键GPIO*按键引脚的输入状态。^0xff,和前面读取到的状态,取反。并将数值储存到ReadData中;
2:用来计算触发变量;
3:用来计算连续变量。
(1)没有按键的时候
端口为0xff,ReadData读端口并且取反,很显然,就是 0x00 了。
Trg = ReadData & (ReadData ^ Cont);(初始状态下,Cont也是为0的)很简单的数学计算,因为ReadData为0,则它和任何数“相与”,结果也是为0的。
Cont = ReadData; 保存Cont 其实就是等于ReadData,为0;
结果就是:
ReadData = 0;
Trg = 0;
Cont = 0;
(2) 第一次PB0按下的情况
端口数据为0xfe,ReadData读端口并且取反,很显然,就是 0x01 了。
Trg = ReadData & (ReadData ^ Cont);因为这是第一次按下,所以Cont是上次的值,应为为0。那么这个式子的值也不难算,也就是 Trg = 0x01 &(0x01^0x00) = 0x01
Cont = ReadData = 0x01;
结果就是:
ReadData = 0x01;
Trg = 0x01; (Trg只会在这个时候对应位的值为1,其它时候都为0)
Cont = 0x01;
(3) PB0按着不松(长按键)的情况
端口数据为0xfe,ReadData读端口并且取反是 0x01 了。
Trg = ReadData & (ReadData ^ Cont);因为这是连续按下,所以Cont是上次的值,应为为0x01。那么这个式子就变成了 Trg = 0x01 &(0x01^0x01) = 0x00
Cont = ReadData = 0x01;
结果就是:
ReadData = 0x01;
Trg = 0x00;
Cont = 0x01;
因为现在按键是长按着,所以MCU会每隔一段时间就会,不断的执行这个函数,那么下次执行的时候情况会是怎么样的呢?
ReadData = 0x01;这个不会变,因为按键没有松开
Trg = ReadData & (ReadData ^ Cont) = 0x01 & (0x01 ^ 0x01) =0 ,只要按键没有松开,这个Trg值永远为 0 !!!
Cont = 0x01;只要按键没有松开,这个值永远是0x01!!
(4) 按键松开的情况
端口数据为0xff,ReadData读端口并且取反是 0x00 了。
Trg = ReadData & (ReadData ^ Cont) = 0x00 & (0x00^0x01) =0x00
Cont = ReadData = 0x00;
结果就是:
ReadData = 0x00;
Trg = 0x00;
Cont = 0x00;
很显然,这个回到了初始状态,也就是没有按键按下的状态。
该代码的精华之处就在于:Trg只有在按一按键的时候才为0x01,只要按键没有放开Trg从第二次进入KeyRead()后,就一直为0x00;Cout,只要按键是按下的,这个值就一直为0x01。
理解基本就是这样了,下面说一下用到的例子:
1:原文中博主的例子,有一个是这样的,类似小时候玩过的电子表调节时间。
按一个键不放手(直到到达指定的功能在放手),从按下,到放手,这个键盘包含了两个功能——切换模式、累计加数(针对他的例子说的功能,意会即可)。其实总的意思就是,从按下,到松手,Trg开始的时候(第一下)为0x01,因为没有放手,故第二次执行KeyRead()的时候,Trg就变为了0x00;故根据原博主的if(Trg & 0x01)和if(Cont & 0x01)这个的判断,从按下,到松手,这个两个函数都会执行过去。[注:原博主的KEY_PLUS的宏定义应该为错误的,若为0x02,这个if永远都不会执行]
上述讲述的这个键盘的功能,做项目可能用得到。
2:在一个就是,我自己做东西遇到的一个问题。按键,短按一个功能,长按一个功能(两个功能不能同时到来)。显然例子1的代码满足不了我的需求。下面看我的代码:
void Key_Proc(void)
{
if(Trg&0x01) //短按
{
DelayMs(200); //200ms
if(GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_13)==1) //判断读取出的键盘输入状态是否为高电平
{
运行代码;
b=0;
}
}
if(Cout&0x01) //长按
{
b++;
if(b>20)
{
运行代码;
b=0;
}
}
}
int main()
{
KeyRead();
Key_Proc();
while(1)
{
DelayMs(10);
break;
}
}
我改的代码,除了 DelayMs(200); //200ms
if(GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_13)==1) //判断读取出的键盘输入状态是否为高电平
其他的基本相同,这段代码,主要解决长按按键,两种功能同时出现的事件。
分析:按键按一下,即按下立马松开。键盘一开始为高电平,Delay,消除键盘按下到放开的反应时间,200MS足以,然后在检测按键输入状态,若为高,说明,已经放开了,判断这是一次短按。
按下不放手,按键开始为高电平,不放手,延迟过后,检测按键依然为低,不进入if,也就屏蔽掉了这个短,按的功能,然后进行后边的if(Cout&0x01),判断为真,进入,b++,后边有10MS的延迟。b一会就会加到20,执行程序,并清除b的值。
为什么短按里面要加一个b=0呢?如果不加的话,你按键盘,若的时间为达到长按的要求,这时候b也会++,可能会出现这样的情况,连续点击键盘,按下松开,按下松开.......虽然你没有长按,但是连续的点击会使b++到20,导致触发功能。故在短按里面加一个b=0.
大致就是这个样子了,还有就是在一个程序中,一个键盘,在不同的地方有不同的功能,这个又该如何实现呢?
我想出来的就是用switch() case 语句实现。switch判断处于程序的哪一个阶段,在找对应的case去执行就好了。今天太累了,具体怎么实现我就不贴代码了。
欢迎光临 (http://www.51hei.com/bbs/) | Powered by Discuz! X3.1 |