05_FreeRTOS相对延时与绝对延时

硬件平台:

  • STM32F103

相关配置:

1. FreeRTOS延时函数

延时函数:

  • vTaskDelay:相对延时,从延时函数调用开始,任务进入阻塞状态,直到指定延时时间完毕。
  • vTaskDelayUntil:绝对延时,计算整个任务的执行时间,最后用指定延时时间减去任务当前的执行时间即为任务所需的延时。

![[Pasted image 20250108145450.png]]

1.1 相对延时 - vTaskDelay

函数说明:

  • 注意实现: INCLUDE_vTaskDelay设置为1
  • 参数1: 指定延时的时间,单位为滴答周期(STM32所一直的FreeRTOS滴答周期为1ms)
void vTaskDelay( const TickType_t xTicksToDelay );

1.2 绝对延时 - vTaskDelayUntil

函数说明:

  • 注意实现: INCLUDE_vTaskDelayUntil设置为1
  • 参数1: 当前滴答计数的值的指针
  • 参数2: 指定延时的时间,单位为滴答周期(STM32所一直的FreeRTOS滴答周期为1ms)
void vTaskDelayUntil( TickType_t *pxPreviousWakeTime,
                      const TickType_t xTimeIncrement );

获取滴答计数值函数:

  • 返回值: 返回当前滴答计数的值
  • 注意实现: 无法从中断中获取
volatile TickType_t xTaskGetTickCount( void );

2. 相对延时与绝对延时示例

示例流程:

  1. 系统启动函数:创建一个启动任务
  2. 启动任务执行函数
    1. 创建任务1
    2. 创建任务2
  3. 任务1:
    1. 串口打印Task1
    2. CPU延时200ms
    3. 相对延时1s
  4. 任务2:
    1. 获取当前计数周期的值
    2. 打印Task2
    3. CPU延时200ms
    4. 绝对延时1s

2.1 系统启动函数

函数说明:

  • 动态创建一个启动任务
  • 启动任务调度器
/* 启动任务相关配置 */
void startTask(void *args);                                 /* 启动任务执行函数 */
#define START_TASK_NAME "start"                             /* 启动任务的名称 */
#define START_TASK_STACK_DEPTH 128                          /* 启动任务栈大小 = 2 * 128 字节 */
#define START_TASK_PRIORITY 4                               /* 启动任务优先级 */
TaskHandle_t startTaskTCB;                                  /* 启动任务的控制块 */

void FreeRTOS_Start(void)
{

    /* 1. 创建启动任务 */
    xTaskCreate(
        startTask,
        START_TASK_NAME,
        START_TASK_STACK_DEPTH,
        NULL,
        START_TASK_PRIORITY,
        &startTaskTCB
    );

    /* 2. 启动任务调度器 */
    vTaskStartScheduler();
}

2.2 启动任务执行函数

函数说明:

  • 创建任务1与任务2
  • 回收起始任务
/* 2个子任务相关配置 */
/* --------------------Task1-------------------- */
void taskFunc1(void *args);                                 /* 任务1执行函数 */
#define TASK_NAME_1 "task1"                                 /* 任务1的名称 */
#define TASK1_PRIORITY 4                                    /* 任务1优先级 */
TaskHandle_t task1TCB;                                      /* 任务1的控制块 */
/* --------------------Task2-------------------- */
void taskFunc2(void *args);                                 /* 任务2执行函数 */
#define TASK_NAME_2 "task2"                                 /* 任务2的名称 */
#define TASK2_PRIORITY 3                                    /* 任务2优先级 */
TaskHandle_t task2TCB;                                      /* 任务2的控制块 */

void startTask(void *args)
{
    // 1. 代码进入临界区,防止代码中断
    vPortEnterCritical();      
    debug_printfln("执行启动任务...");         

    // 2. 创建3个任务
    xTaskCreate(                                        /* 任务1 */
        taskFunc1,
        TASK_NAME_1,
        START_TASK_STACK_DEPTH,
        NULL,
        TASK1_PRIORITY,
        &task1TCB
    );
    xTaskCreate(                                        /* 任务2 */
        taskFunc2,
        TASK_NAME_2,
        START_TASK_STACK_DEPTH,
        NULL,
        TASK2_PRIORITY,
        &task2TCB
    );

    
    // 3. 代码退出临界区
    debug_printfln("启动任务执行完毕...\n回收启动任务...");
    vPortExitCritical();

    // 4. 回收启动任务
    vTaskDelete(NULL);
}

2.3 任务1

函数说明

  1. 串口打印Task1
  2. CPU延时200ms
  3. 相对延时1s
void taskFunc1(void *args)                                  /* 任务1执行函数 */
{
    while (1)
    {
        debug_printfln("Task1...");
        Delay_ms(200);
        vTaskDelay(1000);
    }
}

2.4 任务2

函数说明:

  1. 获取当前计数周期的值
  2. 打印Task2
  3. CPU延时200ms
  4. 绝对延时1s
void taskFunc2(void *args)                                  /* 任务2执行函数 */
{
    TickType_t tickCount = xTaskGetTickCount();
    while (1)
    {
        debug_printfln("Task2...");
        Delay_ms(200);
        vTaskDelayUntil(&tickCount, 1000);
    }
    
}

执行效果:

  • Task2进入阻塞的时间大致为1000-200
  • Task1进入阻塞的时间为1000

![[Pasted image 20250108151452.png]]

文章声明:
本文章为作者学习FreeRTOS实时操作系统的笔记与巩固输出,欢迎同行交流与指教,文章借鉴来源小破站的某谷RTOS教程。

FreeRTOSDemo.h

#ifndef __FREERTOS_DEMO_H
#define __FREERTOS_DEMO_H

/* 任务相关 */
#include "FreeRTOS.h"
#include "task.h"

#include "Common_Debug.h"
#include "Common_Delay.h"
#include "Inf_Key.h"


/* 1. 启动操作系统 */
void FreeRTOS_Start(void);

#endif


FreeRTOSDemo.c

#include "FreeRTOS_Demo.h"

/* 启动任务相关配置 */
void startTask(void *args);                                 /* 启动任务执行函数 */
#define START_TASK_NAME "start"                             /* 启动任务的名称 */
#define START_TASK_STACK_DEPTH 128                          /* 启动任务栈大小 = 2 * 128 字节 */
#define START_TASK_PRIORITY 4                               /* 启动任务优先级 */
TaskHandle_t startTaskTCB;                                  /* 启动任务的控制块 */

/* 2个子任务相关配置 */
/* --------------------Task1-------------------- */
void taskFunc1(void *args);                                 /* 任务1执行函数 */
#define TASK_NAME_1 "task1"                                 /* 任务1的名称 */
#define TASK1_PRIORITY 4                                    /* 任务1优先级 */
TaskHandle_t task1TCB;                                      /* 任务1的控制块 */
/* --------------------Task2-------------------- */
void taskFunc2(void *args);                                 /* 任务2执行函数 */
#define TASK_NAME_2 "task2"                                 /* 任务2的名称 */
#define TASK2_PRIORITY 3                                    /* 任务2优先级 */
TaskHandle_t task2TCB;                                      /* 任务2的控制块 */


void FreeRTOS_Start(void)
{

    /* 1. 创建启动任务 */
    xTaskCreate(
        startTask,
        START_TASK_NAME,
        START_TASK_STACK_DEPTH,
        NULL,
        START_TASK_PRIORITY,
        &startTaskTCB
    );

    /* 2. 启动任务调度器 */
    vTaskStartScheduler();
}

void startTask(void *args)
{
    // 1. 代码进入临界区,防止代码中断
    vPortEnterCritical();      
    debug_printfln("执行启动任务...");         

    // 2. 创建3个任务
    xTaskCreate(                                        /* 任务1 */
        taskFunc1,
        TASK_NAME_1,
        START_TASK_STACK_DEPTH,
        NULL,
        TASK1_PRIORITY,
        &task1TCB
    );
    xTaskCreate(                                        /* 任务2 */
        taskFunc2,
        TASK_NAME_2,
        START_TASK_STACK_DEPTH,
        NULL,
        TASK2_PRIORITY,
        &task2TCB
    );

    
    // 3. 代码退出临界区
    debug_printfln("启动任务执行完毕...\n回收启动任务...");
    vPortExitCritical();

    // 4. 回收启动任务
    vTaskDelete(NULL);
}

void taskFunc1(void *args)                                  /* 任务1执行函数 */
{
    while (1)
    {
        debug_printfln("Task1...");
        Delay_ms(200);
        vTaskDelay(1000);
    }
}

void taskFunc2(void *args)                                  /* 任务2执行函数 */
{
    TickType_t tickCount = xTaskGetTickCount();
    while (1)
    {
        debug_printfln("Task2...");
        Delay_ms(200);
        vTaskDelayUntil(&tickCount, 1000);
    }
    
}


extern void xPortSysTickHandler(void);
void        SysTick_Handler(void)
{
    if(xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
    {
        xPortSysTickHandler();
    }
}

### FreeRTOS 中实现绝对延时FreeRTOS 中,`xTaskDelayUntil()` 是用于实现绝对延时的主要函数。该函数允许任务按照固定的周期执行,即使中间有其他事件发生也不会影响下一次触发的时间点。 #### `xTaskDelayUntil()` 函数说明 此函数接收两个参数: - **pxPreviousWakeTime**: 指向保存上一次唤醒时间变量的指针。首次调用前需初始化为当前滴答计数值。 - **xTimeIncrement**: 延迟的时间长度,单位为 ticks(嘀嗒数),即每次循环之间的间隔时间。 通过这种方式可以确保定时器不会因为中断或其他因素而累积误差[^2]。 #### 使用示例 下面是一个简单的例子展示如何利用 `xTaskDelayUntil()` 来创建一个每秒打印一次消息的任务: ```c TickType_t xLastWakeTime; const TickType_t xFrequency = 1000 / portTICK_PERIOD_MS; // 设定频率为一秒 // 初始化上次唤醒时间为现在 xLastWakeTime = xTaskGetTickCount(); for (;;) { // 执行具体操作, 如打印信息 printf("Hello World\n"); // 让任务休眠直到下一个周期到来 vTaskDelayUntil(&xLastWakeTime, xFrequency); } ``` 在这个例子中,`xFrequency` 定义了两次连续运行之间所需的ticks数量,这里设置成大约一秒钟。当程序第一次遇到 `vTaskDelayUntil()` 调用时,它会记录此时作为下次应该被激活的确切时刻;之后每一次都会基于这个初始值加上指定增量来决定何时再次醒来继续工作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值