软件定时器能干嘛
软件定时器功能上和硬件定时器类似, 但是软件定时器是基于系统中断由软件来模拟的定时器
不像硬件定时器一样占用硬件资源
为了启用软件定时器,需要在头文件FreeRTOSConfig.h中设置configUSE_TIMERS的值为1
和硬件定时器相同, 在经过设定的tick数之后, 会调用对应的回调函数
可以在回调函数中实现需要的逻辑
注意不要在回调函数中执行任何可能会导致其进入阻塞状态的函数
因为定时器回调函数是由进程守护任务(RTOS daemon task)执行的
进程守护任务具有和正常任务相同的优先级机制
一旦定时器回调函数进入阻塞状态, 进程守护任务也会被阻塞, 这是不合法的
mcu总是单线程的, 那么守护进程任务什么时候执行是由谁来维护的呢?
还记得时间片结尾的中断吗?
在这个中断的服务例程里会检查是否满足定时器的条件
如果是, 则唤醒定时器, 紧跟着的就会执行定时器的处理任务了
软件定时器分一次性定时器和自动重载定时器
一次性定时器在运行完一次之后自动进入休眠(dormant)状态
而自动重载定时器在执行完一次后会重新开始

既然定时器是由freertos守护进程任务维护的, 而启动定时器等api函数总是在别的任务中执行的
那么守护进程任务是如何知道在什么时候启动定时器, 又在什么时候对定时器进行操作呢
这就要提到上一节的队列了
队列作为一种任务间的通信方式, 理所应当能够作为进程守护任务与其他任务沟通的桥梁
当其他任务调用xTimerCreate()时, 会向Timer Command Queue(定时器任务列表)中发送一条指令
当进程守护任务从列表中读取到该指令时, 会执行相应的操作
1 | TimerHandle_t xTimerCreate( const char * const pcTimerName, //定时器名, 仅用于调试 |
1 | BaseType_t xTimerStart( TimerHandle_t xTimer, TickType_t xTicksToWait ); |
1 | void vTimerSetTimerID( const TimerHandle_t xTimer, void *pvNewID ); |
1 | void *pvTimerGetTimerID( const TimerHandle_t xTimer ); |
1 | BaseType_t xTimerChangePeriod( TimerHandle_t xTimer, |
1 | BaseType_t xTimerReset( TimerHandle_t xTimer, TickType_t xTicksToWait ); |
上述api函数如若要在中断中使用, 均需要使用其中断专用api函数, 函数名就是原函数名后面加上FromISR
例如xTimerStartFromISR()
静态创建软件定时器xTimerCreateStatic()