软件定时器Software Timer
(或者称为”定时器”)允许函数在未来的某个设定时间得到执行。函数的执行是通过定时器调用回调函数完成的。从定时器开始到回调函数执行,这段时间称为定时器的周期。简而言之,回调函数在定时器周期结束时间得到执行。
软件定时器必须先创建才能使用,也就是默认是无可用的定时器的。
实现软件定时器时对效率的考虑
软件定时器的实现是简单的,但是如何提高效率却是有难度的。freeRTOS在实现定时器时,不在中断中执行定时器的回调函数,不占用CPU时间,除非定时器定时时间确实到来。不增加任何处理开销到节拍中断中,在中断被禁止时,不走任何链表结构。
写定时器的回调函数的注意事项
定时器的回调函数在定时器服务任务中执行,因此回调函数不能尝试阻塞,比如调用vTaskDelay()
和vTaskDelayUntil()
会到只阻塞,这是不允许的。同样对于队列、信号量的获取也会导致阻塞。
定时器的服务/守护任务和定时器命令队列
定时器功能时可选的,并不是freeRTOS内核的一部分,是由定时器服务任务提供的功能。
freeRTOS提供一系列的定时器相关的API函数。大多数的函数使用一个标准的freeRTOS队列来向定时器服务任务发送命令,这个队列称为”定时器器命令队列”。定时器命令队列是freeRTOS定时器的私有实现,无法直接访问。
下面的图表展示了这种方案:
左边的函数是用户程序代码的一部分,由用户任务调用。右边的函数是一个定时器服务任务。左边的函数通过调用xTimerReset()
函数重置软件定时器,实际上该函数是发送重置指令到定时器命令队列中,定时器服务任务从队列中取出指令并执行。在这个过程中,用户代码无法直接访问定时器命令队列。
使用软件定时器
在freeRTOS中加入软件定时器是很简单的,只要完成:
- 添加
FreeRTOS/Source/timers.c
源代码文件到你的工程中 - 按照下面的表格配置软件定时器,注意,下面所列的选项在
FreeRTOSConfig.h
文件中,如果不存在,自己补全它。
参数 | 描述 |
configUSE_TIMERS | 设置为1将包含软件定时器的功能,软件定时器服务函数将在RTOS的调度器开始时自动创建 |
configTIMER_TASK_PRIORITY | 设置软件定时器的优先级,与用户任务的优先级设置相同
|
configTIMER_QUEUE_LENGTH | 这里设置的是命令队列的最大长度
|
configTIMER_TASK_STACK_DEPTH | S设置定时器服务任务的栈深度
|
一次性定时器与自动重装定时器
定时器分为两种:一次性定时器(one-shot Timer)和自动重装定时器(auto-reload Timer)。一次性定时器只会执行回掉函数一次,可以手动重新开始。自动重装定时器会在每次执行回调函数之后自动重新启动自己,因此会周期性的调用回调函数。
下图展示了二者的不同,定时器1是一个周期100的一次性定时器,定时器2是一个周期为200的自动重装定时器:
重设定时器
对于一个已经运行的定时器,重设它也是允许的。重设定时器会使得定时器从重设的时刻重新计算超时时间,而不是定时器最初启动的时间。下面的图展示了这个特点,定时器是一个5秒周期的一次性定时器。
这个例子里,假设使用一个按键控制LCD背光,挡按键按下,LCD背光打开,五秒后关闭,如果在这期间按键再次按下,则重置定时器。