ZStack中OSAL按键事件的触发流程分析.docx
《ZStack中OSAL按键事件的触发流程分析.docx》由会员分享,可在线阅读,更多相关《ZStack中OSAL按键事件的触发流程分析.docx(12页珍藏版)》请在冰豆网上搜索。
ZStack中OSAL按键事件的触发流程分析
Z-Stack中OSAL按键事件的触发流程分析 2010-11-3010:
53:
04
分类:
嵌入式
首先在Main函数中,因为这是整个系统的入口点。
(1)Main函数
所有程序运行首先是在主函数下开始的,这里也不例外。
找到Zmain.c文件下的主函数:
ZSEGintmain(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中,原型如下
voidInitBoard(bytelevel)
{
if(level==OB_COLD)
{
这里执行第一次初始化的内容
}
else
}
(2)注释2:
这个函数在hal_drivers.c中
voidHalDriverInit(void)
{
………
#if(definedHAL_KEY)&&(HAL_KEY==TRUE)
HalKeyInit();
#endif
………..
}
HalKeyInit()这个函数在hal_key.c中
voidHalKeyInit(void)
{
#if(HAL_KEY==TRUE)
/*Initializepreviouskeyto0*/
halKeySavedKeys=0;
....................
#ifdefined(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;/*Setpininputmodeto三态*/
#endif
/*回调函数的初始化,赋值为NULL*/
pHalKeyProcessFunction =NULL;
/*按键还未经配置,赋值为FALSE*/
HalKeyConfigured=FALSE;
#endif/*HAL_KEY*/
}
总结:
这个函数基本完成了相应管脚的基本配置管脚的输入输出等等,给一些变量赋初值。
其中回调函数的定义是这样的
statichalKeyCBack_tpHalKeyProcessFunction;
那halKeyCBack_t是这样定义的
typedefvoid(*halKeyCBack_t)(uint8keys,uint8state);
也就是说它是一个函数的指针。
(3)注释4:
该函数在onboard.c中,原型如下
voidInitBoard(bytelevel)
{
if(level==OB_COLD)
{
//这里执行第一次初始化的内容
}
else//以下执行第二次初始化的内容
{
………
OnboardKeyIntEnable=HAL_KEY_INTERRUPT_DISABLE;
HalKeyConfig(OnboardKeyIntEnable,OnBoard_KeyCallback);
}
}
这里执行else后面的内容,这里调用了HalKeyConfig()函数,这个函数是按键的一些配置,
voidHalKeyConfig(boolinterruptEnable,halKeyCBack_tcback)
{
#if(HAL_KEY==TRUE)
/*Enable/DisableInterruptor*/
Hal_KeyIntEnable=interruptEnable;
/*Registerthecallbackfucntion*/
pHalKeyProcessFunction=cback; //这里给回调函数赋值
/*Determineifinterruptisenableornot*/
if(Hal_KeyIntEnable)
{
………………………………
#ifdefined(HAL_KEY_SW_5_ENABLE)
PICTL&=~(HAL_KEY_SW_5_EDGEBIT);/*Setrisingorfallingedge*/
#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; /*Setinterruptenablebit*/
HAL_KEY_SW_5_IEN|=HAL_KEY_SW_5_IENBIT;
HAL_KEY_SW_5_PXIFG=~(HAL_KEY_SW_5_BIT);/*Clearanypendinginterrupts*/
#endif
………………………………………………
/*Dothisonlyafterthehal_keyisconfigured-toworkwithsleepstuff*/
if(HalKeyConfigured==TRUE)
{
osal_stop_timerEx(Hal_TaskID,HAL_KEY_EVENT); /*Cancelpollingifactive*/
}
}
else /*InterruptsNOTenabled*/
{
#ifdefined(HAL_BOARD_CC2430DB)
#defineHAL_KEY_SW_5_ENABLE /*AllowSW5onlywhenkeyinterruptisdisable*/
#endif
#ifdefined(HAL_KEY_SW_6_ENABLE)
HAL_KEY_SW_6_ICTL&=~(HAL_KEY_SW_6_ICTLBIT); /*Clearinterruptenablebit*/
HAL_KEY_SW_6_IEN&=~(HAL_KEY_SW_6_IENBIT);
#endif
#ifdefined(HAL_KEY_SW_5_ENABLE)
HAL_KEY_SW_5_ICTL&=~(HAL_KEY_SW_5_ICTLBIT); /*Clearinterruptenablebit*/
HAL_KEY_SW_5_IEN&=~(HAL_KEY_SW_5_IENBIT);
#endif
osal_start_timerEx(Hal_TaskID,HAL_KEY_EVENT,HAL_KEY_POLLING_VALUE); /*Kickoffpolling*/
}
/*Keynowisconfigured*/
HalKeyConfigured=TRUE;
#endif /*HAL_KEY*/
}
这里终于看到了回调函数OnBoard_KeyCallback。
该回调函数也在该文件中,原型如下:
voidOnBoard_KeyCallback(uint8keys,uint8state)
{
uint8shift;
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();
voidhalProcessKeyInterrupt(void)
{
#if(HAL_KEY==TRUE)
bool valid=FALSE;
#ifdefined(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()处理。
我们看看这个任务干了些什么:
uint16Hal_ProcessEvent(uint8task_id,uint16events)
{
……
if(events&HAL_KEY_EVENT)
{
#if(definedHAL_KEY)&&(HAL_KEY==TRUE)
/*Checkforkeys*/
HalKeyPoll();//调用了这个函数
……
#endif//HAL_KEY
returnevents^HAL_KEY_EVENT;
……
}
看看HalKeyPoll()做了什么
voidHalKeyPoll(void)
{
#if(HAL_KEY==TRUE)
uint8keys=0;
……
#ifdefined(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的。
继续看回调函数:
voidOnBoard_KeyCallback(uint8keys,uint8state)
{
uint8shift;
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
byteOnBoard_SendKeys(bytekeys,bytestate)
{
keyChange_t*msgPtr;
if(registeredKeysTaskID!
=NO_TASK_ID )//注意这里,判断有没有事先注册事件
{
//Sendtheaddresstothetask如果相应的任务已经被注册到按键中,那么发送该消息到那个任务
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);
}
注意:
在voidSampleApp_Init(uint8task_id)有这样一句话:
RegisterForKeys(SampleApp_TaskID);它调用了onboard.c中的一个函数RegisterForKeys()完成任务对按键事件的注册工作,这里如果不注册的话在后来的程序里是不会产生KEY_CHANG这个事件。
byteRegisterForKeys(bytetask_id)
{
//Allowonlythefirsttask
if(registeredKeysTaskID==NO_TASK_ID)
{
registeredKeysTaskID=task_id;//注意这句话,就是给任务注册。
和任务的ID号联系起来
return(true);
}
else
return(false);
}
这样就把任务和事件联系在了一起。
类型Keychange_t的格式如下:
typedefstruct
{
osal_event_hdr_thdr;
byte state;//shift
byte keys; //keys
}keyChange_t;
最后,调用了osal_msg_send()函数,在这个函数中,调用了
byteosal_msg_send(bytedestination_task,byte*msg_ptr)
{
if(msg_ptr==NULL)
return(INVALID_MSG_POINTER);
if(destination_task>=tasksCnt)
{
osal_msg_deallocate(msg_ptr);
return(INVALID_TASK);
}
//Checkthemessageheader
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;//设置消息数据对应的那个任务
//queuemessage将要发送的消息数据链接到以osal_qHead开头的数据链表中
osal_msg_enqueue(&osal_qHead,msg_ptr);
//Signalthetaskthatamessageiswaiting通知主循环有任务等待处理
osal_set_event(destination_task,SYS_EVENT_MSG);
return(ZSUCCESS);
}
在osal_set_event()函数中,设置了tasksEvents指针的值,然后在主循环中,不停的检测这个数组中的值,如果有变化,就调用任务号对应的事件处理函数,例如SampleApp_ProcessEvent()函数。
这就是整个按键中断一步步运行到用户定义的任务事件处理函数中的过程,任务的id号和事件是紧密联系在一起的。
通过前面的注册函数RegisterForKeys(SampleApp_TaskID)。
byteosal_set_event(bytetask_id,UINT16event_flag)
{
if(task_id {
halIntState_t intState;
HAL_ENTER_CRITICAL_SECTION(intState); //Holdoffinterrupts
tasksEvents[task_id]|=event_flag; //Stufftheeventbit(s)
HAL_EXIT_CRITICAL_SECTION(intState); //Releaseinterrupts
}
else
return(INVALID_TASK);
return(ZSUCCESS);
}