查看: 8440|回复: 6

halJoystickPushed()导航键程序的简要分析

[复制链接]
xingqing 发表于 2010-7-31 21:50:28 | 显示全部楼层 |阅读模式
昨天在答疑解惑中发了一个问题是关于下面这个导航键的程序,今天我好好分析了下这个程序,希望对大家有帮助,也纯属个人愚见,不知道对不对,嘿嘿。。。
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在你的开发板上实验下,看看到底是怎样一个情况,嘿嘿。。。
L.fish 发表于 2010-8-1 13:27:43 | 显示全部楼层
拜读了,分析的很仔细
不过还是有点没明白,也是我昨天一直困惑的
在你的不连发的情景最后这样写到:
    我们导航键按一次,松开之后这个时候返回的value又变成0了,在往下执行,prevValue又变成0了
是松开之后回到中心位置会再一次触发这个函数么?要么怎么才能使得重新value为0?
疑惑啊,盼解答......
ZIGBEE 发表于 2010-10-16 11:50:55 | 显示全部楼层
''关键就是看最后一行的CENTER这里,它的范围是大于0x54,如果按下中心键,那么这个值是大于0x54的,那么if (! active || adcValue < 0x54)中的adcValue < 0x54为假,那个|(或)就不用管了,有一个为假就是假了,这时候再!(非)下,那么这就是真了,这个时候就会执行value = 0;break;这两句话的。''

if (! active || adcValue < 0x54)这里是或语句判断哦  这里:!    <  的优先级是大于||的    也就是说if ((! active )|| (adcValue < 0x54))   对于或语句前的! active   要是AD转化的为0的话就是没有按键按下这个时候就是0  那么! active就是真  所以IF语句就成立了   要是有按键按下就是 !active为0了   那么这个时候才看 adcValue < 0x54这个语句哦  只要不是中间那个按键 同样adcValue < 0x54这个判断也是正确的哦
怎么你就说“有一个为假就是假了”这里不是&&      (我是不知道板子的情况的   自己做了板子正在调试中,呵呵)
suyoujiang 发表于 2010-11-9 22:03:04 | 显示全部楼层
拜读了,写得非常的好!谢谢楼主
li359700725 发表于 2010-12-3 15:51:34 | 显示全部楼层
呵呵额。。。学习一下
crazypy02 发表于 2011-9-27 15:11:28 | 显示全部楼层
回复 1# xingqing


    “关键就是看最后一行的CENTER这里,它的范围是大于0x54,如果按下中心键,那么这个值是大于0x54的,那么if (! active || adcValue < 0x54)中的adcValue < 0x54为假,那个|(或)就不用管了,有一个为假就是假了,这时候再!(非)下,那么这就是真了,这个时候就会执行value = 0;break;这两句话的。”

你这有个错误,!的优先级是最高的,所以!的是active 而不是后面或出来的值,所以在按键之后,整条判断语句还是假的,这样就没有问题了。
lizheng86312 发表于 2012-8-29 13:26:14 | 显示全部楼层
学到东西了。顶。。。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表