ZigBee组网 协议栈按键实验

https://blog.csdn.net/scgaliguodong123_/article/details/41680863

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

本ZigBee开发套件按键S1连接的是P0.0口,按键S2连接的是P0.1口。

===========================================

ZMain.cmain主函数中跟按键相关的有:
HalDriverInit();  
InitBoard( OB_READY );

1、
HalDriverInit()中的HalKeyInit()有

hal_drivers.c

  /* KEY */
#if (defined HAL_KEY) && (HAL_KEY == TRUE)
  HalKeyInit();

hal_key.c

void HalKeyInit( void )

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_SW_6_BIT就是对应P01

#define  BV(n)  (1<<(n))

===========================================

2、 

OnBoard.c

InitBoard( OB_READY )

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);
  }


#define OB_COLD  0

按键检测有两种方式,

一种为中断,一种为定时检测;定时检测的话,在 配置时就会直接启动HAL_KEY_EVENT事件。

#define HAL_KEY_INTERRUPT_DISABLE    0x00             //定时检测
#define HAL_KEY_INTERRUPT_ENABLE     0x01 //中断      一般采用中断方式,更加节省系统资源


定时检测方式

HalKeyConfig(HAL_KEY_INTERRUPT_DISABLEE, OnBoard_KeyCallback);

 /* Determine if interrupt is enable or not */
  if (Hal_KeyIntEnable)
  {

}
  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_ProcessEvent()

hal_drivers.c

uint16 Hal_ProcessEvent( uint8 task_id, uint16 events )

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


hal_key.c

void HalKeyPoll (void)

{

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

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

  /* 调用注册的回调函数,即上面的 OnBoard_KeyCallback */
  /* Invoke Callback if new keys were depressed */
  if (keys && (pHalKeyProcessFunction))
  {
    (pHalKeyProcessFunction) (keys, HAL_KEY_STATE_NORMAL);
  }     

}


----------------------------------------------------------------

 #define    HAL_PUSH_BUTTON1()    (PUSH1_POLARITY (PUSH1_SBIT))
这里我们是低电平按下,所以改成:
#define    PUSH1_POLARITY    ACTIVE_LOW 

----------------------------------------------------------------

按键按下时就传递给上面注册过的回调函数 OnBoard_KeyCallback,传递 进 去 的 就 是 相 应 的 键 值 keys : 
找到之前注册的回调函数
OnBoard_KeyCallback(在 OnBoard.c 中) 
void OnBoard_KeyCallback ( uint8 keys, uint8 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
     {
     }

通过 OnBoard_SendKeys( keys, shift )在发送系统信息给用户的应用任务。 
osal_msg_send( registeredKeysTaskID, (uint8 *)msgPtr );

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

根据具体的键值做相应的处理,这里利用串口打印提示按键按下。
----------------------------------------------------------------
void SampleApp_HandleKeys( uint8 shift, uint8 keys )
  (void)shift;  // Intentionally unreferenced parameter 
  if ( keys & HAL_KEY_SW_6 )
  {
    HalUARTWrite(0, "key S2\n", 7);
  }

----------------------------------------------------------------  

===========================================



按键总体框架图

中断方式

HalKeyConfig(HAL_KEY_INTERRUPT_ENABLE, OnBoard_KeyCallback);

设置成中断检测方式。设置成中断检测方式就不会定时启动 HAL_KEY_EVENT 事件,
这样就会更加节省系统资源,所以一般都是使用中断方式来检测按键。

当按下按键时会进入 P0 口中断服务函数
hal_key.c
HAL_ISR_FUNCTION( halKeyPort0Isr, P0INT_VECTOR )

if (HAL_KEY_JOY_MOVE_PXIFG & HAL_KEY_JOY_MOVE_BIT)
  {
    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 (valid)
  {
    osal_start_timerEx (Hal_TaskID, HAL_KEY_EVENT, HAL_KEY_DEBOUNCE_VALUE);
  }
}

调用 halProcessKeyInterrupt()函数处理按键中断事件, 启动 HAL_KEY_EVENT 事件了,
然后就把按键发送个系统上层任务。