像我们使用电stm32单片机或者51单片机当中,都有定时器这个外设。而freertos也不例外,它自己也有定时器的功能。
#include "timers.h"
TimerHandle_t timer1_Handle; //创建句柄
timer1_Handle = xTimerCreate("timer1Task",1000,pdTRUE,(void*)1,timer1Task); //创建函数
xTimerDelete(timer1_Handle,0); //删除函数
首先先定义软件定时器的头文件和句柄,然后调用xTimerCreate()函数创建软件定时器。xTimerCreate()函数有5个参数,第一个是函数名,个人建议给和回调函数一样的名字即可;第二个是定时时间,单位为ms;第三个参数是模式设置,软件定时器有两个模式,周期模式和单次模式。周期模式就是一直定时1000ms,不断循环,单次模式就是定时一次就自动结束了。选择pdTRUE为周期模式,选择pdFALSE为单次模式;第四个参数是定时器编号,每个定时器最好都别设置一样的编号,需要(void*)进行强转;最好一个参数是回调函数名,软件定时器将一直执行这个回调函数里的逻辑代码。
最后是删除函数,第一个参数是定时器句柄,第二个参数是等待时间,给0的话就是一调用直接删除。删除函数更多的是使用在周期定时器上面,单次定时器调用完一次之后系统会自动删除。
xTimerStart(timer1_Handle,0); //开始定时器
xTimerStop(timer1_Handle,0); //停止定时器
开始定时器函数xTimerStart()函数和停止定时器函数xTimerStop()函数的用法都是一样的。它们都有两个参数,第一个参数是定时器的句柄,第二个参数是等待事件,给0就是直接开始或者直接停止。但是这两个函数都不能在中断里使用,中断有中断自己的开始和停止函数。
xTimerStartFromISR(timer1_Handle,pdTRUE); //开始定时函数
xTimerStopFromISR(timer1_Handle,pdTRUE); //停止定时函数
第一个参数是定时器句柄,第二个可以给pdTRUE或者pdFALSE。
TickType_t tick_num2;
tick_num2 = xTaskGetTickCount();
xTaskGetTickCount()函数可以返回定时器的值,我们定义一个变量来接收即可。
定义两个定时器,一个周期定时器,一个单次定时器,看看他们的效果。
TimerHandle_t timer1_Handle; //周期定时句柄
TimerHandle_t timer2_Handle; //单次定时句柄
TaskHandle_t startTask_handler; //总任务的句柄
TaskHandle_t ledTask_handler; //led的句柄
TaskHandle_t timer1Task_handler; //获取信号量的句柄
TaskHandle_t timer2Task_handler; //释放信号量的句柄
void startTask(void *arg)
{
BaseType_t xReturn = pdFALSE; //创建接收值
taskENTER_CRITICAL(); //临界区
xReturn = xTaskCreate(ledTask,"ledTask",64,NULL,1,&ledTask_handler); //创建led任务
//创建定时器1
timer1_Handle=xTimerCreate("timer1Task",1000,pdTRUE,(void*)1,timer1Task);
if(timer1_Handle != NULL)
{
xTimerStart(timer1_Handle,0); //开启周期定时器
}
//创建定时器2
timer2_Handle=xTimerCreate("timer2Task",5000,pdFALSE,(void*)2,timer2Task);
if(timer2_Handle != NULL)
{
xTimerStart(timer2_Handle,0); //开启单次定时器
}
if(xReturn == pdTRUE)
{
printf("Task create ok\n");
}
else
{
printf("Task create error\n");
}
vTaskDelete(startTask_handler); //删除开始任务
taskEXIT_CRITICAL(); //临界区
}
开始任务startTask(vois *arg)创建了3个任务,分别是led任务,周期定时器任务和单次定时器任务。
void ledTask(void *arg)
{
while(1)
{
GPIO_SetBits(GPIOB,GPIO_Pin_8);
vTaskDelay(500);
GPIO_ResetBits(GPIOB,GPIO_Pin_8);
vTaskDelay(500);
}
}
led任务主要起到一个心跳包的作用,我们可以观察led是否一直闪烁来判断我们的程序是否运行正常。
int timer1Index = 0;
void timer1Task(void *arg)
{
TickType_t tick_num1;
timer1Index++; // 每回调一次加一
tick_num1 = xTaskGetTickCount(); // 获取滴答定时器的计数值
printf("timer1 callback %d times\n", timer1Index);
printf("timer1 data = %d\n", tick_num1);
}
定义一个全局变量timer1Index来记录调用次数,tick_num1用来记录定时器的值,这个任务是每1秒调用一次,不停循环。
int timer2Index = 0;
void timer2Task(void *arg)
{
TickType_t tick_num2;
timer2Index++; // 每回调一次加一
tick_num2 = xTaskGetTickCount(); // 获取滴答定时器的计数值
printf("=========================================\n");
printf("timer2 callback %d times\n", timer2Index);
printf("timer2 data = %d\n", tick_num2);
printf("=========================================\n");
}
定义一个全局变量timer2Index来记录调用次数,tick_num2用来记录定时器的值,这个任务是5秒调用一次,调用完就自动删除。
第一张图片,刚开始按下复位键,串口打印Task create ok,代表所有任务创建成功。随后周期定时器timer1不停执行,到第5次时,单次定时器timer2也调用了。
但是由第2张图可以看到,当周期定时timer1调用第10次时,单次定时器timer2没有调用,因为它已经被删除了。
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "usart.h"
#include "FreeRTOS.h"
#include "task.h"
#include "key.h"
#include "queue.h"
#include "led.h"
#include "stdlib.h"
#include "semphr.h"
#include "timers.h"
TimerHandle_t timer1_Handle; //周期定时句柄
TimerHandle_t timer2_Handle; //单次定时句柄
TaskHandle_t startTask_handler; //总任务的句柄
TaskHandle_t ledTask_handler; //led的句柄
TaskHandle_t timer1Task_handler; //获取信号量的句柄
TaskHandle_t timer2Task_handler; //释放信号量的句柄
int timer1Index = 0;
int timer2Index = 0;
void ledTask(void *arg)
{
while(1)
{
GPIO_SetBits(GPIOB,GPIO_Pin_8);
vTaskDelay(500);
GPIO_ResetBits(GPIOB,GPIO_Pin_8);
vTaskDelay(500);
}
}
void timer1Task(void *arg)
{
TickType_t tick_num1;
timer1Index++; // 每回调一次加一
tick_num1 = xTaskGetTickCount(); // 获取滴答定时器的计数值
printf("timer1 callback %d times\n", timer1Index);
printf("timer1 data = %d\n", tick_num1);
}
void timer2Task(void *arg)
{
TickType_t tick_num2;
timer2Index++; // 每回调一次加一
tick_num2 = xTaskGetTickCount(); // 获取滴答定时器的计数值
printf("=========================================\n");
printf("timer2 callback %d times\n", timer2Index);
printf("timer2 data = %d\n", tick_num2);
printf("=========================================\n");
}
void startTask(void *arg)
{
BaseType_t xReturn = pdFALSE; //创建接收值
taskENTER_CRITICAL(); //临界区
xReturn = xTaskCreate(ledTask,"ledTask",64,NULL,1,&ledTask_handler); //创建led任务
//创建定时器1
timer1_Handle=xTimerCreate("timer1Task",1000,pdTRUE,(void*)1,timer1Task);
if(timer1_Handle != NULL)
{
xTimerStart(timer1_Handle,0); //开启周期定时器
}
//创建定时器2
timer2_Handle=xTimerCreate("timer2Task",5000,pdFALSE,(void*)2,timer2Task);
if(timer2_Handle != NULL)
{
xTimerStart(timer2_Handle,0); //开启单次定时器
}
if(xReturn == pdTRUE)
{
printf("Task create ok\n");
}
else
{
printf("Task create error\n");
}
vTaskDelete(startTask_handler); //删除开始任务
taskEXIT_CRITICAL(); //临界区
}
int main(void)
{
LED_Init();
usrt1_init(9600);
xTaskCreate(startTask,"startTask",512,NULL,1,&startTask_handler); //创建开始任务
vTaskStartScheduler();
}