UCOSII从V2.83版本以后,加入了软件定时器,这使得UCOSII的功能更加完善,在其上的应用程序开发与移植也更加方便。在实时操作系统中一个好的软件定时器实现要求有较高的精度、较小的处理器开销,且占用较少的存储器资源。
ucosII关于定时器的内容在os_tmr.c文件内,需使能os_cfg.h中的OS_CFG_TMR_EN来启动定时器服务。
定时器服务为在协议栈处理,IO定时轮询的设备中提供了很大的方便。
1)软件定时器工作原理
软件定时器同样由OSTimTick提供时钟,但是软件定时器的时钟还OS_TMR_CFG_TICKS_PER_SEC设置的控制,也就是在UCOSII的时钟节拍上面再做了一次“分频”,软件定时器的最快时钟节拍就等于UCOSII的系统时钟节拍。这也决定了软件定时器的精度。
定时时间一到,则系统会调用用户函数实现特定功能。
2)软件定时器在ucos_ii的实现原理
UCOSII中软件定时器的实现方法是,将定时器按定时时间分组,使得每次时钟节拍到来时只对部分定时器进行比较操作,缩短了每次处理的时间。但这就需要动态地维护一个定时器组。定时器组的维护只是在每次定时器到时时才发生,而且定时器从组中移除和再插入操作不需要排序。这是一种比较高效的算法,减少了维护所需的操作时间。
UCOSII软件定时器实现了3类链表的维护:
OS_EXT OS_TMR OSTmrTbl[OS_TMR_CFG_MAX]; //定时器控制块数组
OS_EXT OS_TMR *OSTmrFreeList; //空闲定时器控制块链表指针
OS_EXT OS_TMR_WHEEL OSTmrWheelTbl[OS_TMR_CFG_WHEEL_SIZE]; //定时器轮
- 1
- 2
- 3
- 4
- 5
- 1
- 2
- 3
- 4
- 5
其中OS_TMR为定时器控制块,定时器控制块是软件定时器管理的基本单元,包含软件定时器的名称、定时时间、在链表中的位置、使用状态、使用方式,以及到时回调函数及其参数等基本信息。
OSTmrTbl[OS_TMR_CFG_MAX];:以数组的形式静态分配定时器控制块所需的RAM空间,并存储所有已建立的定时器控制块,OS_TMR_CFG_MAX为最大软件定时器的个数。
OSTmrFreeLiSt:为空闲定时器控制块链表头指针。空闲态的定时器控制块(OS_TMR)中,OSTmrNext和OSTmrPrev两个指针分别指向空闲控制块的前一个和后一个,组织了空闲控制块双向链表。建立定时器时,从这个链表中搜索空闲定时器控制块。
OSTmrWheelTbl[OS_TMR_CFG_WHEEL_SIZE]:该数组的每个元素都是已开启定时器的一个分组,元素中记录了指向该分组中第一个定时器控制块的指针,以及定时器控制块的个数。运行态的定时器控制块(OS_TMR)中,OSTmrNext和OSTmrPrev两个指针同样也组织了所在分组中定时器控制块的双向链表。软件定时器管理所需的数据结构示意图如图所示
如果使能了定时器服务,在ucos初始化的时候,系统便自动创建了一个任务OSTmr_Task(),每次节拍到达便判断相应定时轮中定时器的定时是否到达,如果到达则调用相应的回调函数。
3)软件定时器在ucosII的实现过程
软件定时器由硬件定时器提供基准Tr,可以通过宏定义OS_TMR_CFG_TICKS_PER_SECOND对硬件定时器节拍进行分频即软件定时器时钟节拍为 Tr*OS_TMR_CFG_TICKS_PER_SECOND。
硬件定时器节拍时刻到后触发中断。如果使能了定时器服务,在SysTic_Handler()中断函数中通过一系列调用,最后到执行到OSTimeTickhook()函数,在该函数中会判断该时刻是否是软件定时器的节拍时刻,如果是,则通过释放一个信号量OSTmrSemSignal来激活正在等待改信号量的OSTmrTask()任务。
在ucos初始化的时候,系统便自动创建了一个任务OSTmr_Task(),其优先级,堆栈大小等于任务相关的参数在os_cfg.h中定义。在OSTmr_Task()任务中等待OSTmrSemSignal信号量。并定义了一个变量OSTimTick来计时软件定时器的节拍。OSTmrSemSignal信号量一旦有效OSTimTick便加1并判断相应定时轮中定时器的定时是否到达,如果到达则调用相应的回调函数完成定时器操作。
4)使用软件定时器
在ucos_ii.h中,声明了下面8个函数供用户使用。
OSTmrCreate();
OSTmrDel();
OSTmrNameGet();
OSTmrRemainGet();
OSTmrStateGet();
OSTmrStart();
OSTmrStop();
OSTmrSignal();
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
1、定时器任务参数配置
定时任务有OSInit()在初始化时创建,其优先级,堆栈大小等于任务相关的参数在os_cfg.h中定义。用户可通过项目实际需求修改相应参数。
2、创建定时器
OS_TMR *OSTmrCreate (INT32U dly,
INT32U period,
INT8U opt,
OS_TMR_CALLBACK callback,
void *callback_arg,
INT8U *pname,
INT8U *perr)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
3、编写回调函数
typedef void (*OS_TMR_CALLBACK)(void *ptmr, void *parg);
- 1
- 1
4、启动定时器
BOOLEAN OSTmrStart ( OS_TMR *ptmr,
INT8U *perr)
- 1
- 2
- 1
- 2
5、关于回调函数
回调函数执行时所用到的堆栈是是定时器任务堆栈,所以要确保分配的定时器任务堆栈大小能够满足回调函数的堆栈要求回调函数的执行是根据它们在定时器链表中的位置先后执行(一个定时器只能执行一个回调函数)。
定时器任务的执行时间极大程度是有溢出的定时器个数和回调函数执行时间决定。回调函数执行期间,调度是处于被锁状态,所以回调函数越快执行越好,更不要去在回调函数中去等待事件。