设计软件定时器

在MCU芯片内部,往往硬件定时器的数量是非常有限的,而实际工程中却需要大量的定时器来辅助完成具体的功能,如果一个函数占用一个定时器,那么显然不够用,怎么办?

思路有2种:

1、直接将开源嵌入式操作系统的软件定时器搬来使用

2、自己设计软件定时器

这里我只介绍第二种方法,我们知道,硬件定时器是通过对系统时钟周期进行计数实现的,那么软件定时器也不例外,首先得要有时基,然后得计数以及清零或者重新装载的动作。

那么如何获得时基呢?硬件定时器是直接有系统时钟输入给它们,但是软件定时器则没有,我们必须通过其他的方法获得。有以下两种方法获得时基:

1、直接利用硬件定时器中断作为时基,在硬件定时器中断服务函数中完成对软件定时器的计数。

2、在主函数循环中监视硬件定时器的数值,如果数值达到预定值之后软件定时器就计数。

上面第一种是比较精确的,毕竟中断服务函数总是如期到来,时基差不多是如下这种情况:

但是第二种方法就没那么好了,比如受到任务运行的阻塞,也许硬件定时器早已到达预设数值,软件定时器还没有检测到,这种情况相当于输入到软件定时器的波形为占空比不断变化的时钟,而且硬件定时器的开关以及计数值装载还要通过软件去控制,显然这种方法设计的软件定时器只适合用在对精度要求非常低的情景下,比如按键扫描。

基于上面两种获取时基方式利弊的考虑,我们采用硬件定时器中断的方式获取软件定时器的时基。于是基本思路就很清晰了,在中断服务函数中不断的对软件定时器进行计数,函数再利用软件定时器是否达到预设值来决定是运行还是阻塞。首先我们设计一个结构体,这个结构体包含了四个成员:

typedef struct _SOFTTIMER
{
    bool bIsActivate;
    uint16_t usCount;
    uint16_t usTimerValue;
    bool bIsTimeOut;
}SOFTTIMER;

bIsActivate,该成员用于描述该定时器是否被激活,激活就为TURE,没有激活则为FALSE。
usCount,该成员用于在定时器中断服务函数中计数
TimerValue,该成员用于表示软件定时器的计数最大值
bIsTimeOut,该成员用于表示软件定时器是否到达预设计数值,以作为外部函数是否执行的依据

下面定义若干个软件定时器:

#define SOFTTIMER_MXANUM  5
volatile SOFTTIMER stSOFTTIMERGROUP[SOFTTIMER_MXANUM];

下面设计一个函数用于对软件定时器进行计数,该函数被定时器中断服务函数执行。如下所示:

void SoftTimerRunning(void)
{
    uint16_t i;
    for(i=0;i<SOFTTIMER_MXANUM;i++)
    {
        if(TRUE==stSOFTTIMERGROUP[i].bIsActivate)
        {
            stSOFTTIMERGROUP[i].usCount++;
            if(stSOFTTIMERGROUP[i].usCount>=stSOFTTIMERGROUP[i].usTimerValue)
            {
                stSOFTTIMERGROUP[i].usCount=0;
                stSOFTTIMERGROUP[i].bIsTimeOut=TRUE;
                /*stSOFTTIMERGROUP[i].bIsActivate=FALSE;*/
            }
        }
    }
}

该函数很简单,基本思路就是首先判断某定时器是否被激活,如果被激活则对该定时器进行计数,计数值到预设值则清零并且设置时间到标志。

而定时器的激活则是由外部函数完成的,当外部定时器需要使用某软件定时器的时候就将该软件定时器激活,并将预设计数值传给它,激活后软件定时器就开始计数,之后就检测该定时器是否到达预设值。代码如下:

bool SetTimerOut(uint8_t *FunID,uint16_t PreValue)
{
    uint8_t i;
    for(i=0;i<SOFTTIMER_MXANUM;i++)
    {
        if(TURE!=stSOFTTIMERGROUP[i].bIsActivate)
        {
            stSOFTTIMERGROUP[i].bIsActivate=TRUE;
            stSOFTTIMERGROUP[i].usTimerValue=PreValue;
            *FunID = i;
            return TRUE;
        }
    }
    return FALSE;
}

bool IsTimerOut(uint8_t *FunID)
{
    uint8_t i;
    assert_param(IS_FUNID_RIGHT(*FunID));
    if(TRUE==stSOFTTIMERGROUP[*FunID].bIsTimeOut)return TRUE;
}

先判断某定时器是否被占用(即是否已经激活),如果被占用则查询下一个定时器,直到找到没有被占用的定时器并将预设值传给它,然后返回该定时器的ID号,如果没有找到可用定时器则返回FALSE。

 

未完待续。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值