|
昨天在答疑解惑中发了一个问题是关于下面这个导航键的程序,今天我好好分析了下这个程序,希望对大家有帮助,也纯属个人愚见,不知道对不对,嘿嘿。。。
uint8 halJoystickPushed(void)
{
uint8 value, active;
uint8 i;
static uint8 prevValue = 0;
uint16 adcValue;
// Criterion for button pushed:
// 3 times joystick active and in center position
value = 1;
for (i=0; i<3; i++) {
//获取端口的值,然后赋到active
active = MCU_IO_GET(HAL_BOARD_IO_JOY_MOVE_PORT, HAL_BOARD_IO_JOY_MOVE_PIN);
//模数转换,读取端口的电压值,然后转换为相应的十六进制数
adcValue = adcSampleSingle(ADC_REF_AVDD, ADC_9_BIT, \
HAL_BOARD_IO_JOYSTICK_ADC_CH);
// Only use 7 out of the 9 bits
adcValue = (adcValue & 0x7FC0) >> 8;
if (! active || adcValue < 0x54)//如果没有触发或者读取的电压值转后之后的值小于0x54,那么相当于没有检测到按键
{
// Joystick not active or not in center position
value = 0;
break;
}
halMcuWaitUs(3);//稍微延时下
}
if (value)
{
if (!prevValue)
{
value = prevValue = 1;
halMcuWaitMs(100);
}
else
{
value = 0;
}
}
else
{
prevValue = 0;
}
return value;
}
首先,有必要再啰嗦下prevValue,这个局部静态变量,其生命周期是在整个源程序,但是它执行的范围却是跟auto定义的变量时相同的,具体请百度去吧。。。
我觉得我跟答疑解惑中的小鱼分析的正好相反了,我觉得它加这个是为了防止连发的。
在具体分析之前,有必要说下下面这个问题:
if (! active || adcValue < 0x54)//这里的解释是Joystick not active or not in center position 我觉得前半句还对,后半句我觉得就不对了,我觉得他处在中心位置的时候,它也会执行value = 0;break;这两句的,我的根据是在halJoystickPushed()这个函数的下面那个函数(我指的是在源程序中哦),有这样一个对照表:
Meassured values from the ADC:
* -------------------------------------------
* |Direction | Voltage | Value | Range |
* -------------------------------------------
* |UP | 0.31 V | 0x0D | 0x00-0x27 |
* |DOWN | 1.16 V | 0x31 | 0x28-0x3B |
* |LEFT | 1.62 V | 0x45 | 0x3C-0x49 |
* |RIGHT | 1.81 V | 0x4D | 0x4A-0x53 |
* |CENTER | 2.12 V | 0x5A | 0x54- |
* -------------------------------------------
关键就是看最后一行的CENTER这里,它的范围是大于0x54,如果按下中心键,那么这个值是大于0x54的,那么if (! active || adcValue < 0x54)中的adcValue < 0x54为假,那个|(或)就不用管了,有一个为假就是假了,这时候再!(非)下,那么这就是真了,这个时候就会执行value = 0;break;这两句话的。
接下来,首先要看看他是在什么情况下执行halJoystickPushed()这个函数的,这个是要在选择了发送的模式的时候才会调用的,copy下源程序:
while (TRUE) {
if( halJoystickPushed() ) {
basicRfSendPacket(LIGHT_ADDR, pTxData, APP_PAYLOAD_LENGTH);
// Put MCU to sleep. It will wake up on joystick interrupt
halIntOff();
halMcuSetLowPowerMode(HAL_MCU_LPM_3); // Will turn on global
// interrupt enable
halIntOn();//打开全局中断
}
}
上面这个程序是定义在static void appSwitch()这个函数中
在上面的程序中TURE是1,所以就一直处在这个死循环中了,这时就要看halJoystickPushed() 这个函数的真或者假了,好的我们再来详细的分析这个函数执行的过程,分两种情况:
(1)先说下不是连发的情景;
没有触发导航键的时候,或者按下中间那个键的时候,会执行value = 0;break;这两句,然后执行的是if (value)以下的语句,由于value为0,所以返回的值也就是0了,没有办法回来又重新执行halJoystickPushed() 这个函数,没有按下导航键之前,我们可以很容易判断出来返回的value和prevalue都是0,这个时候我们按下导航键,
if (! active || adcValue < 0x54)//这个函数就被跳过了,直接执行的是下面的if(value)
{
// Joystick not active or not in center position
value = 0;
break;
}
if (value)
{
if (!prevValue)
{
value = prevValue = 1;
halMcuWaitMs(100);
}
else
{
value = 0;
}
}
else
{
prevValue = 0;
}
由于value为1,执行到if (!prevValue),因为先前的prevValue的值为0,所以这句也为真,执行里面的value = prevValue = 1;halMcuWaitMs(100);记住这个时候他们两个的值都变成1了,然后直接执行到了return value;返回的就是1了,这个时候就是发送你按下的键了,发送的函数basicRfSendPacket(LIGHT_ADDR, pTxData, APP_PAYLOAD_LENGTH);下面的那几个函数我就不说了,留在以后分析了,嘿嘿。。。
注意我现在说的是不连发的情况,其实这里有个延时halMcuWaitMs(100);我觉得很有必要,时间短了,就相当于连发了;我们导航键按一次,松开之后这个时候返回的value又变成0了,在往下执行,prevValue又变成0了,其实我们应该重视的是prevValue的值,看下一个连发的情况你就知道了,现在就跟我们初始的状态一样了,他们两个的值都是0,不连发的程序就到这里。
(2)连发的情况:
首先没有按下的时候我们知道value和pervValue都是0,这时我们按下up(四个方向的按键随便哪个都可以,中心键不可以)这个键,按着别动,发一次我们在不连发的情况中分析了,得出来的结果是,value为1,prevValue也为1,其实我们要关心的是后者prevValue这个值,因为他是局部静态变量,会保持它上一次的状态。当第一次的键值发送出去之后,回来又接着进来halJoystickPushed() 这里,
if (! active || adcValue < 0x54)
{
// Joystick not active or not in center position
value = 0;
break;
}
上面这个函数被跳过,直接执行下面的程序
if (value)
{
if (!prevValue)
{
value = prevValue = 1;
halMcuWaitMs(100);
}
else
{
value = 0;
}
}
else
{
prevValue = 0;
}
return value;
}
这个时候value的值为1,那么进来,注意这个时候prevValue的值为1,!prevValue之后就为0这个时候执行的是
else
{
value = 0;
}
紧接着就是返回函数了,return value;那我们就知道他现在返回的是0,但是注意这里的prevValue的值依然没有改变还是1,这就好了,不用再往下分析了,这里已经很明确了,你一直按着这个键值的时候,它除了第一次返回的是1之外,以后返回的都是0。所以我所这个是为了消除连发的。
以上都是个人愚见,由于没有开发板,所以还请outman在你的开发板上实验下,看看到底是怎样一个情况,嘿嘿。。。 |
|