嵌入式时钟管理器的设计方案与实现
2.2 时钟脉冲的提供本文引用地址:https://www.eepw.com.cn/article/148815.htm
本文提供三个用户接口函数和一个用户可修改、但不可调用的钩子函数(clkTick_ISR_hook仅能在clkTick_ISR中被调用)。其用户接口声明如下:
externvoidconstructClk(void);
externvoiddestructClk(void);
externUINT8getClkRate(void);
其中:constructClk用以构建系统时钟,要使用本文所述的时钟管理器,需首先通过调用_clkInit(定义于clk_impl.*模块)实现对本函数的调用;destructClk用以解析业已构建的系统时钟;getClkRate用以获取系统当前的时钟节拍率(即定义于configClk.h中的宏SYS_CLK_RATE的当前值)。
clkTick_ISR_hook由系统声明,用户可修改其定义,其最终仅为系统作周期性调用。用户可将自己需进行的周期性操作放于其中,后面叙述的软件定时器的“守护”例程(wdDaemon)正是置于此处而被周期调用。由于置于其中的操作将在中断执行,所以这些操作应尽可能简短、省时。
2.3 软件定时器的提供
本功能在图1所示的wdLib.*中实现。
其为用户提供了可快速、便捷地实现用户定时需求的接口函数和一个被周期性调用的定时器守护例程wdDaemon。
externvoidconstructWDOG(void);//为使用定时器系统作初始化操作
externvoiddestructWDOG(void)//置定时器系统为初始态
externWDOG_IDwdCreate(void);//建立一个定时器,并返回其ID
externSTATUSwdCancel(WDOG_IDwdId);//终止指定定时器并复位
externSTATUSwdDelete(WDOG_IDwdId);//删除指定定时器
externSTATUSwdStart(WDOG_IDwdId,UINT16ticks,VOIDFUNCPTRwdr);//启动指定定时器,它会在指定时间后触发给定操作
其中:WDOG_ID为定时器ID类型,即UINT8。传送给wdStart的参数“UINT16ticks”指明定时时间长度,单位为系统时钟节拍,1节拍=1/SYS_CLK_RATE(s)。因该参数的类型定为UINT16,故定时器的最大定时长度为216×(1/SYS_CLK_RATE),即216/SYS_CLK_RATE(s)。
定时器的实现方案有静态数组法和delta列表法两种方法。这两种方法各有优缺点:前者逻辑简单,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;
linux操作系统文章专题:linux操作系统详解(linux不再难懂)
评论