一个嵌入式软件定时器的设计

概述

在嵌入式系统里面,相对来说定时器的资源是比较紧缺的,并且定时器是比较精确的,有些时候可能我们需要大量的定时任务,并且并不一定要非常精确的定时器,比如ms级别的定时,s级别的定时器,这个时候我们就需要设计一些软件定时器来做这些需求。

最原始的软件定时器

如果我们现在有一个us定时器,我们还需要一个ms定时器,我们想到最简单的办法就是定义一个变量在中断里面累加,如下代码所示:

uint32_t Timer = 0;;
//main 函数
int main()
{
	//初始化,启动us定时器,
	while(1)
	{}
}
//中断函数
void TIM_IRQ interrupt 0
{
	Timer++; 
	if (Timer == 1000)
	{
		Timer = 0;
		//执行定时任务
	}
}

看上面的一个定时器,这是软件定时器的雏形,就是在中断函数里面不断的累加一个变量到达定时时间之后开始执行中断函数。这也是软件定时器最核心的东西,但是如果大量的定时器都像上面那样写,我们的中断函数里面要写很多的东西,显得很乱,我们希望更多的业务逻辑尽量不要写在中断函数里面,我们对上面的代码改版,出现了下面的代码:


uint32_t Timer = 0;;
//main 函数
int main()
{
	//初始化,启动us定时器,
	Timer = 1000;
	while(1)
	{
		if (Timer <= 0)
		{
			//执行定时任务
		}
	}
}
//中断函数
void TIM_IRQ interrupt 0
{
	if (Timer>0)
	{
		Timer--;	
	}
}

上面的代码看上去稍微好看了一点点,我们把中断处理逻辑移动到了main函数里面处理,现在还是有问题的,我们每启动一个定时器,需要定义一个变量,中断函数里面添加一段逻辑,有时候可能我们的代码是分层写的,驱动和应用是分层写的,于是就出现了一边在写应用层逻辑,一遍还要去中断里面添加定时器,我们设计思路是定义一些定时器,先用着,怎么定义呢,先定义一个定时器数组,看下面代码:


//定义定时器
#define TIME_COUNT  12
int32_t timer[TIME_COUNT] ={-1}; 

//申请一个定时器
int apply_timer(uint32_t time)
{
	//遍历所有定时器,查找未使用定时器
	for(int i = 0;i <TIME_COUNT i++)
	{
		if (timer[i] == -1)//有空闲定时器
		{
			timer[i] = time;
			return i;
		}
	}
	return -1;
}
int read_timer(int id)
{
	return timer[id];
}
//main 函数
int main()
{
	//初始化,启动us定时器,
	int id1 = apply_timer(1000)
	if (id1 == -1)
		printf("apply faild\r\n");
	int id2 = apply_timer(1000)
	if (id2 == -1)
		printf("apply faild\r\n");
	while(1)
	{
		if (read_timer(id1) <= 0)
		{
			//执行定时任务1
		}
		if (read_timer(id2) <= 0)
		{
			//执行定时任务2
		}
	}
}
//中断函数
void TIM_IRQ interrupt 0
{
	for(int i = 0;i <TIME_COUNT i++)
	{
		if (timer[i]>0)
			timer[i]--;
	}
}

上面的代码实现了一个静态的软件定时器,基本分离了驱动层代码和应用层的业务逻辑,但是静态的定时器,静态的定时器我们就不能在程序运行中动态的申请定时器,或者我们预留足够的定时器留给程序中动态申请,但是,资源是紧缺的,我们预留的定时器在一段时间内是不用的,但是同样的还会占用系统资源,我们继续改造定时器,用链表和指针,构造终极定时器,代码见码云:

https://gitee.com/zyzp/codes/ut39rhm61q4vk2yd5bsog46

下次解释代码设计的思路

如果这篇文章对您很有帮助,不妨
----- 本文结束 ❤ 感谢您的阅读 ----