首先在Main函数中,因为这是整个系统的入口点。
(1)Main函数
所有程序运行首先是在主函数下开始的,这里也不例外。找到Zmain.c文件下的主函数:
ZSEG int main( void )
{
// 初始化时要关中断
osal_int_disable( INTS_ALL );
// 电压检测程序
zmain_vdd_check();
// 初始化堆栈
zmain_ram_init();
// 第一次初始化平台 ***** 注释1*******
InitBoard( OB_COLD );
// 硬件驱动初始化******注释2******
HalDriverInit();
…………
//系统初始化*******注释3*******
osal_init_system();
// 第二次初始化平台*******注释4*******
InitBoard( OB_READY );
…………….
osal_start_system(); // 操作系统开始运行
}
说明:
(1)注释1:该函数在onboard.c中,原型如下
void InitBoard( byte level )
{
if ( level == OB_COLD )
{
这里执行第一次初始化的内容
}
else
}
(2)注释2:这个函数在hal_drivers.c中
void HalDriverInit (void)
{
………
#if (defined HAL_KEY) && (HAL_KEY == TRUE)
HalKeyInit();
#endif
………..
}
HalKeyInit()这个函数在hal_key.c中
void HalKeyInit( void )
{
#if (HAL_KEY == TRUE)
/* Initialize previous key to 0 */
halKeySavedKeys = 0;
....................
#if defined (HAL_KEY_SW_5_ENABLE)
HAL_KEY_SW_5_SEL &= ~(HAL_KEY_SW_5_BIT); /* p0SEL的第5位置0,把P0.5作为普通IO口 */
HAL_KEY_SW_5_DIR &= ~(HAL_KEY_SW_5_BIT); /* p0DIR的第5位置0,把P0.5作为输入口 */
HAL_KEY_SW_5_INP |= HAL_KEY_SW_5_BIT;/* Set pin input mode to 三态 */
#endif
/* 回调函数的初始化 ,赋值为NULL*/
pHalKeyProcessFunction = NULL;
/* 按键还未经配置,赋值为FALSE*/
HalKeyConfigured = FALSE;
#endif /* HAL_KEY */
}
总结:这个函数基本完成了相应管脚的基本配置管脚的输入输出等等,给一些变量赋初值。
其中回调函数的定义是这样的
static halKeyCBack_t pHalKeyProcessFunction;
那halKeyCBack_t是这样定义的
typedef void (*halKeyCBack_t) (uint8 keys, uint8 state);
也就是说它是一个函数的指针。
(3)注释4:该函数在onboard.c中,原型如下
void InitBoard( byte level )
{
if ( level == OB_COLD )
{
//这里执行第一次初始化的内容
}
else//以下执行第二次初始化的内容
{
………
OnboardKeyIntEnable = HAL_KEY_INTERRUPT_DISABLE;
HalKeyConfig( OnboardKeyIntEnable, OnBoard_KeyCallback);
}
}
这里执行else后面的内容,这里调用了HalKeyConfig()函数,这个函数是按键的一些配置,
void HalKeyConfig (bool interruptEnable, halKeyCBack_t cback)
{
#if (HAL_KEY == TRUE)
/* Enable/Disable Interrupt or */
Hal_KeyIntEnable = interruptEnable;
/* Register the callback fucntion */
pHalKeyProcessFunction = cback; //这里给回调函数赋值
/* Determine if interrupt is enable or not */
if (Hal_KeyIntEnable)
{
………………………………
#if defined (HAL_KEY_SW_5_ENABLE)
PICTL &= ~(HAL_KEY_SW_5_EDGEBIT);/* Set rising or falling edge */
#if (HAL_KEY_SW_5_EDGE == HAL_KEY_FALLING_EDGE)
PICTL |= HAL_KEY_SW_5_EDGEBIT;
#endif
HAL_KEY_SW_5_ICTL |= HAL_KEY_SW_5_ICTLBIT; /* Set interrupt enable bit */
HAL_KEY_SW_5_IEN |= HAL_KEY_SW_5_IENBIT;
HAL_KEY_SW_5_PXIFG = ~(HAL_KEY_SW_5_BIT); /* Clear any pending interrupts */
#endif
………………………………………………
/* 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 */
{
#if defined (HAL_BOARD_CC2430DB)
#define HAL_KEY_SW_5_ENABLE /* Allow SW5 only when key interrupt is disable */
#endif
#if defined (HAL_KEY_SW_6_ENABLE)
HAL_KEY_SW_6_ICTL &= ~(HAL_KEY_SW_6_ICTLBIT); /* Clear interrupt enable bit */
HAL_KEY_SW_6_IEN &= ~(HAL_KEY_SW_6_IENBIT);
#endif
#if defined (HAL_KEY_SW_5_ENABLE)
HAL_KEY_SW_5_ICTL &= ~(HAL_KEY_SW_5_ICTLBIT); /* Clear interrupt enable bit */
HAL_KEY_SW_5_IEN &= ~(HAL_KEY_SW_5_IENBIT);
#endif
osal_start_timerEx (Hal_TaskID, HAL_KEY_EVENT, HAL_KEY_POLLING_VALUE); /* Kick off polling */
}
/* Key now is configured */
HalKeyConfigured = TRUE;
#endif /* HAL_KEY */
}
这里终于看到了回调函数OnBoard_KeyCallback。
该回调函数也在该文件中,原型如下:
void OnBoard_KeyCallback ( uint8 keys, uint8 state )
{
uint8 shift;
shift = (OnboardKeyIntEnable == HAL_KEY_INTERRUPT_ENABLE) ? false : ((keys & HAL_KEY_SW_6) ? true : false);
………
}
这里的任务是给shift赋值,回调函数就这样提供给上层一个接口,使得下层数据能传输给上层。
好了,执行完初始化以后,osal_start_system()把所有任务交给操作系统去控制。
2.中断执行
一旦有中断发生,中断函数首先跳转到
HAL_ISR_FUNCTION( halKeyPort0Isr, P0INT_VECTOR )
{
halProcessKeyInterrupt();
………
}
然后执行halProcessKeyInterrupt();
void halProcessKeyInterrupt (void)
{
#if (HAL_KEY == TRUE)
bool valid=FALSE;
#if defined (HAL_KEY_SW_5_ENABLE)
if (HAL_KEY_SW_5_PXIFG & HAL_KEY_SW_5_BIT) /*判断中断标志位有效*/
{
HAL_KEY_SW_5_PXIFG = ~(HAL_KEY_SW_5_BIT); /* 清除中断标志位*/
valid = TRUE;
}
#endif
if (valid)
{
osal_start_timerEx (Hal_TaskID, HAL_KEY_EVENT, HAL_KEY_DEBOUNCE_VALUE);
}//然后把该事件传递给任务Hal,由Hal_ProcessEvent()处理。我们看看这个任务干了些什么:
uint16 Hal_ProcessEvent( uint8 task_id, uint16 events )
{
……
if (events & HAL_KEY_EVENT)
{
#if (defined HAL_KEY) && (HAL_KEY == TRUE)
/* Check for keys */
HalKeyPoll();//调用了这个函数
……
#endif // HAL_KEY
return events ^ HAL_KEY_EVENT;
……
}
看看HalKeyPoll()做了什么
void HalKeyPoll (void)
{
#if (HAL_KEY == TRUE)
uint8 keys = 0;
……
#if defined (HAL_KEY_SW_5_ENABLE)
if (HAL_KEY_SW_5_PORT & HAL_KEY_SW_5_BIT) /* Keys得到了按键的值 */
{
keys |= HAL_KEY_SW_5;
}
#endif
……
/* 使用回调函数,如果keys的值改变了的话*/
if (keys && (pHalKeyProcessFunction))
{
(pHalKeyProcessFunction) (keys, HAL_KEY_STATE_NORMAL);//也就是调用OnBoard_KeyCallback()函数
}
#endif /* HAL_KEY */
}
这个回调函数的意义,它的任务是要把任务HAL里的keys值变化情况作为一个消息传递给任务sampple,通过shift这个变量的值。
3. 中断触发的按键消息的传递
刚才在执行的一直是任务HAL,先在讲讲究竟是怎么养通过回调函数把消息传递给任务sampple的。
继续看回调函数:
void OnBoard_KeyCallback ( uint8 keys, uint8 state )
{
uint8 shift;
shift = (OnboardKeyIntEnable == HAL_KEY_INTERRUPT_ENABLE) ? false : ((keys & HAL_KEY_SW_6) ? true : false);
if ( OnBoard_SendKeys( keys, shift ) != ZSuccess )
//这里有很重要的一个函数OnBoard_SendKeys()
……
}
OnBoard_SendKeys()这个函数在文件Onboard.c中被定义了。原来它才是真正传递消息的函数。它的原型如下: 目的是发送按键的事件给相应的任务KEY_CHANGE
byte OnBoard_SendKeys( byte keys, byte 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;//发送KEY_CHANG这个事件标识符
msgPtr->state = state;
msgPtr->keys = keys;
osal_msg_send( registeredKeysTaskID, (uint8 *)msgPtr );
}
return ( ZSuccess );
}
else
return ( ZFailure );
}
注意:在void SampleApp_Init( uint8 task_id )有这样一句话:
RegisterForKeys( SampleApp_TaskID );它调用了onboard.c中的一个函数RegisterForKeys()完成任务对按键事件的注册工作,这里如果不注册的话在后来的程序里是不会产生KEY_CHANG这个事件。
byte RegisterForKeys( byte task_id )
{
// Allow only the first task
if ( registeredKeysTaskID == NO_TASK_ID )
{
registeredKeysTaskID = task_id;//注意这句话,就是给任务注册。和任务的ID号联系起来
return ( true );
}
else
return ( false );
}
这样就把任务和事件联系在了一起。
类型Keychange_t的格式如下:
typedef struct
{
osal_event_hdr_t hdr;
byte state; // shift
byte keys; // keys
} keyChange_t;
最后,调用了osal_msg_send()函数,在这个函数中,调用了
byte osal_msg_send( byte destination_task, byte *msg_ptr )
{
if ( msg_ptr == NULL )
return ( INVALID_MSG_POINTER );
if ( destination_task >= tasksCnt )
{
osal_msg_deallocate( msg_ptr );
return ( INVALID_TASK );
}
// Check the message header
if ( OSAL_MSG_NEXT( msg_ptr ) != NULL ||
OSAL_MSG_ID( msg_ptr ) != TASK_NO_TASK )
{
osal_msg_deallocate( msg_ptr );
return ( INVALID_MSG_POINTER );
}
OSAL_MSG_ID( msg_ptr ) = destination_task; //设置消息数据对应的那个任务
// queue message将要发送的消息数据链接到以osal_qHead开头的数据链表中
osal_msg_enqueue( &osal_qHead, msg_ptr );
// Signal the task that a message is waiting 通知主循环有任务等待处理
osal_set_event( destination_task, SYS_EVENT_MSG );
return ( ZSUCCESS );
}
在osal_set_event()函数中,设置了tasksEvents指针的值,然后在主循环中,不停的检测这个数组中的值,如果有变化,就调用任务号对应的事件处理函数,例如SampleApp_ProcessEvent()函数。这就是整个按键中断一步步运行到用户定义的任务事件处理函数中的过程,任务的id号和事件是紧密联系在一起的。通过前面的注册函数RegisterForKeys( SampleApp_TaskID )。
byte osal_set_event( byte task_id, UINT16 event_flag )
{
if ( task_id < tasksCnt )
{
halIntState_t intState;
HAL_ENTER_CRITICAL_SECTION(intState); // Hold off interrupts
tasksEvents[task_id] |= event_flag; // Stuff the event bit(s)
HAL_EXIT_CRITICAL_SECTION(intState); // Release interrupts
}
else
return ( INVALID_TASK );
return ( ZSUCCESS );
}