因朋友所托而我也正在学习Zigbee跟BLE4.0所以就花了两小时先看了下KEY的运作原理 下面来介绍下
首先打开Zmain.c文件的main函数我们可以看到 HalDriverInit(); 硬件抽象层也就是驱动层的初始化 ,里面有很多芯片外设的初始化 包括KEY
/* KEY */
#if (defined HAL_KEY) && (HAL_KEY == TRUE)
HalKeyInit();
#endif
我们go to跟上会发现这个函数里面是所有按键的初始化设置 DIR跟SEL寄存器
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;
}
我们继续回到main.c文件的main函数
里面有调用按钮初始化函数
继续go to
// Initialize board I/O
InitBoard( OB_COLD );
这里宏定义带进去的是OB_COLD,所以这里的调用是先初始化if检测成立的 主要任务是关闭所有中断
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);
}
}
而else里面的什么时候被执行呢 ,我们继续到main函数
在系统初始化完成后又再一次调用了这个函数
// Final board initialization
InitBoard( OB_READY );
而这次带进的参数是
#define OB_READY 2
这次会进入否则语句
else // !OB_COLD
{
/* Initialize Key stuff */
HalKeyConfig(HAL_KEY_INTERRUPT_ENABLE, OnBoard_KeyCallback);
}
这次则会调用hal_key.c文件里面的按键配置,带入的第一个参数是HAL_KEY_INTERRUPT_ENABLE
按键的检查方式有两种:
1:轮询的方式
2:外部中断的方式
进入HalKeyConfig函数我们可以看到有if判断
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_set_event(Hal_TaskID, HAL_KEY_EVENT);
}
/* Key now is configured */
HalKeyConfigured = TRUE;
}
Hal_KeyIntEnable参数已经等于函数带入的interruptEnable
Hal_KeyIntEnable = HAL_KEY_INTERRUPT_ENABLE
则配置IO的中断寄存器等
如果不成立Hal_KeyIntEnable = HAL_KEY_INTERRUPT_DISABLE 时
测不产生中断 清除配置寄存器并且触发一个事件
osal_set_event(Hal_TaskID, 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 */
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;
if ((HAL_KEY_JOY_MOVE_PORT & HAL_KEY_JOY_MOVE_BIT)) /* Key is active HIGH */
{
// keys = halGetJoyKeyInput();
}
/* If interrupts are not enabled, previous key status and current key status
* are compared to find out if a key has changed status.
*/
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 */
}
if (HAL_PUSH_BUTTON1())
{
keys |= HAL_KEY_SW_6;
}
/* Invoke Callback if new keys were depressed */
if (keys && (pHalKeyProcessFunction))
{
(pHalKeyProcessFunction) (keys, HAL_KEY_STATE_NORMAL);
}
}
而这个函数里面有一个指针pHalKeyProcessFunction这个是halKeyCBack_t类型的指针变量
类型定义:typedef void (*halKeyCBack_t) (uint8 keys, uint8 state);
他在HalKeyConfig被调用的时候被赋值了HalKeyConfig带进的第二个参数 也就是回调函数的地址
相当于这个指针可以调用OnBoard_KeyCallback函数 因为在HalKeyConfig被调用的时候就已经OnBoard_KeyCallback函数的地址传递给了pHalKeyProcessFunction指针
好了 现在回到刚刚讲的HalKeyPoll函数
我们开最后的两句 if(keys && (pHalKeyProcessFunction))
检测keys是否成立 如果有按键按下则按位 |(或)上则成立 (&&)并且检测pHalKeyProcessFunction是否成立 如果没有设置回调这个地址会是0 现在它已经被赋值了所以….
成立测调用OnBoard_KeyCallback并带入参数keys和一个宏定义 额。。。这个宏定义在这个函数里并没什么操作 请看代码:
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也就是HAL_KEY_SW_6是否被按下..
为什么这么做我也不清楚….
我们来看OnBoard_SendKeys函数
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 );
}
检测registeredKeysTaskID有没被注册
给msgPtr分配内存
发送了这个信号之后触发SampleApp.c文件的SampleApp_ProcessEvent任务里的系统事件
接下来你懂得 ….
case KEY_CHANGE:
HalUARTWrite(0,"KEY ",4);//串口提示
SampleApp_HandleKeys( ((keyChange_t *)MSGpkt)->state, ((keyChange_t *)MSGpkt)->keys );
break;
如果是轮训方式的话在第一次设置HAL_KEY_EVENT事件的时候就已经开始定时100毫秒后再次触发事件了
这样的话就可以100ms调用一次HalKeyPoll函数来检测按键了
/* if interrupt disabled, do next polling */
if (!Hal_KeyIntEnable)
{
osal_start_timerEx( Hal_TaskID, HAL_KEY_EVENT, 100);
}
好了,按键的流程就讲完了 希望对你们有帮助 也希望写出这文章能让我记得更牢固写,或者以后忘记了可以翻出来看看。