收藏 分享(赏)

ZigBee协议栈任务处理分析笔记.doc

上传人:scg750829 文档编号:6782952 上传时间:2019-04-22 格式:DOC 页数:11 大小:63KB
下载 相关 举报
ZigBee协议栈任务处理分析笔记.doc_第1页
第1页 / 共11页
ZigBee协议栈任务处理分析笔记.doc_第2页
第2页 / 共11页
ZigBee协议栈任务处理分析笔记.doc_第3页
第3页 / 共11页
ZigBee协议栈任务处理分析笔记.doc_第4页
第4页 / 共11页
ZigBee协议栈任务处理分析笔记.doc_第5页
第5页 / 共11页
点击查看更多>>
资源描述

1、ZigBee 协议栈任务处理分析笔记-(转载请注明出处 )Everhuai 写于 2011-11-17弄了这么久 ZigBee 协议栈,今天终于有一点头绪了,基本上知道了整个系统任务怎么被添加,又是怎么被切换的一个过程。下面就简单讲一讲这部分内容。首先看的当然是 main()函数,不过这个函数不是今天的重点,里面有我添加的注释,先就一笔带过吧。int main( void )/ Turn off interruptsosal_int_disable( INTS_ALL );/关闭全局中断 EA=0,初始化过程不响应任何中断/ Initialization for board related s

2、tuff such as LEDsHAL_BOARD_INIT();/配置了时钟、LED、串口/ Make sure supply voltage is high enough to runzmain_vdd_check();/检查电源电压/ Initialize stack memoryzmain_ram_init();/初始化堆内存/ Initialize board I/O /初始化板子用到的 IO 口InitBoard( OB_COLD );/ Initialze HAL driversHalDriverInit();/初始化外设/ Initialize NV System /系统初始

3、化osal_nv_init( NULL );/ Initialize basic NV items/任务初始化zgInit();/ Initialize the MACZMacInit();/ Determine the extended address /确定长地址zmain_ext_addr();#ifndef NONWK/ Since the AF isnt a task, call its initialization routineafInit();#endif/ Initialize the operating systemosal_init_system(); /系统初始化/ A

4、llow interruptsosal_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_SUPPORTEDzmain_lcd_init(); /显示信息#endif#ifdef WDT_IN_PM1/* If WDT is use

5、d, this is a good place to enable it. */WatchDogEnable( WDTIMX ); /使用看门狗#endifosal_start_system(); / No Return from here/正常情况下不返回/ Shouldnt get herereturn ( 0 ); / main()其中含有 osal 的都是与操作系统相关的。这里主要提一下这些函数:/ Initialze HAL driversHalDriverInit();/初始化外设片内外设与片外外设基本上在这个函数中初始化,像 Timer、DMA、LCD 等。该函数调用后设备即可使

6、用。/ Initialize basic NV itemszgInit();这个函数通过调用/ Initialize the items tablezgInitItems( setDefault );初始化了 zgItemTable/ZGlobal Item Table我反正没搞懂这个数组干嘛用的,至少跟我们今天讨论的任务没有关系。我们讨论的任务在 / Initialize the operating systemosal_init_system();函数中调用 osalInitTasks()进行初始化,在该函数中为每一个任务分配了一个 ID 号,这个 ID 号在任务切换的时候将用到。该函数中

7、的初始化函数的顺序与函数指针数组const pTaskEventHandlerFn tasksArr中对应的任务的顺序是一致的,这一点不难理解,就是为了保证任务与 ID 号的对应。该函数中还有这么两天语句值得注意:tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt);/申请空间,用于存放任务osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt); /用 0 初始化申请到的空间tasksEvents 是一个指针,C 语言好的不用看它的定义都看得出来。任

8、务切换的时候就是通过 tasksEvents 来查找需要处理的任务。tasksEvents 指向的对象保存的是对应任务的掩码。最后通过调用函数 osal_start_system(); /* No Return from here*/启动操作系统,该函数正常情况下是不返回的。#if !defined ( ZBIT ) ;) / Forever Loop#endif然后所有的任务都在这个 for 循环中被处理:uint8 idx = 0;osalTimeUpdate();/定时器任务更新/轮询处理Hal_ProcessPoll(); / This replaces MT_SerialPoll()

9、 and osal_check_timer().do if (tasksEventsidx) / Task is highest priority that is ready./查找优先级最高的任务break; while (+idx timeout timeout = 0;elsesrchTimer-timeout = srchTimer-timeout - updateTime;/ When timeout or delete (event_flag = 0)/需要处理的事件if ( srchTimer-timeout = 0 | srchTimer-event_flag = 0 )/ T

10、ake out of listif ( prevTimer = NULL )timerHead = srchTimer-next;elseprevTimer-next = srchTimer-next;/ Setup to free memory/设置要被释放的资源freeTimer = srchTimer;/ NextsrchTimer = srchTimer-next;else/ Get next/下一个任务prevTimer = srchTimer;srchTimer = srchTimer-next;HAL_EXIT_CRITICAL_SECTION( intState ); / Re

11、-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* r

12、eturn 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 ru

13、ns 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

14、 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./

15、计算已经消耗的时间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、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;/

17、Convert the 320 us ticks into milliseconds and a remainderelapsedMSec += tmp / 25;remUsTicks = tmp % 25;/ Update OSAL Clock and Timers/更新系统定时器if ( elapsedMSec )osalClockUpdate( elapsedMSec );/更新系统时间osalTimerUpdate( elapsedMSec );/更新定时器任务,并设置需要处理的任务的掩码标志都是跟定时器相关的。在函数 osalTimerUpdate 开头定义了两个指针:osalTim

18、erRec_t *srchTimer;osalTimerRec_t *prevTimer;其结构 osalTimerRec_t 定义为typedef structvoid *next;uint16 timeout;uint16 event_flag;uint8 task_id; osalTimerRec_t;操作一个单向链表,链表头为 timerHead,该链表中保存了所有需要定时执行的任务。这些任务在函数 osalTimerRec_t * osalAddTimer( uint8 task_id, uint16 event_flag, uint16 timeout )中被创建。而该函数(只)被

19、 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/添加定时器任务new

20、Timer = 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 中的掩码。通过函数

21、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 )o

22、sal_set_event( freeTimer-task_id, freeTimer-event_flag );/时间到了,设置事件标志以等待处理osal_mem_free( freeTimer );/释放该定时器任务的资源看到没,最后还是调用函数 osal_set_event()对 tasksEvents 进行更改。当一个任务处理完毕时在主循环中清除相应的掩码。当然当一开始进入函数 osal_start_system()中时,应该是没有任务的,这个时候任务是通过中断层层调用,最后还是调用函数 osal_set_event()添加任务。在 ZigBee 协议栈中,中断函数是通过宏来实现的。这

23、些宏在 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_

24、DECLARATION(f,v)当需要编写一个中断函数实体时使用宏 HAL_ISR_FUNCTION(f,v),如:HAL_ISR_FUNCTION( halKeyPort0Isr, P0INT_VECTOR )/P0 口中断服务函数if (HAL_KEY_SW_6_PXIFG /*Clear the CPU interrupt flag for Port_0PxIFG has to be cleared before PxIF*/清除中断标志HAL_KEY_SW_6_PXIFG = 0;HAL_KEY_CPU_PORT_0_IF = 0;HAL_ISR_FUNCTION( halTimer1

25、Isr, 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

26、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 /* Clear Interrupt Flag */valid = TRUE;if (HAL_KEY_SW_7_PXIFG /* Clear Interrupt Flag

27、 */valid = TRUE;if (HAL_KEY_JOY_MOVE_PXIFG /* Clear Interrupt Flag */valid = TRUE;if (valid)/添加定时器任务osal_start_timerEx (Hal_TaskID, HAL_KEY_EVENT, HAL_KEY_DEBOUNCE_VALUE);/使用定时器定时触发任务不知道你是否还记得这个函数:osal_start_timerEx(),在这个函数中添加了一个定时任务,其中 ID 号就不用我多说了,HAL_KEY_EVENT 是将要被添加到 tasksEvents 的任务的掩码,HAL_KEY_DE

28、BOUNCE_VALUE 则是用来进行消抖的一个时间值。用过单片机的都知道当按键按下时会产生抖动,而通常消抖的方法是延时。所以我们也可以知道在这里产生 IO 口中断的是按键。如果使用 IO 口中断来读其它设备则可以根据实际情况读或调用函数 osal_set_event()对添加任务。当然并不是每个中断都必须添加对应的任务,如定时器中断。在中断服务函数中是否添加对应的任务应视具体情况而定。下面对 ZigBee 协议栈对事件的处理做一个总结。在 ZigBee 协议栈中处理事件有三种方式:轮询、中断、 (操作系统)任务。其中轮询与中断学过单片机的都用过,在这就不必多说了。唯独任务(至少我所了解的)是

29、操作系统才有的概念。使用任务处理事件就需要在一个事件产生时添加任务,在任务处理完毕时删除任务,还需要在不同任务间进行切换。在 ZigBee 协议栈中 tasksEvents 是一个任务是否存在的标志,当需要添加任务时通过调用函数 osal_set_event()在 tasksEvents 中添加相应的掩码,当任务处理完毕时直接把相应的掩码清零即可。而任务切换则必须等到前一个任务处理完毕,并且没有优先级更高的任务时才被处理。而优先级是由数组 tasksArr的成员的顺序决定的。在一些比较强大的操作系统当中这些东西都有,当然是会有所区别的,只不过要复杂得多,并且引入了一些新的概念像 PCB、任务调度、进程、线程等,其中任务调度我的理解就是任务切换。像这些东西我所知道的与不知道的讲也讲不完,就并不多说了,还是回到我们的话题。在 ZigBee 协议栈中任务的处理总结起来就一句话:任何一个任务都只有调用了函数osal_set_event()之后才能被处理。当然事件与任务不是一回事,任务同中断一样只是处理事件的一种方式。而且通常是先有事件然后注册一个与事件对应的任务。没有事件当然也可以注册任务,不过这又有点扯远了。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报