概述
- 协议栈已经自带了按键的驱动和使用函数。
- 网蜂 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-通过协议栈实现按键功能所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复