嵌入式时钟管理器的设计方案与实现
ROM用量小,但效率较低(与定时器数目相关);后者逻辑复杂,ROM用量大,但效率较高(与定时器数目无关)。应用中使用哪种方案,可在configClk.h中配置选择。 2.3.1 静态数组法 静态数组法的数据结构如下: structwdNode{ BOOLflag;//标明本结点是否已被使用 UINT16ticks;//用以定时的节拍数 VOIDFUNCPTRrout;//定时到时需执行的操作 }datawdList[_MAX_WDOG_NUM_]; 其中:_MAX_WDOG_NUM_指出了系统中允许的最大定时器数,其值决定于应用需求及系统资源量,可在configClk.h中设定。一个定时器结点占用5B的RAM空间。具有给定数据结构的静态数组是方案实施的基础。 另外,该静态数组作为软件定时器的全局变量而存在,当系统中有多个定时器活动时,它们都将访问该全局静态数组。重要的是:它们的活动是异步的,所以,对该静态数组(临界资源)的访问需作临界保护。对于51系统,应采用开关中断的方式实现,且应确保不会影响关中断前的中断状态。 (1)用户接口定义 上述用户接口皆基于该静态数组进行,限于篇幅,这里给出关键接口wdStart的定义。 STATUSwdStart(WDOG_IDwdId,UINT16ticks, VOIDFUNCPTRwdr){ if(wdId_MAX_WDOG_NUM_){ if(wdList[wdId].flag){//判断给定定时器ID有效否 RTX_ENTER_CRITICAL();//进入临界区 wdList[wdId].ticks=ticks;//操作静态数组中的特定定时结点 wdList[wdId].rout=wdr; returnOK;//定时器启动成功 } } returnERROR;//给定定时器ID无效 } 调用该接口函数,即可启动已创建(wdCreate)的软件定时器。当经历ticks节拍后,给定函数wdr将被执行,以完成用户的定时需求。 (2)定时器守护例程 定时器守护例程wdDaemon被置于前述的钩子函数clkTick_ISR_hook中,以使其周期性执行。由于本例程自身的特点,它应作为clkTick_ISR_hook的最后一个调用函数。本例程是软件定时器实现的核心,而其关键又是对系统栈的调整,为说明其实现流程,给出了如图2所示的wdDaemon的栈(stack)结构。 由图2可知:wdDaemon的返回地址没有入栈,因其为clkTick_ISR_hook中的最后一个函数调用,故其返回地址被优化掉。wdDaemon将栈顶的8B数据上移2B,然后将定时器指定函数的地址插入腾出的栈空间(2B)中。如此,该地址将会被IRET弹入IP中。由于IRET指令的执行而使中断系统复位以重新响应外部中断,同时也使定时器指定函数在非中断态执行,从而不过分影响系统的响应速度。 2.3.2 delta列表法 delta列表法仅维护有效定时器的链表,且链表中的定时器结点按定时剩余时间由小到大排列,使距timeout点最近的定时器作为链表的首结点。链表中定时器结点的顺序由其独特的结点插入算法决定:如有5个定时器,其定时长度分别为10、14、21、32和39,当其组成delta列表时,定时值最小的结点为首结点,其定时存储值为10,而后依序排列,其定时存储值分别为4、7、11、7,即后一个定时器的定时存储值由自己的实际定时值与相邻的前一个定时器的实际定时值相减而得。可见,除首结点外的所有定时器的计数操作在其插入delta列表时就已完成。因而当定时器守护例程确定timeout的定时器时,只需对首结点进行减1或删除的操作,而不需遍历整个列表,从而使delta列表的操作与定时器数量无关。这使delta列表法在大量定时器管理中大显其能。 该法在系统中实现的数据结构为一静态双向链表: structwdNode{ BOOLflag; UINT16ticks; VOIDFUNCPTRrout; UINT8next; }idatawdList[_MAX_WDOG_NUM_]; UINT8headIdx;//索引首结点 有了delta列表法的思路及其实现的数据结构,在静态数组法具体实现的基础上,便可得此法的具体实现。 应用中如果目标系统ROM较小,且系统中启用的定时器少,则用静态数组法;若目标系统ROM较大,且系统中用到的定时器较多,则用delta列表法。 3 应用 针对前述的嵌入式系统中的定时需求,利用定时器管理系统给出其实现代码。 假定“特定操作”为voidspecFunc(void),“特定时间段”长度为10分钟。 (1)在经历特定的时间段后,执行特定操作。 #include″clk.h″ #include″wdLib.h″ voidmain(void){ WDOG_IDwdId; constructClk();constructWDOG(); wdId=wdCreate(); wdStart(wdId,10*ONE_MINUTE,specFunc); while(1); } (2)以给定周期周期性地执行特定操作。 基于前者,只需在voidspecFunc(void)函数体的最后加入下述代码即可: wdStart(wdId,10*ONE_MINUTE,specFunc); 注:该给定周期为10分钟。 由于本时钟管理器只需一个硬件定时器的支持,所以其具有广泛的适用性。
RTX_EXIT_CRITICAL();//退出临界区
UINT8prior;
- SN2005学习系统 数字语音室解决方案(05-19)
- 以可编程DSP架构应对TD-SCDMA以及TD-LTE带来的设计挑战 (02-14)
- ARM-μCLinux嵌入式系统启动引导的实现(07-26)
- 多核处理器架构及调试方案(03-28)
- 基于DSP的电源解决方案(06-13)
- 间歇性Bug最佳解决方案(09-24)