ZigBee协议栈任务处理分析笔记.doc_第1页
ZigBee协议栈任务处理分析笔记.doc_第2页
ZigBee协议栈任务处理分析笔记.doc_第3页
ZigBee协议栈任务处理分析笔记.doc_第4页
ZigBee协议栈任务处理分析笔记.doc_第5页
已阅读5页,还剩6页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

ZigBee协议栈任务处理分析笔记 -(转载请注明出处 774910349)Everhuai写于2011-11-17弄了这么久ZigBee协议栈,今天终于有一点头绪了,基本上知道了整个系统任务怎么被添加,又是怎么被切换的一个过程。下面就简单讲一讲这部分内容。首先看的当然是main()函数,不过这个函数不是今天的重点,里面有我添加的注释,先就一笔带过吧。int main( void ) / Turn off interrupts osal_int_disable( INTS_ALL );/关闭全局中断EA=0,初始化过程不响应任何中断 / Initialization for board related stuff such as LEDs HAL_BOARD_INIT();/配置了时钟、LED、串口 / Make sure supply voltage is high enough to run zmain_vdd_check();/检查电源电压 / Initialize stack memory zmain_ram_init();/初始化堆内存 / Initialize board I/O/初始化板子用到的IO口 InitBoard( OB_COLD ); / Initialze HAL drivers HalDriverInit();/初始化外设 / Initialize NV System/系统初始化 osal_nv_init( NULL ); / Initialize basic NV items/任务初始化 zgInit(); / Initialize the MAC ZMacInit(); / Determine the extended address/确定长地址 zmain_ext_addr();#ifndef NONWK / Since the AF isnt a task, call its initialization routine afInit();#endif / Initialize the operating system osal_init_system();/系统初始化 / Allow interrupts osal_int_enable( INTS_ALL );/使能中断 / Final board initialization/后期初始化 InitBoard( OB_READY ); /sd rest / 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/正常情况下不返回 / Shouldnt get here return ( 0 ); / main()其中含有osal的都是与操作系统相关的。这里主要提一下这些函数: / Initialze HAL drivers HalDriverInit();/初始化外设片内外设与片外外设基本上在这个函数中初始化,像Timer、DMA、LCD等。该函数调用后设备即可使用。 / Initialize basic NV items zgInit();这个函数通过调用 / Initialize the items table zgInitItems( setDefault );初始化了zgItemTable/ZGlobal Item Table我反正没搞懂这个数组干嘛用的,至少跟我们今天讨论的任务没有关系。我们讨论的任务在 / Initialize the operating system osal_init_system();函数中调用osalInitTasks()进行初始化,在该函数中为每一个任务分配了一个ID号,这个ID号在任务切换的时候将用到。该函数中的初始化函数的顺序与函数指针数组const pTaskEventHandlerFn tasksArr中对应的任务的顺序是一致的,这一点不难理解,就是为了保证任务与ID号的对应。该函数中还有这么两天语句值得注意: tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt);/申请空间,用于存放任务 osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt);/用0初始化申请到的空间tasksEvents是一个指针,C语言好的不用看它的定义都看得出来。任务切换的时候就是通过tasksEvents来查找需要处理的任务。tasksEvents指向的对象保存的是对应任务的掩码。最后通过调用函数osal_start_system(); /* No Return from here*/启动操作系统,该函数正常情况下是不返回的。#if !defined ( ZBIT ) & !defined ( UBIT ) for(;) / Forever Loop#endif然后所有的任务都在这个for循环中被处理: uint8 idx = 0; osalTimeUpdate();/定时器任务更新/轮询处理 Hal_ProcessPoll(); / This replaces MT_SerialPoll() and osal_check_timer(). do if (tasksEventsidx) / Task is highest priority that is ready./查找优先级最高的任务 break; while (+idx tasksCnt);/tasksCnt为总的任务数 if (idx tasksCnt)/任务数检查 uint16 events; halIntState_t intState; HAL_ENTER_CRITICAL_SECTION(intState);/保存中断状态 events = tasksEventsidx;/取出任务后立即清除 tasksEventsidx = 0; / Clear the Events for this task. HAL_EXIT_CRITICAL_SECTION(intState);/恢复中断状态 events = (tasksArridx)( idx, events );/执行任务,返回值是未处理的事件的掩码 HAL_ENTER_CRITICAL_SECTION(intState); tasksEventsidx |= 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? /当任务ID号出错时进入睡眠 osal_pwrmgr_powerconserve(); / Put the processor/system into sleep #endif 当有任务需要处理时便调用函数osal_set_event()添加任务:/* * fn osal_set_event * * brief * * This function is called to set the event flags for a task. The * event passed in is ORd into the tasks event variable. *设置事件标志,这些事件保存到变量task * param uint8 task_id - receiving tasks ID * param uint8 event_flag - what event to set * * return SUCCESS, INVALID_TASK */uint8 osal_set_event( uint8 task_id, uint16 event_flag ) if ( task_id timeout timeout = 0; else srchTimer-timeout = srchTimer-timeout - updateTime; / 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 );/释放该定时器任务的资源 在我所使用的版本中该函数只被两个函数调用,分别是:/* * fn osal_adjust_timers * * brief Update the timer structures for elapsed ticks. * * param none * * return none */void osal_adjust_timers( void ) uint16 eTime; if ( timerHead != NULL ) / Compute elapsed time (msec) eTime = TimerElapsed() / TICK_COUNT; if ( eTime ) osalTimerUpdate( eTime ); /* * FUNCTIONS */* * fn osalTimeUpdate * * brief Uses the free running rollover count of the MAC backoff timer; * this timer runs freely with a constant 320 usec interval. The * count of 320-usec ticks is converted to msecs and used to update * the OSAL clock and Timers by invoking osalClockUpdate() and * osalTimerUpdate(). This function is intended to be invoked * from the background, not interrupt level. * * param None. * * return None. */void osalTimeUpdate( void )/定时器任务更新 uint16 tmp; uint16 ticks320us; uint16 elapsedMSec = 0; / Get the free-running count of 320us timer ticks/设置时间片 tmp = macMcuPrecisionCount();/获取溢出值,该溢出值是一个累计的溢出值 if ( tmp != previousMacTimerTick )/相等则代表没有溢出 / Calculate the elapsed ticks of the free-running timer./计算已经消耗的时间 ticks320us = tmp - previousMacTimerTick; / Store the MAC Timer tick count for the next time through this function. previousMacTimerTick = tmp;/保存当前时间 /* It is necessary to loop to convert the usecs to msecs in increments so as * not to overflow the 16-bit variables. *这是必要的循环转换usecs毫秒的增量,以免溢出16位变量。 */ while ( ticks320us MAXCALCTICKS ) ticks320us -= MAXCALCTICKS; elapsedMSec += MAXCALCTICKS * 8 / 25; remUsTicks += MAXCALCTICKS * 8 % 25; / update converted number with remaining ticks from loop and the / accumulated remainder from loop/更新转换从循环和循环积累的其余部分与其余蜱 tmp = (ticks320us * 8) + remUsTicks; / Convert the 320 us ticks into milliseconds and a remainder elapsedMSec += tmp / 25; remUsTicks = tmp % 25; / Update OSAL Clock and Timers/更新系统定时器 if ( elapsedMSec ) osalClockUpdate( elapsedMSec );/更新系统时间 osalTimerUpdate( elapsedMSec );/更新定时器任务,并设置需要处理的任务的掩码标志 都是跟定时器相关的。在函数osalTimerUpdate开头定义了两个指针: osalTimerRec_t *srchTimer; osalTimerRec_t *prevTimer;其结构osalTimerRec_t定义为typedef struct void *next; uint16 timeout; uint16 event_flag; uint8 task_id; osalTimerRec_t;操作一个单向链表,链表头为timerHead,该链表中保存了所有需要定时执行的任务。这些任务在函数osalTimerRec_t * osalAddTimer( uint8 task_id, uint16 event_flag, uint16 timeout )中被创建。而该函数(只)被uint8 osal_start_timerEx( uint8 taskID, uint16 event_id, uint16 timeout_value )调用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 );其中event_id跟函数uint8 osal_set_event( uint8 task_id, uint16 event_flag )中event_flag的作用是一样的,都是最后被写入到tasksEvents中的掩码。通过函数osal_set_event()更改tasksEvents: tasksEventstask_id |= event_flag; / Stuff the event bit(s)/添加需要处理的事件的掩码函数osal_start_timerEx使用结构osalTimerRec_t临时保存newTimer-event_flag = event_flag;最后通过在主循环中调用osalTimeUpdate()又调用osalTimerUpdate( elapsedMSec )最后通过代码 if ( freeTimer )/释放任务 if ( freeTimer-timeout = 0 ) osal_set_event( freeTimer-task_id, freeTimer-event_flag );/时间到了,设置事件标志以等待处理 osal_mem_free( freeTimer );/释放该定时器任务的资源 看到没,最后还是调用函数osal_set_event()对tasksEvents进行更改。当一个任务处理完毕时在主循环中清除相应的掩码。当然当一开始进入函数osal_start_system()中时,应该是没有任务的,这个时候任务是通过中断层层调用,最后还是调用函数osal_set_event()添加任务。在ZigBee协议栈中,中断函数是通过宏来实现的。这些宏在Hal_mcu.h文件中定义:#define _PRAGMA(x) _Pragma(#x)#define HAL_ISR_FUNC_DECLARATION(f,v) _PRAGMA(vector=v) _near_func _interrupt void f(void)#define HAL_ISR_FUNC_PROTOTYPE(f,v) _PRAGMA(vector=v) _near_func _interrupt void f(void)#define HAL_ISR_FUNCTION(f,v) HAL_ISR_FUNC_PROTOTYPE(f,v); HAL_ISR_FUNC_DECLARATION(f,v)当需要编写一个中断函数实体时使用宏HAL_ISR_FUNCTION(f,v),如:HAL_ISR_FUNCTION( halKeyPort0Isr, P0INT_VECTOR )/P0口中断服务函数 if (HAL_KEY_SW_6_PXIFG & HAL_KEY_SW_6_BIT)|(HAL_KEY_SW_7_PXIFG & HAL_KEY_SW_7_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;HAL_ISR_FUNCTION( halTimer1Isr, T1_VECTOR )/定时器1中断服务函数 halProcessTimer1 ();HAL_ISR_FUNCTION( macMcuRfIsr, RF_VECTOR )/RF中断服务函数只要对这些宏进行展开就得到了CC2530中断服务函数的形式。下面就通过来看一下中断服务函数是怎么添加任务的。在P0口中断服务函数中调用了这么一个函数halProcessKeyInterrupt(),该函数的实现如下:/* * fn halProcessKeyInterrupt * * brief Checks to see if its a valid key interrupt, saves interrupt driven key states for * processing by HalKeyRead(), and debounces keys by scheduling HalKeyRead() 25ms later. * * param * * return */void halProcessKeyInterrupt (void) bool valid=FALSE;/检查中断源 if (HAL_KEY_SW_6_PXIFG & HAL_KEY_SW_6_BIT) /* Interrupt Flag has been set */ HAL_KEY_SW_6_PXIFG = (HAL_KEY_SW_6_BIT); /* Clear Interrupt Flag */ valid = TRUE; if (HAL_KEY_SW_7_PXIFG & HAL_KEY_SW_7_BIT) /* Interrupt Flag has been set */ HAL_KEY_SW_7_PXIFG = (HAL_KEY_SW_7_BIT); /* Clear Interrupt Flag */ valid = TRUE; if (HAL_KEY_JOY_MOVE_PXIFG & HAL_KEY_JOY_MOVE_BIT) /* Interrupt Flag has been set */ HAL_KEY_JOY_MOVE_PXIFG = (HAL_KEY_JOY_MOVE_B

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论