任务处理表taskEvents的处理有几种方式,记录下来完了可以来翻阅,哈哈。。。。
总的来说,添加任务都是通过OSAL.C》》uint8 osal_set_event( uint8 task_id, uint16 event_flag )添加的,那么在什么地方可以触发这个呢?
一、设置计时器,当其溢出时,触发事件处理
首先任何程序都是从main函数开始的::
int main( void )
{
// Turn off interrupts
osal_int_disable( INTS_ALL ); //关闭所有中断
// Initialization for board related stuff such as LEDs
HAL_BOARD_INIT(); //初始化系统时钟
// Make sure supply voltage is high enough to run
zmain_vdd_check(); //检查芯片电压是否正常
// Initialize board I/O
InitBoard( OB_COLD ); //初始化 I/O , LED 、 Timer 等
// Initialze HAL drivers
HalDriverInit(); //初始化芯片各硬件模块
// Initialize NV System
osal_nv_init( NULL ); // 初始化 Flash 存储器
// Initialize the MAC
ZMacInit(); //初始化 MAC 层
// Determine the extended address
zmain_ext_addr(); //确定 IEEE 64 位地址
#if defined ZCL_KEY_ESTABLISH
// Initialize the Certicom certificate information.
zmain_cert_init();
#endif
// Initialize basic NV items
zgInit(); // 初始化非易失变量
#ifndef NONWK
// Since the AF isn't a task, call it's initialization routine
afInit();
#endif
// Initialize the operating system
osal_init_system(); // 初始化操作系统--重点关注
// Allow interrupts
osal_int_enable( INTS_ALL ); // 使能全部中断
// Final board initialization
InitBoard( OB_READY ); // 初始化按键
// Display information about this device
zmain_dev_info(); //显示设备信息
/* Display the device info on the LCD */
#ifdef LCD_SUPPORTED
zmain_lcd_init();
#endif
#ifdef WDT_IN_PM1
/* If WDT is used, this is a good place to enable it. */
WatchDogEnable( WDTIMX );
#endif
osal_start_system(); // No Return from here进入操作系统,轮询不在跳出
return 0; // Shouldn't get here.
} // main()
进入函数: osal_start_system(); ------转----osal_run_system();
/*********************************************************************
* @fn osal_run_system
*
* @brief
*
* This function will make one pass through the OSAL taskEvents table
* and call the task_event_processor() function for the first task that
* is found with at least one event pending. If there are no pending
* events (all tasks), this function puts the processor into Sleep.
*
* @param void
*
* @return none
*/
void osal_run_system( void )
{
uint8 idx = 0;
osalTimeUpdate(); //该文重要地方,在这里扫描那个时间被触发,并置相应位
Hal_ProcessPoll();
do {
if (tasksEvents[idx]) // Task is highest priority that is ready.
{
break; //得到待处理的最高优先级任务索引号 idx
}
} while (++idx < tasksCnt);
if (idx < tasksCnt)
{
uint16 events;
halIntState_t intState;
HAL_ENTER_CRITICAL_SECTION(intState); // 进入临界区,保护
events = tasksEvents[idx]; //提取需要处理的任务中的事件
tasksEvents[idx] = 0; // Clear the Events for this task.
HAL_EXIT_CRITICAL_SECTION(intState); // 退出临界区
activeTaskID = idx;
events = (tasksArr[idx])( idx, events ); //通过指针调用任务处理函数
activeTaskID = TASK_NO_TASK;
HAL_ENTER_CRITICAL_SECTION(intState); // 进入临界区,保护
tasksEvents[idx] |= events//Add back unprocessed events to the current task.
HAL_EXIT_CRITICAL_SECTION(intState); // 退出临界区
}
#if defined( POWER_SAVING )
else // Complete pass through all task events with no activity?
{
osal_pwrmgr_powerconserve(); // Put the processor/system into sleep
}
#endif
/* Yield in case cooperative scheduling is being used. */
#if defined (configUSE_PREEMPTION) && (configUSE_PREEMPTION == 0)
{
osal_task_yield();
}
#endif
}
进入函数:osalTimeUpdate();------转--------osalTimerUpdate( elapsedMSec );
第二个方式也从这里开始,events = (tasksArr[idx])( idx, events );进入tasksArr[idx]列表中
/*********************************************************************
* @fn osalTimerUpdate
*
* @brief Update the timer structures for a timer tick.
*
* @param none
*
* @return none
*********************************************************************/
void osalTimerUpdate( uint16 updateTime )
{
halIntState_t intState;
osalTimerRec_t *srchTimer;
osalTimerRec_t *prevTimer;
HAL_ENTER_CRITICAL_SECTION( intState ); // Hold off interrupts.
// Update the system time
osal_systemClock += updateTime;
HAL_EXIT_CRITICAL_SECTION( intState ); // Re-enable interrupts.
// Look for open timer slot
if ( timerHead != NULL )
{
// Add it to the end of the timer list
srchTimer = timerHead;
prevTimer = (void *)NULL;
// Look for open timer slot
while ( srchTimer )
{
osalTimerRec_t *freeTimer = NULL;
HAL_ENTER_CRITICAL_SECTION( intState ); // Hold off interrupts.
if (srchTimer->timeout <= updateTime)
{
srchTimer->timeout = 0;
}
else
{
srchTimer->timeout = srchTimer->timeout - updateTime;
}
// Check for reloading
if ( (srchTimer->timeout == 0) && (srchTimer->reloadTimeout) && (srchTimer->event_flag) )
{
// Notify the task of a timeout
//就在这里了,那么他是怎么触发的呢?
osal_set_event( srchTimer->task_id, srchTimer->event_flag );
// Reload the timer timeout value
srchTimer->timeout = srchTimer->reloadTimeout;
}
// When timeout or delete (event_flag == 0)
if ( srchTimer->timeout == 0 || srchTimer->event_flag == 0 )
{
// Take out of list
if ( prevTimer == NULL )
timerHead = srchTimer->next;
else
prevTimer->next = srchTimer->next;
// Setup to free memory
freeTimer = srchTimer;
// Next
srchTimer = srchTimer->next;
}
else
{
// Get next
prevTimer = srchTimer;
srchTimer = srchTimer->next;
}
HAL_EXIT_CRITICAL_SECTION( intState ); // Re-enable interrupts.
if ( freeTimer )
{
if ( freeTimer->timeout == 0 )
{
//就在这里了,那么他是怎么触发的呢?
osal_set_event( freeTimer->task_id, freeTimer->event_flag );
}
osal_mem_free( freeTimer );
}
}
}
}
从上面看,似乎找到了源头,那么怎么才能触发呢?那么就得介绍一个函数了:OSAL_Timers.c》》uint8 osal_start_timerEx( uint8 taskID, uint16 event_id, uint16 timeout_value )
/*********************************************************************
* @fn osal_start_timerEx
*
* @brief
*
* This function is called to start a timer to expire in n mSecs.
* When the timer expires, the calling task will get the specified event.
*
* @param uint8 taskID - task id to set timer for
* @param uint16 event_id - event to be notified with
* @param UNINT16 timeout_value - in milliseconds.
*
* @return SUCCESS, or NO_TIMER_AVAIL.
*/
uint8 osal_start_timerEx( uint8 taskID, uint16 event_id, uint16 timeout_value )
{
halIntState_t intState;
osalTimerRec_t *newTimer;
HAL_ENTER_CRITICAL_SECTION( intState ); // Hold off interrupts.
// Add timer----------------------------------------------------------
newTimer = osalAddTimer( taskID, event_id, timeout_value );
//-------------------------------------------------------------------
HAL_EXIT_CRITICAL_SECTION( intState ); // Re-enable interrupts.
return ( (newTimer != NULL) ? SUCCESS : NO_TIMER_AVAIL );
}
在这个函数中,它会开始一个timeout_value(ms)的计时器,当这个计时器溢出时,则会对taskID这个task,设置一个event_id,让这个任务在后面的主循环中运行到,但是是怎么实现的呢?还是要请osalTimerUpdate来帮忙。。。
这个就总结到这吧,其实后面我也不是很懂,看的迷迷糊糊的,在后面我会帖上出处,,,
二、直接通过任务间的消息传递机制触发(以按键为例)
本文前面有介绍从哪里进入,,,,events = (tasksArr[idx])( idx, events );进入tasksArr[idx]列表中
本文前面有介绍从哪里进入,,,,events = (tasksArr[idx])( idx, events );进入tasksArr[idx]列表中
然后进入函数:Hal_ProcessEvent,可以找到检查按键的函数:HalKeyPoll();
/**************************************************************************************************
* @fn HalKeyPoll
*
* @brief Called by hal_driver to poll the keys
*
* @param None
*
* @return None
**************************************************************************************************/
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;
}
//在HalKeyPoll函数中,无论按键是ADC方式,或者是扫描IO口的方式,
//最后都会生成一个键值keys, 然后通过下面的语句来调用按键服务程序
/* Invoke Callback if new keys were depressed */
if (keys && (pHalKeyProcessFunction))
{
(pHalKeyProcessFunction) (keys, HAL_KEY_STATE_NORMAL);
}
}
(pHalKeyProcessFunction) (keys, HAL_KEY_STATE_NORMAL);这句话我刚开始看起来很奇怪,后来看懂了作者的意思,原来在主函数初始化InitBoard( OB_READY );中有这么一个函数:HalKeyConfig(HAL_KEY_INTERRUPT_DISABLE, OnBoard_KeyCallback);进入这个函数可以看到
<span style="font-size:14px;">void HalKeyConfig (bool interruptEnable, halKeyCBack_t cback)
{
/* Enable/Disable Interrupt or */
Hal_KeyIntEnable = interruptEnable;
/* Register the callback fucntion */
pHalKeyProcessFunction = cback;
。。。。。。。。
}</span>
这就间接的把pHalKeyProcessFunction初始化成OnBoard_KeyCallback了;接下来的事就让OnBoard_KeyCallback完成了,等哈继续往下面看。。。。。。
在void HalKeyConfig (bool interruptEnable, halKeyCBack_t cback)上面有个函数void HalKeyInit( void )里面有句 pHalKeyProcessFunction = NULL;我瞬间就看不懂了,,,后来才发现这两个函数都优先级不一样。。。
接着往下看,让OnBoard_KeyCallback完成了,那么就进入OnBoard_KeyCallback会发现有这么个判断语句if ( OnBoard_SendKeys( keys, shift ) != ZSuccess )直接深入OnBoard_SendKeys就可以发现osal_msg_send向上级应用程序发送消息的
额,我的记录就到这了,本文只代表个人观点,出错概不负责,不过也希望看到这里的朋友评价其中的错误或者你的更高深的理解,附录:http://bbs.feibit.com/thread-16-1-1.html
修改,最近在网上看到一个比较好的文章,他直接用图片的形式展示出来了,
http://wenku.baidu.com/view/ef12e01d10a6f524ccbf85fb.html 如果资料被删除,请联系我,我这里有备份。。。。。