我是靠谱客的博主 敏感果汁,最近开发中收集的这篇文章主要介绍ZIGBEE-通过协议栈实现按键功能,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

  • 协议栈已经自带了按键的驱动和使用函数。
  • 网蜂 ZigBee 开发套件按键 S1 连接的是 P0.0 口,按键 S2 连接的是 P0.1 口。
  • 在 ZMain.c 的 main 主函数中跟按键相关的有: HalDriverInit();    InitBoard( OB_READY );

 

  • 按键流程分析

A.非中断情况下:

第一步:进入 HalDriverInit()中的 HalKeyInit()
 

void HalKeyInit( void )

{

  /* Initialize previous key to 0 */

  halKeySavedKeys = 0;





   /*这里主要是初始化按键相关的引脚,HAL_KEY_SW_6 就是对应 P01*/

  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 就是 TI 板子上的 J-STICK 摇杆,这里我们不用用到,直接注释或删掉。*/

  //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;

}

 

第二步:分析 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_ENABLE, OnBoard_KeyCallback);





  //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 */


    
    /********* 启动 HAL_KEY_EVENT 事件 ***************/
    osal_set_event(Hal_TaskID, HAL_KEY_EVENT);  




  }


/*从上面的配置我们知道按键检测有两种方式,一种为中断,一种为定时检测;
定 时 检 测 的 话 在 配 置 时 就 会 直 接 启 动 HAL_KEY_EVENT 事 件 , 那 么 在
HAL_KEY_EVENT 中会做什么事情呢?找到此事件的处理函数。 hal_drivers.c 中的 Hal_ProcessEvent()函数: */


  
  /* Key now is configured */
  HalKeyConfigured = TRUE;
}

第四步:启 动 HAL_KEY_EVENT 事 件 后,进入hal_drivers.c 中的 Hal_ProcessEvent()函数

 /***************检测按键*********************************/
  
  if (events & HAL_KEY_EVENT)
  {

#if (defined HAL_KEY) && (HAL_KEY == TRUE)
    


    /* Check for keys */
    HalKeyPoll();          //检测按键——重点 



    /* if interrupt disabled, do next polling */

    //如果不是中断方式的话就定时启动此事件检测按键 ,启用定时器,定时启动HAL_KEY_EVent事件。
    if (!Hal_KeyIntEnable)
    {
      osal_start_timerEx( Hal_TaskID, HAL_KEY_EVENT, 100);
    }
#endif // HAL_KEY



    return events ^ HAL_KEY_EVENT;
  }

第五步:在上一步中定时进入HalKeyPoll()检测按键。


void HalKeyPoll (void)
{

  uint8 keys = 0; //检测按键 S2 是否按下 

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

  
/*************************按键的检测 **********************/
  if (HAL_PUSH_BUTTON1())   //这里需要改成低电平按下 
  {
    keys |= HAL_KEY_SW_6;
  }


  /* If interrupts are not enabled, previous key status and current key status
   * are compared to find out if a key has changed status.
  
    当按键按下时就传递给上面注册过的回调函数 OnBoard_KeyCallback,传递进去的就是
    相应的键值keys ;找到之前注册的回调函数OnBoard_KeyCallback(在 OnBoard.c 中) 
   */
  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 */
  /* 调用注册的回调函数,即上面的 OnBoard_KeyCallback */ 
  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
    {
      //这里就是通过 OnBoard_SendKeys( keys, shift )在发送系统信息给用户的应用任务。
      
    }



    // 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 );
      /*registeredKeysTaskID 任务     这个就 是 我 们 用 户 根 据 自 己 的 需 要 
      选 择 按 键 的 传 递 的 任 务 号 ,  可 通 过RegisterForKeys( xxx_TaskID )
      注册,此工程中在 SampleApp_Init()中已经调用此函数注册到 SampleApp_TaskID 
      中了,就是说按键信息会传递到此任务中。 */



    }
    return ( ZSuccess );
  }
  else
    return ( ZFailure );
}

第八步:传递到SampleApp_ProcessEvent( uint8 task_id, uint16 events )中的 SampleApp_HandleKeys()按键事件及处理函数.

uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events )
{
  afIncomingMSGPacket_t *MSGpkt;
  (void)task_id;  // Intentionally unreferenced parameter

  if ( events & SYS_EVENT_MSG )   //系统信息发送事件
  {
    MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID );
    while ( MSGpkt )
    {
      switch ( MSGpkt->hdr.event )
      {


        // Received when a key is pressed
        case KEY_CHANGE:  //按键事件及处理函数
          SampleApp_HandleKeys( ((keyChange_t *)MSGpkt)->state, ((keyChange_t *)MSGpkt)->keys );



          break;

        // Received when a messages is received (OTA) for this endpoint
        case AF_INCOMING_MSG_CMD:
          SampleApp_MessageMSGCB( MSGpkt );
          break;

第九步:在SampleApp_HandleKeys()按键事件及处理函数中 根据具体的键值做相应的处理,这里利用串口打印提示按键按下。


void SampleApp_HandleKeys( uint8 shift, uint8 keys )
{
  (void)shift;  // Intentionally unreferenced parameter
  
  if ( keys & HAL_KEY_SW_6 )
  {
    /* This key sends the Flash Command is sent to Group 1.此键发送Flash命令发送到组1
     * This device will not receive the Flash Command from this
     * device (even if it belongs to group 1).
     * 此设备将不接收来自该设备的闪存命令(即使它属于第1组)
     */

    
   /*按键事件:串口打印*/
   HalUARTWrite(0,"KEY S2n",7);
   // SampleApp_SendFlashMessage( SAMPLEAPP_FLASH_DURATION );




  }

  if ( keys & HAL_KEY_SW_2 )
  {
    /* 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.
     *FLASR命令发送到第1组。
     *此键可将该设备切换到第1组。
     *如果此设备不属于第1组,则此应用程序
     *不会收到发送到组1的Flash命令。
     */
    HalUARTWrite(0,"KEY S3n",7);
   }
}

 

B.中断方式

在 HalKeyConfig(HAL_KEY_INTERRUPT_ENABLE, OnBoard_KeyCallback);中设置成中断检测方式。设置成中断检测方式就不会定时启动 HAL_KEY_EVENT 事件,这样就会更加节省系统资源,所以一般都是使用中断方式来检测按键。当按下按键时会进入 P0 口中断服务函数 hal_key.c中的HAL_ISR_FUNCTION( halKeyPort0Isr, P0INT_VECTOR )  P0 口中断服务函数 。

HAL_ISR_FUNCTION( halKeyPort0Isr, P0INT_VECTOR )
{
  HAL_ENTER_ISR();

  if (HAL_KEY_SW_6_PXIFG & HAL_KEY_SW_6_BIT)
  {
    halProcessKeyInterrupt();
  }

  /*
    Clear the CPU interrupt flag for Port_0
    PxIFG has to be cleared before PxIF
  */
  HAL_KEY_SW_6_PXIFG = 0;
  HAL_KEY_CPU_PORT_0_IF = 0;
  
  CLEAR_SLEEP_MODE();
  HAL_EXIT_ISR();
}

并调用 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 事件了。

 

 

 

 

 

 

 

 

 

 

最后

以上就是敏感果汁为你收集整理的ZIGBEE-通过协议栈实现按键功能的全部内容,希望文章能够帮你解决ZIGBEE-通过协议栈实现按键功能所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(76)

评论列表共有 0 条评论

立即
投稿
返回
顶部