浅析 FreeRTOS SysTick 和任务延时

这篇具有很好参考价值的文章主要介绍了浅析 FreeRTOS SysTick 和任务延时。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

浅析 FreeRTOS SysTick 和任务延时

概述

FreeRTOS 提供的最小时间单元为一个 SysTick,举例:
假设配置 RTOS 的 SysTick 为 100Hz,则 RTOS 能提供的最小时间单位为 1/100 s,即 10ms. 即一个 RTOS 的系统时钟为 10ms.
FreeRTOS 自带了一个 SysTick 计数器,任务调度器启用后,每个 SysTick 发生,该计数器就加一。可以通过下述函数获取任务调度器当前运行了几个 SysTick:

TickType_t xTaskGetTickCount(void)

通常,这个 API 可以用来测试 TaskCode 中的一段代码的运行时间:

TickType_t xLastWakeTime;
xLastWakeTime = xTaskGetTickCount ();
// dosomethings
code();
xLastWakeTime = xTaskGetTickCount () - xLastWakeTime;

上述示例计算 code()共消耗了多少个 SysTick,假设当前的 SysTick 为 上述的 100Hz,当前消耗了 10个 SysTick,则实际消耗时间为 10* 10ms = 100ms.
FreeRTOS 中提供了一个宏来完成 SysTick 到 毫秒单位的转换:

#define pdMS_TO_TICKS( xTimeInMs )    ( ( TickType_t ) ( ( ( TickType_t ) ( xTimeInMs ) * ( TickType_t ) configTICK_RATE_HZ ) / ( TickType_t ) 1000U ) )

将 10 SysTick 转为 ms 单位,使用 pdMS_TO_TICKS(10)即可。

要改变RTOS 的 SysTick 的大小,可以改变宏 configTICK_RATE_HZ的值,在 ESP32 的开发环境中,使用 idf.py menuconfig命令在下述图形界面改变 SysTick 的值即可。
xtaskgettickcount,ESP32 FreeRTOS-基础篇,ESP,c语言,物联网,单片机,iot,risc-v

注意,SysTick 决定了 RTOS 的最小时间单位,因此,当 SysTick 为 100Hz 时,最小时间单位为 10ms,比这更小的时间需求,如延时,定时需求将不容易通过 RTOS 的系统接口实现。增大 SysTick 提高时间的精确度诚然可行,但当 SysTick 过大,系统的运算需求和负载(中断切换时间)也将变大,可能导致设备变热和运行问题。

在了解 SysTick 的基础上,我们可以研究 RTOS 两种延时函数的使用和异同:
1)相对延时:

void vTaskDelay(const TickType_t xTicksToDelay) // 参数为要延时的 SysTick 数目

2)绝对延时:

BaseType_t vTaskDelayUntil(TickType_t *const pxPreviousWakeTime, const TickType_t xTimeIncrement) // 参数为要延时起始的 SysTick 时刻,和相对起始时刻的时间间隔

两者都可以实现延时,进入延时后的函数将进入休眠状态,等指定的几个 SysTick 后,任务会被唤醒,重新进入可执行的就绪状态。注意,唤醒后的任务并不一定是立即运行的,只是进入一个就绪状态,只有其优先级足够高,才能被任务调度器赋予其 CPU 使用权,进入运行状态。

两者的不同:

1)传的参数不同。

2)进入休眠状态的时机不一样:
xtaskgettickcount,ESP32 FreeRTOS-基础篇,ESP,c语言,物联网,单片机,iot,risc-v
vTaskDelay(2) 在执行时,假设期望在 Tick2 得到执行,但此时 CPU 被其他任务抢占,则实际 vTaskDelay(2) 并没有在 Tick2 得到执行,而是在该任务重庆获取 CPU 后的 Tick4 成功调用 vTaskDelay(2) ,之后延时两个 SysTick,在Tick6 被唤醒。

vTaskDelayUntil(2,2) 则不同,它可以指定计算 SysTick 的起始时刻,指定其开始的 SysTick 为 Tick2 后,其一定在 Tick4 得到唤醒。 因此,后者延时的准确性、可控制性更好。

需求及功能解析

示例延时了两种延时的区别:

1)vTaskDelay():

static void task1_process(void *arg)
{
    static const char *TASK1_TAG = "TASK1";
    TickType_t last_wake_time = 0;
    TickType_t ticks_before_delay = 0;
    ticks_before_delay = xTaskGetTickCount();
    while (1) {
        esp_rom_delay_us(100*1000); // 模拟有其他任务或者系统中断抢占 CPU,导致延迟进入 vtaskdelay()
        task1_flag++;
        vTaskDelay(pdMS_TO_TICKS(1000));
        last_wake_time = xTaskGetTickCount();
        printf("%s: tick used=%dms\r\n", TASK1_TAG, TICKS_TO_MS(last_wake_time-ticks_before_delay));
        ticks_before_delay = last_wake_time;
    }
}

2)vTaskDelayUntil():

static void task2_process(void *arg)
{
    static const char *TASK2_TAG = "TASK2";
    TickType_t ticks_before_delay;;
    TickType_t last_wake_time = 0;
    last_wake_time = xTaskGetTickCount();
    ticks_before_delay = last_wake_time;

    while (1) {
        esp_rom_delay_us(100*1000); // 模拟有其他任务或者系统中断抢占 CPU
        task2_flag++;
        vTaskDelayUntil(&last_wake_time, pdMS_TO_TICKS(1000)); // 注意,使用后,last_wake_time 的值会被更新为当下的系统 systick.
        printf("%s: tick used=%dms\r\n", TASK2_TAG, TICKS_TO_MS(xTaskGetTickCount() - ticks_before_delay));
        ticks_before_delay = last_wake_time;
    }
    vTaskDelete(NULL);
}

示例解析

示例输出:

This is esp32 chip with 2 CPU core(s), WiFi/BT/BLE, Minimum free heap size: 294424 bytes
TASK2: tick used=1000ms
TASK1: tick used=1100ms
TASK3: use time=1095764us
TASK2: tick used=1000ms
TASK1: tick used=1100ms
TASK3: use time=1099870us

示例中使用 esp_rom_delay_us(100*1000) 模拟有其他任务或者系统中断抢占 CPU的情况,该函数实际是一个 while 实现的让 CPU 空转指定时间的函数。

当希望实现延时为 1000ms 的延时时。与上述的延时原理一致,使用vTaskDelayUntil() 的 Task2 每次运行的 tick used = 1000ms,即实现了较为准确的周期为 1000ms 的延时执行。而使用 vTaskDelay() 的 Task1 则因为进入睡眠的延时,导致实际延时为1100ms。

最后,Task3 演示了vTaskDelay() 中使用的参数的单位为几个 SysTick,并不是实际的 ms 单位。使用 esp_timer_get_time()可以获得较为准确的系统时间。

讨论

尝试改变 ESP32 的 SysTick,观察系统延时精度及上诉函数返回值的变化。

总结

1)FreeRTOS 提供的最小时间单元为一个 SysTick,使用 xTaskGetTickCount() 可以获得自任务调度器启用后,系统一共运行了几个 SysTick 了。

2)FreeRTOS 提供了两种系统延时函数 vTaskDelay()、vTaskDelayUntil(),两者都可以实现延时,进入延时后的函数将进入休眠状态,等指定的几个 SysTick 后,任务会被唤醒,重新进入可执行的就绪状态。注意,唤醒后的任务并不一定是立即运行的,只是进入一个就绪状态,只有其优先级足够高,才能被任务调度器赋予其 CPU 使用权,进入运行状态。特别注意,两者进入睡眠的时机和真正延时时间上的区别。

3)SysTick 与 时间单位的转换可以使用宏 pdMS_TO_TICKS()TICKS_TO_MS()

资源链接

1)Learning-FreeRTOS-with-esp32 系列博客介绍
2)对应示例的 code 链接 (点击直达代码仓库)

3)下一篇:FreeRTOS 任务通知浅析文章来源地址https://www.toymoban.com/news/detail-622297.html

到了这里,关于浅析 FreeRTOS SysTick 和任务延时的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【HAL库】STM32CubeMX开发----非阻塞延时实验----SysTick(滴答定时器)中断

    STM32CubeMX 下载和安装 详细教程 【HAL库】STM32CubeMX开发----STM32F103/F207/F407----目录 HAL库 有自带的 ms级 延时函数: HAL_Delay(); 缺点: 这是 阻塞延时 方式,就是延时期间,什么都不能干,这样很浪费资源。 这篇文章主要介绍,利用 SysTick(滴答定时器)中断 实现 非阻塞延时 的实验

    2024年02月16日
    浏览(40)
  • 1902_野火FreeRTOS教程内核在STM32中用到的2个中断PENDSV和SYSTICK

    全部学习汇总:  g_FreeRTOS: FreeRTOS学习笔记 (gitee.com) 上面是涉及到的源代码,而这次需要分析的就是78、79行的两个中断。首先,需要确认NVIC_SYSPRI2寄存器的作用。 进一步看里面相关的定义,从这里看这个注释与代码出现了不一致的地方。也就是这个 0xe000ed20地址究竟是哪一

    2024年02月21日
    浏览(30)
  • STM32CubeMx学习FreeRTOS的绝对延时和相对延时

    在阻塞状态中 可以空闲出时间 来让低优先级的任务可以进行 有两种阻塞延时 一个是相对延时 也就是  这样的osDelay可以让在到这里的时候,延时500ms 也就是程序到这里才500ms 不记程序前面所用的时间 而还有一个绝对延时 绝对延时指的是 加上程序自己跑的时间 全部的一起

    2024年02月14日
    浏览(28)
  • HAL STM32基于系统滴答定时器(SysTick)实现多任务时间片轮询

    📑RTOS(实时操作系统)和定时器时间片轮询是两种不同的任务调度和执行方式的差异简介 🔖 以下部分内容,由AI给出的解答: 🔖RTOS(实时操作系统): 🌿RTOS是一种专门设计用于实时系统的操作系统,它可以有效地管理多个任务,提供任务调度、同步和通信等功能。 🌿

    2024年02月21日
    浏览(36)
  • 【ESP32】arduino中的ESP32实时系统FreeRTOS使用教程(一)

    简单的本节略过,详细的可以看视频:单片机ESP32上的FREERTOS这个作者讲的挺好的,通俗易懂 FreeRTOS中的任务有运行态、就绪态、阻塞态、挂起态四种状态,在任何时候都只处于其中一种状态。任务状态之间的转换如下图所示: 每一个任务都会有一个任务优先级,其范围为

    2023年04月15日
    浏览(33)
  • 【Arduino 时间函数】ESP32怎么实现微秒级延时,适用于ESP8266等

    如果基于 Arduino 开发 ESP32 ,则延时函数可以直接使用 Arduino 提供的时间函数。 Arduino提供四种不同的时间操作函数。 delay() 函数 delayMicroseconds() 函数 一毫秒内有一千微秒,一秒内有一百万微秒。 millis() 函数 此函数用于返回Arduino板开始运行当前程序时的毫秒数。 micros() 函数

    2024年02月13日
    浏览(34)
  • 了解 ESP32 FreeRTOS:初学者指南

    ESP32 FreeRTOS是针对ESP32微控制器的一个实时操作系统(RTOS),它采用了FreeRTOS内核,可以帮助开发人员在ESP32芯片上进行多任务处理。简单来说,FreeRTOS提供了一种方式来管理软件任务并协调它们的执行。 ESP32是一个功能强大的嵌入式系统,可以用于构建各种物联网应用程序。

    2023年04月14日
    浏览(44)
  • STM32+FREERTOS任务堆栈大小

    在FREERTOS任务开发过程中,由于不知道具体需要分配多大的任务堆栈大小,就需要在开始开发阶段尽可能的多分配一些,不然在调试过程中会出现程序卡死或者数据通信异常的现象。 如何评估任务堆栈的分配大小问题,可以根据任务的规模以及所任务所需的数据空间大概进行

    2024年02月16日
    浏览(33)
  • 基于STM32+FreeRtos+ESP8266+MQTT连接阿里云

    实现通过stm32f103c8t6+操作系统(freertos)读取dht12温湿度传感器的数据,采用ESP8266连接网络,经过MQTT协议连接阿里云IOT,进行数据的传输,以及服务器发送数据控制LED的亮灭,包括消息的发布和订阅等操作,完成云端和设备端的通讯。 首先,我们使用MQTT.fx模拟器,通过模拟的

    2024年02月06日
    浏览(36)
  • FreeRTOS源码分析-4 SysTick系统时钟详解

    目录 1 SysTick初始化 2 SysTick中断服务函数 3 SysTick任务调度 初始化流程 配置SysTick装载值 使能SysTick时钟源 使能SysTick中断 使能SysTick 其中装载值1ms、10ms、100ms都可以,但是不要小于1ms 系统节拍初始化源码 在vPortSetupTimerInterrupt中 中断服务函数流程: 关闭中断 Tick值增加SysTick任

    2024年02月16日
    浏览(25)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包