硬件定时器功能强大,遗憾数量较少。故可以使用软件定时器来拓展,软件定时器允许设置一段时间,当设置的时间达到后就执行指定的功能函数,模拟实现定时器中断的功能。
被定时器调用的函数叫定时器回调函数,回调函数执行的间隔叫定时器周期。软件定时器的回调函数在定时器服务任务中执行的,一定不用在回调函数中调用任何会阻塞的任务API函数,如vTaskDelay、vTaskDelayUnti、阻塞信号量等。
定时器是可选的、不属于FreeRTOS内核的功能,由定时器服务任务提供。
FreeRTOS提供了许多定时器相关的API函数,这些API函数大多使用队列发送命令给定时器服务任务。这个队列叫定时器命令队列,仅供FreeRTOS的软件定时器使用,用户不能直接访问。
定时器任务的创建过程:vTaskStartScheduler->xTimerCreateTimerTask->xTaskCreate->prvTimerTask(“Tmr Svc”)->prvProcessReceivedCommands
configUSE_TIMERS 为一启用软件定时器。
configTIMER_TASK_PRIORITY 设置为最高优先级,即(configMAX_PRIORITIES-1)
configTIMER_QUEUE_LENGTH 软件定时器队列长度
configTIMER_TASK_STACK_DEPTH 定时器的堆栈大小,默认(configMINIMAL_STACK_SIZE*2) =260 。注意回调函数申请的空间不要太复杂。
定时器分单次定时器和周期性定时器。
xTimerCreate() // 动态
xTimerCreateStatic() // 静态
动态创建参数说明
const char * const pcTimerName, // 定时器的名字
const TickType_t xTimerPeriodInTicks, // 定时器的周期节拍数,可以使用portTICK_PERIOD_MS将ms转换为节拍数
const UBaseType_t uxAutoReload, // 是否自动重装载,pdTRUE为自动重装载
void * const pvTimerID, // 定时器ID,每个ID对应一个回调函数,允许ID相同对应同一个回调函数。
TimerCallbackFunction_t pxCallbackFunction // 回调函数,执行定时器时间到了的功能函数
// 返回值为句柄
新创建的软件定时器都是未运行的,处于休眠状态。需使用start开启
xTimerReset() // 任务级复位软件定时器
xTimerResetFromISR() // 中断级复位软件定时器
任务级复位定时器参数说明
TimerHandle_t xTimer // 定时器句柄
TickType_t xTickToWait // 阻塞时间,即进入队列的阻塞时间
xTimerStart() // 任务级开启软件定时器
xTimerStartFromISR() // 中断级开启软件定时器
任务级开启定时器参数说明
TimerHandle_t xTimer // 定时器句柄
TickType_t xTickToWait // 阻塞时间,即进入队列的阻塞时间
xTimerStop() // 任务级停止软件定时器
xTimerStopFromISR() // 中断级停止软件定时器
使用按键控制定时器的开始和停止,观察重装载和单次定时器的区别。
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "string.h"
#include "FreeRTOS.h"
#include "task.h"
#include "key.h"
#include "queue.h"
#include "timer.h"
#include "timers.h"
/************************************************
************************************************/
//任务优先级
#define START_TASK_PRIO 1
//任务堆栈大小
#define START_STK_SIZE 128
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters);
//任务优先级
#define TIMCTRL_TASK_PRIO 2
//任务堆栈大小
#define TIMCTRL_STK_SIZE 128
//任务句柄
TaskHandle_t TimCtrl_Handler;
//任务函数
void tim_ctrl_task(void *pvParameters);
TimerHandle_t ReloadTimerHandle;
TimerHandle_t OneShotTimerHandle;
// 定时器回调函数
void ReloadTimerCallback( TimerHandle_t xTimer );
// 定时器回调函数
void OneShotTimerCallback( TimerHandle_t xTimer );
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4
delay_init(); //延时函数初始化
uart_init(115200); //初始化串口
LED_Init(); //初始化LED
KEY_Init();
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(); //开启任务调度
}
//开始任务任务函数
void start_task(void *pvParameters)
{
taskENTER_CRITICAL(); //进入临界区
// 创建定时器
ReloadTimerHandle = xTimerCreate((const char * ) "Reload Timer",
(TickType_t ) 1000, // 时钟节拍数
(UBaseType_t ) pdTRUE, //uxAutoReload,是否自动重装载
(void * ) 1, //pvTimerID,定时器ID
(TimerCallbackFunction_t) ReloadTimerCallback ); // 回调函数
// 创建定时器
OneShotTimerHandle = xTimerCreate((const char * ) "One Shot Timer",
(TickType_t ) 2000, // 时钟节拍数
(UBaseType_t ) pdFALSE, //uxAutoReload,是否自动重装载
(void * ) 2, //pvTimerID,定时器ID
(TimerCallbackFunction_t) OneShotTimerCallback ); // 回调
if(ReloadTimerHandle&&OneShotTimerHandle)
printf("ReloadTimerHandle&&OneShotTimerHandle Create Sucess\r\n");
xTaskCreate((TaskFunction_t) tim_ctrl_task,
(const char * ) "tim_ctrl_task",
(uint16_t ) TIMCTRL_STK_SIZE,
(void * ) NULL,
(UBaseType_t ) TIMCTRL_TASK_PRIO,
(TaskHandle_t* ) &TimCtrl_Handler);
vTaskDelete(StartTask_Handler); //删除开始任务
taskEXIT_CRITICAL(); //退出临界区
}
//任务函数
void tim_ctrl_task(void *pvParameters)
{
u8 key = 0;
BaseType_t err;
while(1)
{
key = KEY_Scan(0);
switch(key)
{
case WKUP_PRES:
err = xTimerStart(ReloadTimerHandle,0);
if(err == pdTRUE)
printf("++Reload Timer Start Sucess!!!\r\n");
else
printf("Reload Timer Start Failed\r\n");
break;
case KEY1_PRES:
err = xTimerStop(ReloadTimerHandle,0);
if(err == pdTRUE)
printf("--Reload Timer Stop Sucess!!!\r\n");
else
printf("Reload Timer Stop Failed\r\n");
break;
case KEY0_PRES:
err = xTimerStart(OneShotTimerHandle,0);
if(err == pdTRUE)
printf("+OneShot Timer Start Sucess!!!\r\n");
else
printf("OneShot Timer Start Failed\r\n");
break;
case KEY2_PRES:
err = xTimerStop(OneShotTimerHandle,0);
if(err == pdTRUE)
printf("-OneShot Timer Stop Sucess!!!\r\n");
else
printf("OneShot Timer Stop Failed\r\n");
break;
}
vTaskDelay(10); //延时1s,也就是1000个时钟节拍
}
}
// 定时器回调函数
void ReloadTimerCallback( TimerHandle_t xTimer )
{
static u8 times = 0;
LED0=!LED0;
times++;
printf("RUNNING %d,Reload Timer\r\n",times);
}
// 定时器回调函数
void OneShotTimerCallback( TimerHandle_t xTimer )
{
static u8 times = 0;
LED1=!LED1;
times++;
printf("RUNNING %d,OneShot Timer\r\n",times);
}