1.软件定时器概念
是指具有定时功能的软件,可设置定时周期,当指定时间到达后要调用回调函数(也称超时函数),用户在回调函数中处理信息。
2 软件定时器使用特点
1)如果要使能软件定时器,需将configUSE_TIMERS 配置项配置成 1
2)软件定时器支持设置成:单次定时器或周期定时器
3)软件定时器的超时回调函数是由软件定时器服务任务调用的,软件定时器的超时回调函数本身不是任务,因此不能在该回调函数中使用可能会导致任务阻塞的 API 函数。
3 软件定时器服务任务
在调用函数 vTaskStartScheduler()开启任务调度器的时候,会创建一个用于管理软件定时器的任务,这个任务就叫做软件定时器服务任务。
其作用:
1、负责软件定时器超时的逻辑判断
2、调用超时软件定时器的超时回调函数
3、处理软件定时器命令队列
4软件定时器相关配置
1)当FreeRTOS 的配置项 configUSE_TIMERS 设置为1,在启动任务调度器时,会自动创建软件定时器的服务/守护任务prvTimerTask( ) ;
2)软件定时器服务任务的优先级为 configTIMER_TASK_PRIORITY = 31;
3)定时器的命令队列长度为 configTIMER_QUEUE_LENGTH = 5 ;
注意事项:软件定时器的超时回调函数是在软件定时器服务任务中被调用的,服务任务不是专为某个定时器服务的,它还要处理其他定时器。因此调用的回调函数不能被阻塞,要求如下:
1、回调函数要尽快实行,不能进入阻塞状态,即不能调用那些会阻塞任务的 API 函数,如:vTaskDelay()
2、访问队列或者信号量的非零阻塞时间的 API 函数也不能调用。
5软件定时器的状态
休眠态:当指定时间到达之后,但因为没有运行,所以其定时超时回调函数不会被执行。
运行态:运行态的定时器,当指定时间到达之后,它的超时回调函数会被调用。
注意:
刚创建的软件定时器处于休眠态
6 软件定时器的状态转换
7 软件定时器结构体
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 /* 软件定时器的编号,调试用 */
#endif
uint8_t ucStatus; /* 软件定时器的状态 */
} xTIMER;
8软件定时器API函数
1)创建软件定时器
TimerHandle_t xTimerCreate( const char * const pcTimerName,
const TickType_t xTimerPeriodInTicks,
const UBaseType_t uxAutoReload,
void * const pvTimerID,
TimerCallbackFunction_t pxCallbackFunction );
形参:
pcTimerName :软件定时器名
xTimerPeriodInTicks:定时超时时间,单位:系统时钟节拍
uxAutoReload:定时器模式, pdTRUE:周期定时器, pdFALSE:单次定时器
pvTimerID:软件定时器 ID,用于多个软件定时器公用一个超时回调函数
pxCallbackFunction:软件定时器超时回调函数
返回值:
NULL 创建失败
其他 返回句柄,创建成功
2)开启软件定时器
BaseType_t xTimerStart( TimerHandle_t xTimer,
const TickType_t xTicksToWait );
形参:
xTimer: 等待软件定时器句柄
xTicksToWait:发送命令到软件定时器命令队列的最大等待时间
返回值:
pdPASS 成功
pdFAIL 失败
3)停止软件定时器API函数
BaseType_t xTimerStop( TimerHandle_t xTimer,
const TickType_t xTicksToWait);
形参:
xTimer: 软件定时器句柄
xTicksToWait:发送命令到软件定时器命令队列的最大等待时间
返回值:
pdPASS 成功
pdFAIL 失败
4)复位软件定时器
BaseType_t xTimerReset( TimerHandle_t xTimer,
const TickType_t xTicksToWait);
形参:
xTimer: 软件定时器句柄
xTicksToWait:发送命令到软件定时器命令队列的最大等待时间
返回值:
pdPASS 成功
pdFAIL 失败
注意:该功能将使软件定时器的重新开启定时,复位后的软件定时器以复位时的时刻作为开启时刻重新定时
5)更改软件定时器超时时间
BaseType_t xTimerChangePeriod( TimerHandle_t xTimer,
const TickType_t xNewPeriod,
const TickType_t xTicksToWait);
形参:
xTimer: 软件定时器句柄
xNewPeriod: 新的定时超时时间,单位:系统时钟节拍
xTicksToWait:发送命令到软件定时器命令队列的最大等待时间
返回值:
pdPASS 成功
pdFAIL 失败
8软件定时器实战
代码:
#include "freertos_demo.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
/*FreeRTOS*********************************************************************************************/
#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"
/******************************************************************************************************/
/*FreeRTOS配置*/
/* START_TASK 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define START_TASK_PRIO 1 /* 任务优先级 */
#define START_STK_SIZE 128 /* 任务堆栈大小 */
TaskHandle_t StartTask_Handler; /* 任务句柄 */
void start_task(void *pvParameters); /* 任务函数 */
/* TASK1 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define TASK1_PRIO 2 /* 任务优先级 */
#define TASK1_STK_SIZE 128 /* 任务堆栈大小 */
TaskHandle_t Task1Task_Handler; /* 任务句柄 */
void task1(void *pvParameters); /* 任务函数 */
//定义定时器回调函数、与定时器句柄
TimerHandle_t timer1_handle = 0; //单次定时器
TimerHandle_t timer2_handle = 0; //周期定时器
void timer1_callback(TimerHandle_t pxTimer);
void timer2_callback(TimerHandle_t pxTimer);
/**
* @brief FreeRTOS例程入口函数
* @param 无
* @retval 无
*/
void freertos_demo(void)
{
xTaskCreate((TaskFunction_t )start_task, /* 任务函数 */
(const char* )"start_task", /* 任务名称 */
(uint16_t )START_STK_SIZE, /* 任务堆栈大小 */
(void* )NULL, /* 传入给任务函数的参数 */
(UBaseType_t )START_TASK_PRIO, /* 任务优先级 */
(TaskHandle_t* )&StartTask_Handler); /* 任务句柄 */
vTaskStartScheduler();
}
/**
* @brief start_task
* @param pvParameters : 传入参数(未用到)
* @retval 无
*/
void start_task( void * pvParameters )
{
taskENTER_CRITICAL(); /* 进入临界区 */
// 定时器1创建为单次定时器
timer1_handle = xTimerCreate("timer1", 500, pdFALSE, (void *)1, timer1_callback);
// 定时器2创建为周期定时器
timer2_handle = xTimerCreate( "timer2", 2000,pdTRUE, (void*)2, timer2_callback);
xTaskCreate((TaskFunction_t ) task1,
(char * ) "task1",
(configSTACK_DEPTH_TYPE ) TASK1_STK_SIZE,
(void * ) NULL,
(UBaseType_t ) TASK1_PRIO,
(TaskHandle_t * ) &Task1Task_Handler );
vTaskDelete(NULL);
taskEXIT_CRITICAL(); /* 退出临界区 */
}
/**
* @brief task1
* @param pvParameters : 传入参数(未用到)
* @retval 无
*/
//任务一、按键扫描并控制软件定时器
void task1(void *pvParameters)
{
uint8_t key = 0;
while(1)
{
key = key_scan(0);
if(key == KEY0_PRES)
{
xTimerStart(timer1_handle,portMAX_DELAY);
xTimerStart(timer2_handle,portMAX_DELAY);
}
else if(key == KEY1_PRES)
{
xTimerStop(timer1_handle,portMAX_DELAY);
xTimerStop(timer2_handle,portMAX_DELAY);
}
vTaskDelay(10);
}
}
/**
* @brief Timer1超时回调函数
* @param xTimer : 传入参数(未用到)
* @retval 无
*/
//timer1的超时回调函数
void timer1_callback(TimerHandle_t pxTimer)
{
static uint32_t timer = 0;
printf("timer1的运行次数:%d\r\n",++timer);
}
/**
* @brief Timer2超时回调函数
* @param xTimer : 传入参数(未用到)
* @retval 无
*/
void timer2_callback(TimerHandle_t pxTimer)
{
static uint32_t timer = 0;
printf("timer2的运行次数:%d\r\n",++timer);
}