软件定时器的简介(了解)
FreeRTOS 中的软件定时器是一种轻量级的时间管理工具,用于在任务中创建和管理定时器。软件定时器是基于 FreeRTOS 内核提供的时间管理功能实现的,允许开发者创建、启动、停止、删除和管理定时器,从而实现在任务中对时间的灵活控制。
软件定时器与硬件定时器的主要区别如下:
| 软件定时器 | 硬件定时器 |
| FreeRTOS提供的功能来模拟定时器,依赖系统的任务调度器来进行计时和任务调度 | 由芯片或微控制器提供,独立于 CPU,可以在后台运行,不受任务调度器的影响 |
| 精度和分辨率可能受到任务调度的影响 | 具有更高的精度和分辨率 |
| 不需要额外的硬件资源,但可能会增加系统的负载 | 占用硬件资源,不会增加 CPU 的负载 |
软件定时器能够让函数在未来的设定时间执行。由定时器执行的函数称为定时器的回调函数。从定时器启动到其回调函数执行之间的时间被称为定时器的周期。简而言之,当定时器的周期到期时,定时器的回调函数会被执行。
定时器回调函数在定时器服务任务的上下文中执行,在定时器回调函数中不能调用导致阻塞的API函数。
软件定时器服务任务是任务调度器中的一个特殊任务,专门用于管理和维护软件定时器的正常运行。如果configUSE_TIMERS 设置为1,在开启任务调度器的时候,会自动创建软件定时器服务的任务。它主要负责软件定时器超时的逻辑判断、调用超时软件定时器的超时回调函数、处理软件定时器命令队列。
软件定时器的状态(熟悉)
FreeRTOS 中的软件定时器有三种状态,分别是:
- 未创建(Uncreated):软件定时器被创建之前的状态。在这个状态下,定时器的数据结构已经被定义,但尚未通过 xTimerCreate() 函数创建。
- 已创建(Created):软件定时器已被成功创建,但尚未启动。在这个状态下,可以对定时器进行配置,如设置定时器的周期、回调函数等,但定时器并未开始计时。
- 已运行(Running):软件定时器已经被启动,正在运行中。在这个状态下,定时器会按照预定的周期定时触发超时事件,执行注册的回调函数。
单次定时器和周期定时器(熟悉)
在 FreeRTOS 中,软件定时器主要有两种类型:一次性定时器和周期性定时器。
- 一次性定时器(One-shot Timer): 这种定时器在触发一次超时后就会停止,不再执行。适用于只需在特定时间执行一次任务或动作的场景。
- 周期性定时器(Periodic Timer): 这种定时器会在每个超时周期都触发一次,循环执行。适用于需要在固定的时间间隔内重复执行任务或动作的场景。
FreeRTOS软件定时器相关API函数(熟悉)
软件定时器相关函数如下:
| 函数 | 描述 |
| xTimerCreate() | 动态方式创建软件定时器 |
| xTimerCreateStatic() | 静态方式创建软件定时器 |
| xTimerStart() | 开启软件定时器定时 |
| xTimerStartFromISR() | 在中断中开启软件定时器定时 |
| xTimerStop() | 停止软件定时器定时 |
| xTimerStopFromISR() | 在中断中停止软件定时器定时 |
| xTimerReset() | 复位软件定时器定时 |
| xTimerResetFromISR() | 在中断中复位软件定时器定时 |
| xTimerChangePeriod() | 更改软件定时器的定时超时时间 |
| xTimerChangePeriodFromISR() | 在中断中更改定时超时时间 |
FreeRTOS软件定时器实验(掌握)实验目标
学习使用FreeRTOS软件定时器的函数:
- start_task:用来创建task1任务,并创建一次性定时器和周期性定时器。
- task1:用于按键扫描,并对软件定时器进行开启、停止操作。
FreeRTOSConfig.h代码清单
/* 软件定时器相关定义 */
#define configUSE_TIMERS 1 /* 1: 使能软件定时器, 默认: 0。使能后需指定下面3个 */
#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES - 1) // 定义软件定时器任务的优先级
#define configTIMER_QUEUE_LENGTH 5 /* 定义软件定时器命令队列的长度*/
#define configTIMER_TASK_STACK_DEPTH (configMINIMAL_STACK_SIZE * 2) /* 定义软件定时器任务的栈空间大小*/
freertos_demo.c代码清单
- 引入头文件
#include "timers.h"
- 任务配置
#include "freertos_demo.h"
/* freertos相关的头文件,必须的 */
#include "FreeRTOS.h"
#include "task.h"
#include "timers.h" // 软件定时器的头文件
/* 需要用到的其他头文件 */
#include "LED.h"
#include "Key.h"
/* 启动任务的配置 */
#define START_TASK_STACK 128
#define START_TASK_PRIORITY 1
TaskHandle_t start_task_handle;
void start_task(void *pvParameters);
/* 任务1的配置 */
#define TASK1_STACK 128
#define TASK1_PRIORITY 2
TaskHandle_t task1_handle;
void task1(void *pvParameters);
/* 软件定时器的超时回调函数 */
void timer1_callback(TimerHandle_t xTimer); // 单次
void timer2_callback(TimerHandle_t xTimer); // 周期
/* 软件定时器的句柄 */
TimerHandle_t timer1_handle;
TimerHandle_t timer2_handle;
/**
* @description: 启动FreeRTOS
* @return {*}
*/
void freertos_start(void)
{
/* 创建一次性软件定时器 */
timer1_handle = xTimerCreate(
"ergou", // 软件定时器的名称
(TickType_t)500, // 超时时间 = 500个 RTOS的时钟节拍
pdFALSE, // 是否自动重载:pdTRUE --- 周期型; pdFALSE --- 一次性
(void *)1, // 定时器的唯一ID
timer1_callback);
if (timer1_handle != NULL)
{
printf("timer1一次性定时器创建成功...\r\n");
}
/* 创建周期性软件定时器 */
timer2_handle = xTimerCreate(
"gousheng", // 软件定时器的名称
(TickType_t)1000, // 超时时间 = 1000个 RTOS的时钟节拍
pdTRUE, // 是否自动重载:pdTRUE --- 周期型; pdFALSE --- 一次性
(void *)2, // 定时器的唯一ID
timer2_callback);
if (timer2_handle != NULL)
{
printf("timer2周期性定时器创建成功...\r\n");
}
/* 1.创建一个启动任务 */
xTaskCreate((TaskFunction_t)start_task, // 任务函数的地址
(char *)"start_task", // 任务名字符串
(configSTACK_DEPTH_TYPE)START_TASK_STACK, // 任务栈大小,默认最小128,单位4字节
(void *)NULL, // 传递给任务的参数
(UBaseType_t)START_TASK_PRIORITY, // 任务的优先级
(TaskHandle_t *)&start_task_handle); // 任务句柄的地址
/* 2.启动调度器:会自动创建空闲任务 */
vTaskStartScheduler();
}
/**
* @description: 启动任务:用来创建其他Task
* @param {void} *pvParameters
* @return {*}
*/
void start_task(void *pvParameters)
{
/* 进入临界区:保护临界区里的代码不会被打断 */
taskENTER_CRITICAL();
/* 创建3个任务 */
xTaskCreate((TaskFunction_t)task1,
(char *)"task1",
(configSTACK_DEPTH_TYPE)TASK1_STACK,
(void *)NULL,
(UBaseType_t)TASK1_PRIORITY,
(TaskHandle_t *)&task1_handle);
/* 启动任务只需要执行一次即可,用完就删除自己 */
vTaskDelete(NULL);
/* 退出临界区 */
taskEXIT_CRITICAL();
}
/**
* @description: 任务一:用于按键扫描,并对软件定时器进行开启、停止操作
* @param {void} *pvParameters
* @return {*}
*/
void task1(void *pvParameters)
{
uint8_t key = 0;
BaseType_t res = 0;
while (1)
{
key = Key_Detect();
if (key == KEY1_PRESS)
{
/* 开启软件定时器 */
res = xTimerStart(timer1_handle, portMAX_DELAY);
if (res != pdFAIL)
{
printf("timer1单次定时器启动成功\r\n");
}
res = xTimerStart(timer2_handle, portMAX_DELAY);
if (res != pdFAIL)
{
printf("timer2周期定时器启动成功\r\n");
}
}
else if (key == KEY2_PRESS)
{
/* 停止软件定时器 */
res = xTimerStop(timer1_handle, portMAX_DELAY);
if (res != pdFAIL)
{
printf("timer1单次定时器停止成功\r\n");
}
res = xTimerStop(timer2_handle, portMAX_DELAY);
if (res != pdFAIL)
{
printf("timer2周期定时器停止成功\r\n");
}
}
vTaskDelay(500);
}
}
void timer1_callback(TimerHandle_t xTimer)
{
static uint16_t timer1_count = 0;
printf("timer1超时回调=%d次..\r\n",++timer1_count);
}
void timer2_callback(TimerHandle_t xTimer)
{
static uint16_t timer2_count = 0;
printf("timer2超时回调=%d次..\r\n",++timer2_count);
}

Comments NOTHING