ZigBee TI ZStack CC2530 3.14 按键驱动01-轮询模式
2017-08-14 23:11
465 查看
(配套源码、软件、开发板等资源,可移步博客同名QQ群:拿破仑940911)
在Z-Stack协议栈中,对于按键的检测,分为两种不同的机制,分别称为“轮询模式”和“中断模式”,类比单片机中的按键检测,还是很好理解的。但是相比我们之前所学所用,Z-Stack协议栈中的按键检测实现还是相对要复杂一些的。
本节将分为4点详细讲述Z-Stack协议栈中的按键检测机制:
1、按键检测机制选择——“轮询模式”or“中断模式”
2、轮询模式
3、中断模式
4、HalKeyInit( )
1、按键检测机制选择——“轮询模式”or“中断模式”
实际运行过程中,按键检测到底工作在哪种模式,由InitBoard( )函数中下面这句代码决定:
HalKeyConfig(HAL_KEY_INTERRUPT_DISABLE, OnBoard_KeyCallback);HalKeyConfig( )函数中的第一个参数,若是HAL_KEY_INTERRUPT_DISABLE,则是选择“轮询模式”;若是HAL_KEY_INTERRUPT_ENABLE,则是选择“中断模式”;由上述代码可见,Z-Stack协议栈中默认使用的是“轮询模式”。具体是如何实现的,详见HalKeyConfig( )函数中的实现代码,该函数主要功能如下:
(1)指定按键回调函数为OnBoard_KeyCallback( ): /* Register the callback fucntion */
pHalKeyProcessFunction = cback;(2)如果要“使能中断”,则进行相应的中断配置(如配置触发边沿、清除中断标志位等):
2、轮询模式
(1)上面已经提及,Z-Stack协议栈中默认使用的就是“轮询模式”,第一次触发硬件抽象层任务(Hal_TaskID)中的按键查询事件(HAL_KEY_EVENT)后,随即也就触发了间隔为100ms(1秒10次)的定时按键检测(循环调用HalKeyPoll( )),故称为“轮询模式”: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;
}
......
}(2)在HalKeyPoll( )函数中,对各个定义的按键状态做完检测之后,即调用前面指定的按键回调函数OnBoard_KeyCallback( ),对键值做进一步处理:void HalKeyPoll (void)
{
......
/* Invoke Callback if new keys were depressed */
if (keys && (pHalKeyProcessFunction))
{
(pHalKeyProcessFunction) (keys, HAL_KEY_STATE_NORMAL);
}
......
}OnBoard_KeyCallback( )函数的代码如下,可见其中又进一步调用了OnBoard_SendKeys( ):
{
// Allow only the first task
if ( registeredKeysTaskID == NO_TASK_ID )
{
registeredKeysTaskID = task_id;
return ( true );
}
else
return ( false );
}而调用RegisterForKeys( )函数,则是在我们的应用层任务ProjectApp中,也就是所谓的“注册按键”:
uint16 ProjectApp_ProcessEvent( uint8 task_id, uint16 events )
{
......
if ( events & SYS_EVENT_MSG )
{
......
case KEY_CHANGE : ProjectApp_HandleKeys(((keyChange_t *)MSGpkt)->state,((keyChange_t *)MSGpkt)->keys);break;
......
}
......
}
具体ProjectApp_HandleKeys( )这个键值处理函数实现什么功能,就完全取决于大家自己啦~
3、中断模式
(1)在InitBoard( )函数中调用HalKeyConfig( )时,若第一个参数填为HAL_KEY_INTERRUPT_ENABLE,则会自动选择为“中断模式”;
(2)在“中断模式”下,一旦按键所在IO口产生了外部中断,程序便会立即响应,调到对应的中断服务函数中(以P0组IO对应中断为例):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();
}Z-Stack协议栈中关于P0组的中断服务函数已经编写好,我们只需关心其中的halProcessKeyInterrupt( )函数即可:
(3)延时HAL_KEY_DEBOUNCE_VALUE毫秒后,程序运行到了硬件抽象层任务(Hal_TaskID)的任务处理函数(Hal_ProcessEvent( ))中的HAL_KEY_EVENT分支,后面的代码原理就和“轮询模式”几乎没有任何区别了!唯一一点不同是不会像“轮询模式”下那样触发间隔为100ms(1秒10次)的定时按键检测。
4、HalKeyInit( )
不管选择的是“轮询模式”还是“中断模式”,在系统真正开始进行按键检测之前,一定都要对按键所在IO当做是普通IO口来进行相关初始化,对应的函数是HalKeyInit( )。
(配套源码、软件、开发板等资源,可移步博客同名QQ群:拿破仑940911)
在Z-Stack协议栈中,对于按键的检测,分为两种不同的机制,分别称为“轮询模式”和“中断模式”,类比单片机中的按键检测,还是很好理解的。但是相比我们之前所学所用,Z-Stack协议栈中的按键检测实现还是相对要复杂一些的。
本节将分为4点详细讲述Z-Stack协议栈中的按键检测机制:
1、按键检测机制选择——“轮询模式”or“中断模式”
2、轮询模式
3、中断模式
4、HalKeyInit( )
1、按键检测机制选择——“轮询模式”or“中断模式”
实际运行过程中,按键检测到底工作在哪种模式,由InitBoard( )函数中下面这句代码决定:
HalKeyConfig(HAL_KEY_INTERRUPT_DISABLE, OnBoard_KeyCallback);HalKeyConfig( )函数中的第一个参数,若是HAL_KEY_INTERRUPT_DISABLE,则是选择“轮询模式”;若是HAL_KEY_INTERRUPT_ENABLE,则是选择“中断模式”;由上述代码可见,Z-Stack协议栈中默认使用的是“轮询模式”。具体是如何实现的,详见HalKeyConfig( )函数中的实现代码,该函数主要功能如下:
(1)指定按键回调函数为OnBoard_KeyCallback( ): /* Register the callback fucntion */
pHalKeyProcessFunction = cback;(2)如果要“使能中断”,则进行相应的中断配置(如配置触发边沿、清除中断标志位等):
/* 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 */ /* 4000 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 */ } }(3)如果不“使能中断”,则向硬件抽象层任务(Hal_TaskID)发送按键查询事件(HAL_KEY_EVENT),触发一次按键查询:
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_set_event(Hal_TaskID, HAL_KEY_EVENT); }
2、轮询模式
(1)上面已经提及,Z-Stack协议栈中默认使用的就是“轮询模式”,第一次触发硬件抽象层任务(Hal_TaskID)中的按键查询事件(HAL_KEY_EVENT)后,随即也就触发了间隔为100ms(1秒10次)的定时按键检测(循环调用HalKeyPoll( )),故称为“轮询模式”: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;
}
......
}(2)在HalKeyPoll( )函数中,对各个定义的按键状态做完检测之后,即调用前面指定的按键回调函数OnBoard_KeyCallback( ),对键值做进一步处理:void HalKeyPoll (void)
{
......
/* Invoke Callback if new keys were depressed */
if (keys && (pHalKeyProcessFunction))
{
(pHalKeyProcessFunction) (keys, HAL_KEY_STATE_NORMAL);
}
......
}OnBoard_KeyCallback( )函数的代码如下,可见其中又进一步调用了OnBoard_SendKeys( ):
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 ) { ...... } }在OnBoard_SendKeys( )函数中,最终将键值(keys)封装成了一个keyChange_t类型的数据包,发送至了registeredKeysTaskID任务:
uint8 OnBoard_SendKeys( uint8 keys, uint8 state ) { ...... // 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( )函数中被赋值指定的:uint8 RegisterForKeys( uint8 task_id )
{
// Allow only the first task
if ( registeredKeysTaskID == NO_TASK_ID )
{
registeredKeysTaskID = task_id;
return ( true );
}
else
return ( false );
}而调用RegisterForKeys( )函数,则是在我们的应用层任务ProjectApp中,也就是所谓的“注册按键”:
void ProjectApp_Init( uint8 task_id ) { ProjectApp_TaskID = task_id; ...... RegisterForKeys( ProjectApp_TaskID );// Register for all key events - This app will handle all key events ...... }(3)紧接着,我们的应用层任务ProjectApp就会收到键值所在的数据包,具体处理键值的代码如下:
uint16 ProjectApp_ProcessEvent( uint8 task_id, uint16 events )
{
......
if ( events & SYS_EVENT_MSG )
{
......
case KEY_CHANGE : ProjectApp_HandleKeys(((keyChange_t *)MSGpkt)->state,((keyChange_t *)MSGpkt)->keys);break;
......
}
......
}
具体ProjectApp_HandleKeys( )这个键值处理函数实现什么功能,就完全取决于大家自己啦~
3、中断模式
(1)在InitBoard( )函数中调用HalKeyConfig( )时,若第一个参数填为HAL_KEY_INTERRUPT_ENABLE,则会自动选择为“中断模式”;
(2)在“中断模式”下,一旦按键所在IO口产生了外部中断,程序便会立即响应,调到对应的中断服务函数中(以P0组IO对应中断为例):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();
}Z-Stack协议栈中关于P0组的中断服务函数已经编写好,我们只需关心其中的halProcessKeyInterrupt( )函数即可:
void halProcessKeyInterrupt (void) { ...... if (valid) { osal_start_timerEx (Hal_TaskID, HAL_KEY_EVENT, HAL_KEY_DEBOUNCE_VALUE); } }在halProcessKeyInterrupt( )函数中,首先对按键引发的外部中断的有效性进行判断,若有效,便也会如“轮询模式”下一样,向硬件抽象层任务(Hal_TaskID)发送按键查询事件(HAL_KEY_EVENT),触发一次按键查询。不同的是,这里是延时HAL_KEY_DEBOUNCE_VALUE(25)毫秒之后再执行,这里的延时可以起到“消抖”的功能!
(3)延时HAL_KEY_DEBOUNCE_VALUE毫秒后,程序运行到了硬件抽象层任务(Hal_TaskID)的任务处理函数(Hal_ProcessEvent( ))中的HAL_KEY_EVENT分支,后面的代码原理就和“轮询模式”几乎没有任何区别了!唯一一点不同是不会像“轮询模式”下那样触发间隔为100ms(1秒10次)的定时按键检测。
4、HalKeyInit( )
不管选择的是“轮询模式”还是“中断模式”,在系统真正开始进行按键检测之前,一定都要对按键所在IO当做是普通IO口来进行相关初始化,对应的函数是HalKeyInit( )。
(配套源码、软件、开发板等资源,可移步博客同名QQ群:拿破仑940911)
相关文章推荐
- ZigBee TI ZStack CC2530 3.15 按键驱动02-中断模式
- ZigBee TI ZStack CC2530 4.12 单播通信01-16位地址模式
- ZigBee TI ZStack CC2530 5.6 实例(三)多功能按键01-实现
- ZigBee TI ZStack CC2530 5.5 实例(三)多功能按键00-总
- ZigBee TI ZStack CC2530 4.17 绑定通信01-概念介紹
- ZigBee TI ZStack CC2530 4.13 单播通信02-64位地址模式
- ZigBee TI ZStack CC2530 4.5 设备地址01-Primary/Secondary IEEE Address
- ZigBee TI ZStack CC2530 5.7 实例(三)多功能按键02-指示灯
- ZigBee TI ZStack CC2530 3.18 串口01-发送
- ZigBee TI ZStack CC2530 3.10 IO口01-输入输出
- ZigBee TI ZStack CC2530 2.1 如何学习ZigBee
- ZigBee TI ZStack CC2530 5.2 实例(二)终端设备低功耗与电池寿命00-总
- ZigBee TI ZStack CC2530 3.11 IO口02-外部中断
- ZigBee TI ZStack CC2530 2.6 选择开发板和下载器
- ZigBee TI ZStack CC2530 4.16 绑定通信00-总
- ZigBee TI ZStack CC2530 4.18 绑定通信02-实验验证
- ZigBee TI ZStack CC2530 3.6 创建基于ZStack的新工程
- ZigBee TI ZStack CC2530 4.11 单播通信00-总
- ZigBee TI ZStack CC2530 4.15 组播通信
- ZigBee TI ZStack CC2530 8.4 用高版本IAR打开低版本协议栈