文章目录
前言
定时器可以说是每个MCU都有的外设,除了有最基础的定时的功能,还有些很强大的功能–PWM,输出捕获等功能。MCU自带的定时器属于硬件定时器,不同MCU的硬件定时器数量不同。freeRTOS提供了软件定时器,软件定时器精度没有硬件定时器的精度高。但是对于普通的精度要求的周期性处理的任务来说足够了。
当MCU的硬件定时器不够的时候就可以考虑freeRTOS 的软件定时器。
一、软件定时器介绍
软件定时器可以定时一段时间,当定时的时间到达之后就执行指定的功能函数,被定时器调用的这个功能叫做回调函数。回调函数的两次执行间隔就是定时器的定时周期,简单地说,当定时器的定时时间到了以后就会执行回调函数。
关于回调函数的注意事项:
软件定时器的回调函数在定时器服务中执行,所以一定不能在回调函数中调用任何会阻塞任务的API!!!比如,定时器回调函数中绝对不要用 vTaskDelay(),vTaskDelayUntil(),以及一些访问队列或者信号量的非零阻塞时间的API!!
二、定时器服务/Daemon 任务
1. 定时器服务任务 与 队列
2. 定时器相关配置
定时器服务任务 与 定时器命令队列
3. 单次定时器 与 周期定时器
4. 复位软件定时器
有时候定时器正在运行的时候需要复位软件定时器,复位软件定时器会重新计算走起到达的时间点,这个新的时间点是相对于杜威定时器的那个时刻计算的,并不是第一次启动软件定时器的那个时间点。
5. 创建软件定时器
6. 开启软件定时器
中断版本的传参和之前的一样!!!
7. 停止软件定时器
参数与之前的参数一致!!
8. 实验
#include "sys.h"
#include "usart.h"
#include "led.h"
#include "delay.h"
//#include <string.h>
#include "FreeRTOS.h"
#include "semphr.h"//信号量的头文件
#include "task.h"
#include "timers.h"
/*
本次实验:学习freeRTOS软件定时器的使用,包含软件定时器的创建,开启和停止
start_task:开始创建任务
task1:控制两个软件定时器的开启与停止
------------
注意:对于使用软件定时器需要的配置:
configUSE_TIMERS 1
configTIMER_TASK_PRIORITY (configMAX_PRIORITIES-1) //软件定时器优先级,也就是 32-1
configTIMER_QUEUE_LENGTH 5 //软件定时器队列长度
configTIMER_TASK_STACK_DEPTH (configMINIMAL_STACK_SIZE*2) //软件定时器任务堆栈大小
------------
本实验除了创建两个任务,还需要创建两个软件定时器。分别为单次定时器和周期定时器。
单次定时器的定时周期:2000个时钟周期(2s)
周期定时器的定时周期:1000个时钟周期(1s)
*/
#define start_task_size 52
#define start_task_pro 1
TaskHandle_t startTask_handler;
void start_task(void *pram);
#define task1_size 52
#define task1_pro 2
TaskHandle_t Task1_handler;
void task1(void *pram);
//软件定时器的句柄
TimerHandle_t autoReloadTimer_handle;//周期定时器句柄
TimerHandle_t oneReloadTimer_handle;//单次定时器句柄
//定时器的回调函数(注意这里的传参,传的是 定时器句柄 )
void autoReloadCalLback(TimerHandle_t xTimer);//周期定时器回调函数
void oneReloadCallback(TimerHandle_t xTimer);//单次定时器回调函数
int main(void)
{
delay_init(); //延时函数初始化
uart_init(115200); //初始化串口
LED_Init(); //初始化LED
xTaskCreate(
(TaskFunction_t )start_task,
(const char * ) "start_task",
(uint16_t )start_task_size ,
(void * )NULL,
(UBaseType_t ) start_task_pro,
(TaskHandle_t * )startTask_handler );
vTaskStartScheduler();//开始任务调度
}
/*88888888888888888888888888888888888888888888888888888888888888888888*/
void start_task(void *pram)
{
taskENTER_CRITICAL();
//BaseType_t Return;
//创建周期定时器,定时周期为1000个时钟周期(1s)
autoReloadTimer_handle = xTimerCreate( (const char *) "autoReloadTimer", /* 软件定时器名称 */
(TickType_t ) 1000, /* 软件定时器周期(时钟周期为单位) */
(UBaseType_t) pdTRUE, /* 周期模式--->pdTRUE,单次模式--->pdFALSE */
(void *) 1, /* 定时器ID */
(TimerCallbackFunction_t) autoReloadCalLback);/* 定时器回调函数 */
//创建单次定时器,定时周期为2000个时钟周期(2s)
oneReloadTimer_handle = xTimerCreate( (const char *) "oneReloadTimer", /* 软件定时器名称 */
(TickType_t ) 2000, /* 软件定时器周期(时钟周期为单位) */
(UBaseType_t) pdFALSE, /* 周期模式--->pdTRUE,单次模式--->pdFALSE */
(void *) 2, /* 定时器ID */
(TimerCallbackFunction_t) oneReloadCallback);/* 定时器回调函数 */
//创建任务1
xTaskCreate(
(TaskFunction_t ) task1,
(const char * ) "task1",
(uint16_t ) task1_size ,
(void * ) NULL,
(UBaseType_t ) task1_pro,
(TaskHandle_t * ) Task1_handler);
vTaskDelete(NULL);
taskEXIT_CRITICAL();
}
//task1:控制两个软件定时器的开启与停止
void task1(void *pram)
{
}
void autoReloadCalLback(TimerHandle_t xTimer)
{
/*不要调用任何具有阻塞性质的API*/
}
void oneReloadCallback(TimerHandle_t xTimer)
{
/*不要调用任何具有阻塞性质的API*/
}
我这里没有把程序写完,对于task1函数,里面就通过一个触发信号
(比如按键)来实现软件定时器的开启与停止。具体可以自己自由发挥。
总结
定时器 定时时间一到就会调用回调函数。