软件定时器简介
定时器:从指定的时刻开始,经过一个指定时间,然后触发一个超时事件,用户可以自定义 定时器周期。
硬件定时器:芯片本身自带的定时器模块,硬件定时器的精度一般很高,每次在定时时间到之后自动触发中断,用户在中断服务函数中处理信息。
软件定时器:具有定时功能的软件,可以设置定时周期,当指定时间到达后调用回调函数,(可以称之为超时函数),用户在回调函数中处理信息。
软件定时器的优缺点
优点:
1:硬件定时器数量有限,软件定时器理论上只需要有足够的内存,就可以创建多个
2:使用简单,成本低
缺点:
1:软件定时器相对于硬件定时器来说,精度不高(因为它以系统时钟为基准,系统时钟中断优先级最低,容易被打断),对于需要高精度要求的场合,不建议使用软件定时器。
软件定时器的特点
1:可以裁剪,软件定时器是可裁剪可配置功能,如果要使用软件定时器,需要将configUSE_TIMERS 配置为 1。
2:单次和周期,软件定时器支持设置为:单次定时器周期或周期定时器
注:
1:软件定时器超时回调函数是由软件定时器服务任务调用的,软件定时器超时回调函数不是任务,因此不能在该回调函数中使用可能会导致任务阻塞的API函数。
2:软件定时器服务任务:在调用函数vTaskStartScheduler()开启任务调度器的时候,会创建一个用于管理软件定时器的任务,这个任务就叫做软件定时器服务任务。
软件定时器服务任务作用
1:可以裁剪,软件定时器是可裁剪可配置功能,如果要使用软件定时器,需要将configUSE_TIMERS 配置为 1。
2:单次和周期,软件定时器支持设置为:单次定时器周期或周期定时器
注:
1:软件定时器超时回调函数是由软件定时器服务任务调用的,软件定时器超时回调函数不是任务,因此不能在该回调函数中使用可能会导致任务阻塞的API函数。
2:软件定时器服务任务:在调用函数vTaskStartScheduler()开启任务调度器的时候,会创建一个用于管理软件定时器的任务,这个任务就叫做软件定时器服务任务。
软件定时器服务任务作用
1:负责软件定时器超时的逻辑判断
2:调用超时软件定时器的超时回调函数
3:处理软件定时器的命令队列
【软件定时器在开始创建的时候处于休眠状态,要通过命令队列唤醒工作】
软件定时器命令队列
FreeRTOS提供了许多软件定时器相关的API函数,这些API函数大多都是往定时器的队列中写入消息(发送命令),这个队列叫做软件定时器命令队列,是提供给FreeRTOS中的软件定时器使用的,用户是不能直接访问的。
【往软件定时器发送一个命令】
软件定时器相关配置
1:宏定义配置,当freeRTOS的配置项configUSE_TIMERS 设置为 1,在启动任务调度器时,会自动创建软件定时器的服务/守护任务preTimerTask();
2:软件定时器服务任务优先级configTIMER_TASK_PRIORITY = 31
3: 定时器的命令长度为configTIMER_QUEUE_LENGTH = 5;
注:
软件定时器的超时回调函数是在软件定时器服务任务中被调用的,服务任务不是专门为某个定时器服务,它还要处理其他定时器。
so:
1:定时器回调函数要尽快实行,不能进入阻塞状态,即不能调用那些会阻塞任务的API函数,如vTaskDelay();
2:访问队列或者信号量的非零阻塞时间的API函数也不能调用
软件定时器的状态
1:休眠态,软件定时器可以通过其句柄被引用,但是因为没有运行,所以其定时超时回调函数不会被执行。
2:运行态,指定的定时时间到达之后,它的超时回调函数会被调用
注:
1:新创建的软件定时器处于休眠的状态,是没有运行的
2:通过发送命令队列的方式可以让软件定时器从休眠的状态转换为运行的状态
单次定时器和周期定时器
FreeRTOS提供了两种软件定时器
1:"单次定时器" ,一旦定时超时,只会执行一次其软件定时器超时回调函数,不会自动重新开启定时,不过可以被手动重新开启。
2:"周期定时器",周期定时器一旦启动以后就会执行完回调函数后自动重新启动,从而周期的执行其软件定时器回调函数。
软件定时器状态转换图
软件定时器结构体成员
typedef struct{const char * pcTimerName /*软件定时器名字*/ListItem_t xTimerListItem /*软件定时器列表项*/TickType_t xTimerPeriodInTicks /*软件定时器的周期*/void * pvTimerID /*软件定时器ID*/TimerCallbackFunction_t pxCallbackFunction /*软件定时器回调函数*/#if(configUSE_TRACE_FACILITY == 1)UBaseType_t uxTimerNumber /*软件定时器的编号*/#endifuint8_t ucStatus /*软件定时器的状态*/}xTIMER;
软件定时器API函数
函数 | 描述 |
xTimerCreadte() | 动态方式创建软件定时器 |
xTimerCreateStatic() | 静态方式创建软件定时器 |
xTimerStart() | 开启软件定时器定时 |
xTimerStartFromISR() | 在中断中开启软件定时器定时 |
xTimerStop() | 停止软件定时器定时 |
xTimerStopFromISR() | 在中断中停止软件定时器定时 |
xTimerReaet() | 复位软件定时器定时 |
xTimerResetFromISR() | 在中断中复位软件定时器定时 |
xTimerChangePeriod() | 更改软件电视器定时超时时间 |
xTimerChangePeriodFromISR() | 在中断中更改定时超时时间 |
创建软件定时器
要使用定时器,需要先创建它,得到它的句柄。 有两种方法创建定时器:动态分配内存、静态分配内存。函数原型如下:
/*使用动态分配内存的方式创建软件定时器* pcTimerName:定时器名字, 用处不大, 尽在调试时用到* xTimerPeriodInTicks: 周期, 以Tick为单位* uxAutoReload: 类型, pdTRUE表示自动加载, pdFALSE表示一次性* pvTimerID: 回调函数可以使用此参数, 比如分辨是哪个定时器* pxCallbackFunction: 回调函数* 返回值: 成功则返回TimerHandle_t, 否则返回NULL
*/
TimerHandle_t xTimerCreate( const char * const pcTimerName,const TickType_t xTimerPeriodInTicks,const UBaseType_t uxAutoReload,void * const pvTimerID, TimerCallbackFunction_t pxCallbackFunction );/*
静态创建软件定时器
* pcTimerName:定时器名字, 用处不大, 尽在调试时用到
* xTimerPeriodInTicks: 周期, 以Tick为单位
* uxAutoReload: 类型, pdTRUE表示自动加载, pdFALSE表示一次性
* pvTimerID: 回调函数可以使用此参数, 比如分辨是哪个定时器
* pxCallbackFunction: 回调函数
* pxTimerBuffer: 传入一个StaticTimer_t结构体, 将在上面构造定时器
* 返回值: 成功则返回TimerHandle_t, 否则返回NULL
*/
TimerHandle_t xTimerCreateStatic(const char * const pcTimerName,TickType_t xTimerPeriodInTicks,UBaseType_t uxAutoReload,void * pvTimerID,TimerCallbackFunction_t pxCallbackFunction, StaticTimer_t *pxTimerBuffer);
开启定时器的API函数
BaseType_t xTimerStart(TimerHandle_t xTimer,const TickType_t xTicksToWait);/*参数含义xTimer 待开启软件定时器句柄xTickToWait 发送命令到软件定时器命令队列的最大等待时间返回值PSPASS 软件定时器开启成功pdFALSE 软件定时器开启失败*/
停止软件定时器的API函数
BaseType_t xTimerStop(TimerHandle_t xTimer,const TickType_t xTickToWait
);
/*参数含义xTimer 待停止的软件定时器句柄xTickToWait 发送命令到软件定时器命令队列的最大等待时间返回值PdPASS 停止成功pdFALSE 停止失败
*/
复位软件定时器
该功能将使软件定时器的重新开启定时,复位后的软件定时器以复位时的时刻作为开启时刻重新定时,(按下复位键之后,重新开始从原来的时间继续计时)。
BaseType_t xTimerReset(TimerHandle_t xTimer,const TickType_t xTickToWait
);
/*参数含义xTimer 待复位的软件定时器句柄xTickToWait 发送命令到软件定时器命令队列的最大等待时间返回值PdPASS 软件定时器复位成功pdFALSE 软件定时器复位失败
*/
更改软件定时器超时时间API函数
BaseType_t xTimerChangePeriod(TimerHandle_t xTimer,const TickType_t xNewPeriod,const TickType_t xTicksToWait
);
/*定时器参数xTimer 待更新的软件定时器句柄xNewPeriod 新的定时器超时时间,单位:系统时钟节拍xTickToWait 发送命令到软件定时器命令队列的最大等待时间返回值PdPASS 软件定时器定时超时时间修改成功pdFALSE 软件定时器定时超时时间修改失败
*/
软件定时器项目实战
【参考自正点原子视频和伟东山老师文档】