zoukankan      html  css  js  c++  java
  • ZigBee开发(14)--组网实验按键

    通过节点 1 的按键 S1 中断配置,检测按键的按下情况。整个过程在协议栈 Z-STACK SampleApp.eww 上完成。

    协议栈已经自带了按键的驱动和使用函数。所以将按键改到任 IO 口也不是问题了。 

    首先我们需要做的是花精力将官方自带的按键 IO 改到我的板子的 IO口上。 官方电路的按键 S1 连接的是 P0.1 引脚,我的按键 S1连接的是 P0.1 口,按键 S2 连接的是 P2.0 口。

    首先就是要了解协议栈中按键的检测与按键事件的传递过程;

    按键流程分析 :
      在上一节工程的基础上我们来进行分析修改,(上一节的工程链接为:https://pan.baidu.com/s/10eRDKbndrYMTkm-sgpGd_w

    打开 SampleApp.eww 工程,在 ZMain.c main 主函数中跟按键相关的有:

    HalDriverInit();
    InitBoard( OB_READY );

    进入 HalDriverInit()中的 HalKeyInit()

    void HalKeyInit( void )
    {
      /* Initialize previous key to 0 */
      halKeySavedKeys = 0;
    
      HAL_KEY_SW_6_SEL &= ~(HAL_KEY_SW_6_BIT);    /* Set pin function to GPIO */
      HAL_KEY_SW_6_DIR &= ~(HAL_KEY_SW_6_BIT);    /* Set pin direction to Input */
    
      HAL_KEY_JOY_MOVE_SEL &= ~(HAL_KEY_JOY_MOVE_BIT); /* Set pin function to GPIO */
      HAL_KEY_JOY_MOVE_DIR &= ~(HAL_KEY_JOY_MOVE_BIT); /* Set pin direction to Input */
    
    
      /* Initialize callback function */
      pHalKeyProcessFunction  = NULL;
    
      /* Start with key is not configured */
      HalKeyConfigured = FALSE;
    }

    这里主要是初始化按键相关的引脚, HAL_KEY_SW_6 就是对应 P01,而HAL_KEY_JOY 就是 TI 子上的 J-STICK 摇杆,

    我们的板子上大部分都没有,直接注释或删掉。

     接着分析 InitBoard( OB_READY )

    void InitBoard( uint8 level )
    {
      if ( level == OB_COLD )
      {
        // IAR does not zero-out this byte below the XSTACK.
        *(uint8 *)0x0 = 0;
        // Interrupts off
        osal_int_disable( INTS_ALL );
        // Check for Brown-Out reset
        ChkReset();
      }
      else  // !OB_COLD
      {
        /* Initialize Key stuff */
        HalKeyConfig(HAL_KEY_INTERRUPT_DISABLE, OnBoard_KeyCallback);
      }
    }

    对按键的具体配置(重点): 配置按键的检测方式和按键的回调函数

    HalKeyConfig(HAL_KEY_INTERRUPT_DISABLE,OnBoard_KeyCallback); 

    进入到此函数中,先配置非中断检测的,先看代码:

    void HalKeyConfig (bool interruptEnable, halKeyCBack_t cback)
    {
      /* Enable/Disable Interrupt or */
      Hal_KeyIntEnable = interruptEnable;
    
      /* Register the callback fucntion */
      pHalKeyProcessFunction = cback;
    
      /* Determine if interrupt is enable or not */
      if (Hal_KeyIntEnable)
      {
        /* Rising/Falling edge configuratinn */
    
        PICTL &= ~(HAL_KEY_SW_6_EDGEBIT);    /* Clear the edge bit */
        /* For falling edge, the bit must be set. */
      #if (HAL_KEY_SW_6_EDGE == HAL_KEY_FALLING_EDGE)
        PICTL |= HAL_KEY_SW_6_EDGEBIT;
      #endif
    
    
        /* Interrupt configuration:
         * - Enable interrupt generation at the port
         * - Enable CPU interrupt
         * - Clear any pending interrupt
         */
        HAL_KEY_SW_6_ICTL |= HAL_KEY_SW_6_ICTLBIT;
        HAL_KEY_SW_6_IEN |= HAL_KEY_SW_6_IENBIT;
        HAL_KEY_SW_6_PXIFG = ~(HAL_KEY_SW_6_BIT);
    
    
    
        /* Rising/Falling edge configuratinn */
    
        HAL_KEY_JOY_MOVE_ICTL &= ~(HAL_KEY_JOY_MOVE_EDGEBIT);    /* Clear the edge bit */
        /* For falling edge, the bit must be set. */
      #if (HAL_KEY_JOY_MOVE_EDGE == HAL_KEY_FALLING_EDGE)
        HAL_KEY_JOY_MOVE_ICTL |= HAL_KEY_JOY_MOVE_EDGEBIT;
      #endif
    
    
        /* Interrupt configuration:
         * - Enable interrupt generation at the port
         * - Enable CPU interrupt
         * - Clear any pending interrupt
         */
        HAL_KEY_JOY_MOVE_ICTL |= HAL_KEY_JOY_MOVE_ICTLBIT;
        HAL_KEY_JOY_MOVE_IEN |= HAL_KEY_JOY_MOVE_IENBIT;
        HAL_KEY_JOY_MOVE_PXIFG = ~(HAL_KEY_JOY_MOVE_BIT);
    
    
        /* Do this only after the hal_key is configured - to work with sleep stuff */
        if (HalKeyConfigured == TRUE)
        {
          osal_stop_timerEx( Hal_TaskID, HAL_KEY_EVENT);  /* Cancel polling if active */
        }
      }
      else    /* Interrupts NOT enabled */
      {
        HAL_KEY_SW_6_ICTL &= ~(HAL_KEY_SW_6_ICTLBIT); /* don't generate interrupt */
        HAL_KEY_SW_6_IEN &= ~(HAL_KEY_SW_6_IENBIT);   /* Clear interrupt enable bit */
    
        osal_start_timerEx (Hal_TaskID, HAL_KEY_EVENT, HAL_KEY_POLLING_VALUE);    /* Kick off polling */
      }
    
      /* Key now is configured */
      HalKeyConfigured = TRUE;
    }

    从上面的配置可以知道按键检测有两种方式,一种为中断,一种为定时检测   定时检 测 的 话 在 配置 时就 会 直 接 启 动 HAL_KEY_EVENT 事件 , 找到此事件的处理函数。
    hal_drivers.c 中的 Hal_ProcessEvent()函数:

    uint16 Hal_ProcessEvent( uint8 task_id, uint16 events )
    {
      uint8 *msgPtr;
      
      (void)task_id;  // Intentionally unreferenced parameter
    
      if ( events & SYS_EVENT_MSG )
      {
        msgPtr = osal_msg_receive(Hal_TaskID);
    
        while (msgPtr)
        {
          /* Do something here - for now, just deallocate the msg and move on */
    
          /* De-allocate */
          osal_msg_deallocate( msgPtr );
          /* Next */
          msgPtr = osal_msg_receive( Hal_TaskID );
        }
        return events ^ SYS_EVENT_MSG;
      }
    
      if ( events & HAL_LED_BLINK_EVENT )
      {
    #if (defined (BLINK_LEDS)) && (HAL_LED == TRUE)
        HalLedUpdate();
    #endif /* BLINK_LEDS && HAL_LED */
        return events ^ HAL_LED_BLINK_EVENT;
      }
    
      if (events & HAL_KEY_EVENT)
      {
    
    #if (defined HAL_KEY) && (HAL_KEY == TRUE)
        /* Check for keys */
        HalKeyPoll();  
      
        /* if interrupt disabled, do next polling */
        if (!Hal_KeyIntEnable)
        {
          osal_start_timerEx( Hal_TaskID, HAL_KEY_EVENT, 100);
        }
    #endif // HAL_KEY
    
        return events ^ HAL_KEY_EVENT;
      }
    
    #ifdef POWER_SAVING
      if ( events & HAL_SLEEP_TIMER_EVENT )
      {
        halRestoreSleepLevel();
        return events ^ HAL_SLEEP_TIMER_EVENT;
      }
    #endif
    
    #ifdef CC2591_COMPRESSION_WORKAROUND
      if ( events & PERIOD_RSSI_RESET_EVT )
      {
        macRxResetRssi();
        return (events ^ PERIOD_RSSI_RESET_EVT);
      }
    #endif  
      
      /* Nothing interested, discard the message */
      return 0;
    
    }

    接下来就是 HalKeyPoll()了, 

    void HalKeyPoll (void)
    {
      uint8 keys = 0;
    
    /* if ((HAL_KEY_JOY_MOVE_PORT & HAL_KEY_JOY_MOVE_BIT))  // Key is active HIGH 
      {
        keys = halGetJoyKeyInput();
      }
    */
      if (!HAL_PUSH_BUTTON2())//S0
      {
        keys |= HAL_KEY_SW_1; 
      }
      if (!HAL_PUSH_BUTTON1())//S1 
      {
        keys |= HAL_KEY_SW_6; 
      }
      
      if (!Hal_KeyIntEnable)
      {
        if (keys == halKeySavedKeys)
        {
          /* Exit - since no keys have changed */
          return;
        }
        /* Store the current keys for comparation next time */
        halKeySavedKeys = keys;
      }
      else
      {
        /* Key interrupt handled here */
      }
    
      /* Invoke Callback if new keys were depressed */
      if (keys && (pHalKeyProcessFunction))
      {
        (pHalKeyProcessFunction) (keys, HAL_KEY_STATE_NORMAL);
      }
    }

    当按键按下时就传递给上面注册过的回调函数 OnBoard_KeyCallback,传 递 进 去 的 就 是 相 应  键 值 keys ; 找 到 之 前 注 册 的 回 调 函 数OnBoard_KeyCallback(在 OnBoard.c 中)

    void OnBoard_KeyCallback ( uint8 keys, uint8 state )
    {
      uint8 shift;
      (void)state;
    
      shift = (keys & HAL_KEY_SW_6) ? true : false;
    
      if ( OnBoard_SendKeys( keys, shift ) != ZSuccess )
      {
        // Process SW1 here
        if ( keys & HAL_KEY_SW_1 )  // Switch 1
        {
        }
        // Process SW2 here
        if ( keys & HAL_KEY_SW_2 )  // Switch 2
        {
        }
        // Process SW3 here
        if ( keys & HAL_KEY_SW_3 )  // Switch 3
        {
        }
        // Process SW4 here
        if ( keys & HAL_KEY_SW_4 )  // Switch 4
        {
        }
        // Process SW5 here
        if ( keys & HAL_KEY_SW_5 )  // Switch 5
        {
        }
        // Process SW6 here
        if ( keys & HAL_KEY_SW_6 )  // Switch 6
        {
        }
      }
    }

    这里就是通过 OnBoard_SendKeys( keys, shift )在发送系统信息给用户的应用任务。

    uint8 OnBoard_SendKeys( uint8 keys, uint8 state )
    {
      keyChange_t *msgPtr;
    
      if ( registeredKeysTaskID != NO_TASK_ID )
      {
        // Send the address to the task
        msgPtr = (keyChange_t *)osal_msg_allocate( sizeof(keyChange_t) );
        if ( msgPtr )
        {
          msgPtr->hdr.event = KEY_CHANGE;
          msgPtr->state = state;
          msgPtr->keys = keys;
    
          osal_msg_send( registeredKeysTaskID, (uint8 *)msgPtr );
        }
        return ( ZSuccess );
      }
      else
        return ( ZFailure );
    }

    到这里我们就不知道 msg 发送到哪里了? registeredKeysTaskID 任务?这个就 是 我 们 用 户 根 据 自 己 的 需 要 选 择 按 键 的 传 递 的 任 务 号 , 可 通 过RegisterForKeys( xxx_TaskID )注册,此工程中在 SampleApp_Init()中已经调用此函数注册到 SampleApp_TaskID 中了,就是说按键信息会传递到此任务中。
    接下来就是终点站了: 

    void SampleApp_HandleKeys( uint8 shift, uint8 keys ) 
    {
      (void)shift;  // Intentionally unreferenced parameter
      
      if ( keys & HAL_KEY_SW_1 )
      {
        HalUARTWrite(0,"KEY1
    ",4);
        /* This key sends the Flash Command is sent to Group 1.
         * This device will not receive the Flash Command from this
         * device (even if it belongs to group 1).
         */
        SampleApp_SendFlashMessage( SAMPLEAPP_FLASH_DURATION );
      }
    
      if ( keys & HAL_KEY_SW_2 )
      {
        HalUARTWrite(0,"KEY2
    ",4);
        /* The Flashr Command is sent to Group 1.
         * This key toggles this device in and out of group 1.
         * If this device doesn't belong to group 1, this application
         * will not receive the Flash command sent to group 1.
         */
        aps_Group_t *grp;
        grp = aps_FindGroup( SAMPLEAPP_ENDPOINT, SAMPLEAPP_FLASH_GROUP );
        if ( grp )
        {
          // Remove from the group
          aps_RemoveGroup( SAMPLEAPP_ENDPOINT, SAMPLEAPP_FLASH_GROUP );
        }
        else
        {
          // Add to the flash group
          aps_AddGroup( SAMPLEAPP_ENDPOINT, &SampleApp_Group );
        }
      }
    }

    根据具体的键值做相应的处理,这里利用串口打印提示按键按下。 

    轮训按键链接https://pan.baidu.com/s/1zNySZRpc83p9g0-h71jhzg

    第二中按键检测方式:中断检测

     在  HalKeyConfig(HAL_KEY_INTERRUPT_ENABLE, OnBoard_KeyCallback);中 设置成中断检测方式,这样会更节省系统资源,所以一般都是使用中断方式来检测按键

    当按键按下时进入P0口中断服务函数

    void HalKeyConfig (bool interruptEnable, halKeyCBack_t cback)
    {
      /* Enable/Disable Interrupt or */
      Hal_KeyIntEnable = interruptEnable;
    
      /* Register the callback fucntion */
      pHalKeyProcessFunction = cback;
    
      /* Determine if interrupt is enable or not */
      if (Hal_KeyIntEnable)
      {
        /* Rising/Falling edge configuratinn */
    
        PICTL &= ~(HAL_KEY_SW_6_EDGEBIT);    /* Clear the edge bit */
        /* For falling edge, the bit must be set. */
      #if (HAL_KEY_SW_6_EDGE == HAL_KEY_FALLING_EDGE)
        PICTL |= HAL_KEY_SW_6_EDGEBIT;
      #endif
    
    
        /* Interrupt configuration:
         * - Enable interrupt generation at the port
         * - Enable CPU interrupt
         * - Clear any pending interrupt
         */
        HAL_KEY_SW_6_ICTL |= HAL_KEY_SW_6_ICTLBIT;
        HAL_KEY_SW_6_IEN |= HAL_KEY_SW_6_IENBIT;
        HAL_KEY_SW_6_PXIFG = ~(HAL_KEY_SW_6_BIT);
    
    
    
        /* Rising/Falling edge configuratinn */
    
        HAL_KEY_JOY_MOVE_ICTL &= ~(HAL_KEY_JOY_MOVE_EDGEBIT);    /* Clear the edge bit */
        /* For falling edge, the bit must be set. */
      #if (HAL_KEY_JOY_MOVE_EDGE == HAL_KEY_FALLING_EDGE)
        HAL_KEY_JOY_MOVE_ICTL |= HAL_KEY_JOY_MOVE_EDGEBIT;
      #endif
    
    
        /* Interrupt configuration:
         * - Enable interrupt generation at the port
         * - Enable CPU interrupt
         * - Clear any pending interrupt
         */
        HAL_KEY_JOY_MOVE_ICTL |= HAL_KEY_JOY_MOVE_ICTLBIT;
        HAL_KEY_JOY_MOVE_IEN |= HAL_KEY_JOY_MOVE_IENBIT;
        HAL_KEY_JOY_MOVE_PXIFG = ~(HAL_KEY_JOY_MOVE_BIT);
    
    
        /* Do this only after the hal_key is configured - to work with sleep stuff */
        if (HalKeyConfigured == TRUE)
        {
          osal_stop_timerEx( Hal_TaskID, HAL_KEY_EVENT);  /* Cancel polling if active */
        }
      }
      else    /* Interrupts NOT enabled */
      {
        HAL_KEY_SW_6_ICTL &= ~(HAL_KEY_SW_6_ICTLBIT); /* don't generate interrupt */
        HAL_KEY_SW_6_IEN &= ~(HAL_KEY_SW_6_IENBIT);   /* Clear interrupt enable bit */
    
        osal_start_timerEx (Hal_TaskID, HAL_KEY_EVENT, HAL_KEY_POLLING_VALUE);    /* Kick off polling */
      }
    
      /* Key now is configured */
      HalKeyConfigured = TRUE;
    }

     并调用 halProcessKeyInterrupt()函数处理按键中断事件:

    void halProcessKeyInterrupt (void)
    {
      bool valid=FALSE;
    
      if (HAL_KEY_SW_6_PXIFG & HAL_KEY_SW_6_BIT)  /* Interrupt Flag has been set */
      {
        HAL_KEY_SW_6_PXIFG = ~(HAL_KEY_SW_6_BIT); /* Clear Interrupt Flag */
        valid = TRUE;
      }
    
      if (HAL_KEY_JOY_MOVE_PXIFG & HAL_KEY_JOY_MOVE_BIT)  /* Interrupt Flag has been set */
      {
        HAL_KEY_JOY_MOVE_PXIFG = ~(HAL_KEY_JOY_MOVE_BIT); /* Clear Interrupt Flag */
        valid = TRUE;
      }
    
      if (valid)
      {
        osal_start_timerEx (Hal_TaskID, HAL_KEY_EVENT, HAL_KEY_DEBOUNCE_VALUE);
      }
    }

    这里又跑去启动 HAL_KEY_EVENT 事件了,然后就把按键发送个系统上层任务,后面 就跟轮询方式一样了

    中断方式链接:https://pan.baidu.com/s/1oKAOByy6PdIaiiKieIoXMA

     下面是修改IO口和中断标志的位置

    修改 hal_key.C 文件.

      1、 修改 SW_6 所在 IO
    2

    /* SW_6 is at P0.4 */
    #define HAL_KEY_SW_6_PORT P0
    
    #define HAL_KEY_SW_6_BIT BV(4) //BV(1) 改到 P0.4
    
    #define HAL_KEY_SW_6_SEL P0SEL
    #define HAL_KEY_SW_6_DIR P0DIR

    3、 边缘触发方式

    /* edge interrupt */
    #define HAL_KEY_SW_6_EDGEBIT BV(0)
    #define
    HAL_KEY_SW_6_EDGE
    HAL_KEY_RISING_EDGE//HAL_KEY_FALLING_EDGE 改成上升缘触发

    4、 中断一些相关标志位

    /* SW_6 interrupts */
    #define HAL_KEY_SW_6_IEN IEN1 /* CPU interrupt mask
    register */
    #define HAL_KEY_SW_6_IENBIT BV(5) /* Mask bit for all of Port_0 */
    #define HAL_KEY_SW_6_ICTL P0IEN /* Port Interrupt Control
    register */
    #define HAL_KEY_SW_6_ICTLBIT BV(4) //BV(1) /* P0IEN – P0.1
    enable/disable bit 改到 P0.4*/
    #define HAL_KEY_SW_6_PXIFG P0IFG /* Interrupt flag at source */

    不需要用到 TI 的摇杆 J-STICK, 所以把代码注释掉。

    void HalKeyPoll (void)
    {
    uint8 keys = 0;
    if ((HAL_KEY_JOY_MOVE_PORT & HAL_KEY_JOY_MOVE_BIT)) 
    
    /* Key is active HIGH */
    {
    //keys = halGetJoyKeyInput();
    } 

    修改 hal_board_cfg.h 文件。

      1、 修改 SW_6 所在 IO 口
    /* S1 */
    #define PUSH1_BV BV(4) //BV(1)
    #define PUSH1_SBIT P0_4 //P0_1 

    修改 OnBoard.C 文件。在 ZMain.C 目录树下, 

       2、 使能中断
    HalKeyConfig(HAL_KEY_INTERRUPT_ENABLE,OnBoard_KeyCallback); 

    下面是协议栈是检测到按键按下时候是如何处理的, 16 位必须只占 1 位,所以只能 16个任务。
    回到 SampleApp.c 文件,找到按键时间处理 KEY_CHANGE 事件的函数:

    当按键按下时,就会进入上面事件,我们加入串口提示:

    // Received when a key is pressed
            case KEY_CHANGE://按键事件
              HalUARTWrite(0,"KEY ",4);
              SampleApp_HandleKeys( ((keyChange_t *)MSGpkt)->state, ((keyChange_t *)MSGpkt)->keys );
              break;

    进入 SampleApp_HandleKeys()函数,加入我们的按键处理函数。这里是SW_6,也即是我们刚定义好的开发板上的 S1

    if ( keys & HAL_KEY_SW_6 )
      {
        HalUARTWrite(0,"KEY1
    ",4);
        /* This key sends the Flash Command is sent to Group 1.
         * This device will not receive the Flash Command from this
         * device (even if it belongs to group 1).
         */
        SampleApp_SendFlashMessage( SAMPLEAPP_FLASH_DURATION );
      }



    这个实验花了一个下午才弄明白,不过这一个下午的改错,对这个操作系统工作流程的理解确实比原来理解的深了一点,不过要暂时先放下ZigBee了,继续着手STM32,开始学STM32的时候忘记写一写博客了,等把这个工训大赛结束之后一起写吧!



     

     


      

  • 相关阅读:
    [网络流24题]餐巾计划问题
    [网络流24题]方格取数问题
    [网络流24题]试题库问题
    [网络流24题]最长递增子序列问题
    [网络流24题]圆桌问题
    [网络流24题]魔术球问题
    51nod1462 树据结构
    51nod1053 最大M子段和 V2
    51nod1026 矩阵中不重复的元素 V2
    BZOJ3832: [Poi2014]Rally
  • 原文地址:https://www.cnblogs.com/tianxxl/p/9893023.html
Copyright © 2011-2022 走看看