ESP32学习笔记_FreeRTOS(3)——SoftwareTimer

摘要(From AI):
这篇笔记全面介绍了 FreeRTOS 软件定时器的核心概念和使用方法,包括定时器的创建、管理、常用 API 和辅助函数,并通过示例代码演示了如何启动、重置和更改定时器的周期。它强调了软件定时器的灵活性、平台无关性以及与硬件定时器的对比

前言:本文档是本人在依照B站UP:Michael_ee的视频教程进行学习时所做的学习笔记,可能存在疏漏和错误,如有发现,望指正。

上一篇:ESP32学习笔记_FreeRTOS(2)——Queue

文章目录

  • Software Timer
    • Creating a Software Timer
      • xTimerCreate()
    • Managing Software Timers
      • xTimerStart()
      • xTimerStop()
      • pcTimerGetName()
      • pvTimerGetTimerID()
      • xTimerReset()
      • xTimerChangePeriod()
    • Example Code:Using Software Timers

参考资料:

[Michael_ee视频教程] https://www.bilibili.com/video/BV1Nb4y1q7xz?spm_id_from=333.788.videopod.sections&vd_source=4d8bd0ed3878ef81b239bf69bf38e741
freeRTOS官网
espressif 在线文档


Software Timer

硬件定时器会有数量等方面的限制,使用较不灵活,而软件定时器使用更为灵活,其与硬件、平台无关,在不同的 MCU 都可以使用 FreeRTOS API 进行调用

特性硬件定时器软件定时器
数量固定,受 MCU 硬件资源限制(通常只有几个)灵活,可以根据需要动态创建(受内存和任务管理能力限制)
依赖性依赖具体硬件平台,配置方式和功能因芯片而异与硬件平台无关,可通过 FreeRTOS API 在不同 MCU 上使用
精度高精度,直接由硬件计时,通常用于实时性要求高的场景精度依赖于 RTOS 的调度周期(tick 周期),不适合极高实时性场景
性能高性能,独立运行,不占用 CPU 资源运行在 RTOS 守护任务上下文中,占用 CPU 资源
适用场景适合时间敏感的应用,如 PWM 信号生成、脉冲捕获、输入输出事件计时等适合通用定时功能,如定时任务执行、软件超时处理等
灵活性配置固定,功能和用途受限灵活性高,可动态调整超时时间、回调函数等
使用复杂度配置复杂,需根据芯片手册手动设置寄存器使用方便,通过 FreeRTOS API 调用
移植性差,代码与硬件平台强耦合好,代码与硬件无关,便于跨平台移植

所有软件定时器的回调函数都在同一个RTOS守护任务(也称为“定时器服务任务”)的上下文中执行(该任务最初被称为“定时器服务任务”,因为最初它只用于执行软件定时器回调函数。现在同一任务也用于其他用途,因此被改名为更通用的“RTOS 守护任务”)
守护任务是一个标准的FreeRTOS任务,会在调度器启动时自动创建。其优先级和堆栈大小由编译时配置常量configTIMER_TASK_PRIORITYconfigTIMER_TASK_STACK_DEPTH分别设置,这两个常量在FreeRTOSConfig.h中定义

需要注意,软件定时器的回调函数是在 RTOS 守护任务的上下文中执行的,而不是在独立的任务中运行。因此,回调函数中不能调用可能使任务进入阻塞状态的 FreeRTOS API 函数,因为这会阻塞整个守护任务,导致系统运行异常

Creating a Software Timer

xTimerCreate()

xTimerCreate() 用于创建一个新的软件定时器,并返回一个句柄以引用创建的定时器

#include “FreeRTOS.h”
#include “timers.h”TimerHandle_t xTimerCreate( const char *pcTimerName,const TickType_t xTimerPeriod,const UBaseType_t uxAutoReload,void * const pvTimerID,TimerCallbackFunction_t pxCallbackFunction );

参数

  • pcTimerName定时器的名称,仅用于调试
  • xTimerPeriod定时器周期,单位为系统 tick,不能为 0。可以使用 pdMS_TO_TICKS()` 宏将毫秒转换为 tick。例如:
    • 100 tick直接设置为 100
    • 500ms可使用 pdMS_TO_TICKS(500),前提是 configTICK_RATE_HZ <= 1000
  • uxAutoReload设置定时器类型:
    • pdTRUE自动重载定时器(周期性触发)
    • pdFALSE一次性定时器(仅触发一次,可手动重新启动)
  • pvTimerID定时器标识符,用于在回调函数中区分不同的定时器,或在回调调用之间存储值
  • pxCallbackFunction:定时器到期时执行的回调函数,需符合 TimerCallbackFunction_t 原型:
void vCallbackFunctionExample(TimerHandle_t xTimer);

configTICK_RATE_HZ 是 FreeRTOS 配置文件 FreeRTOSConfig.h 中定义的一个宏,它表示 每秒系统 Tick 的次数,即 FreeRTOS 的调度器每秒中断的频率(单位为 Hz)
例如:
如果 configTICK_RATE_HZ = 1000,表示系统每 1 毫秒触发一次 Tick 中断
如果 configTICK_RATE_HZ = 100,表示系统每 10 毫秒触发一次 Tick 中断

返回值

  • NULL 定时器创建失败,原因可能是 FreeRTOS 堆内存不足
  • 其他值 定时器创建成功,返回的句柄可用于引用该定时器

配置要求(一般不用动)

  • FreeRTOSConfig.h 文件中,configUSE_TIMERSconfigSUPPORT_DYNAMIC_ALLOCATION 必须都设置为 1
  • 如果 configSUPPORT_DYNAMIC_ALLOCATION 未定义,其默认值为 1

创建定时器并不会立即启动。可以使用以下函数来启动或管理定时器

// 启动定时器。如果定时器已经在运行,则从当前时间重新开始。
BaseType_t xTimerStart( TimerHandle_t xTimer, TickType_t xTicksToWait );// 重置(重新启动)定时器。确保定时器启动或重新计算到期时间。
BaseType_t xTimerReset( TimerHandle_t xTimer, TickType_t xTicksToWait );// 从中断上下文启动定时器。等效于 xTimerStart(),用于中断中调用。
BaseType_t xTimerStartFromISR( TimerHandle_t xTimer,BaseType_t *pxHigherPriorityTaskWoken );// 从中断上下文重置(重新启动)定时器。等效于 xTimerReset(),用于中断中调用。
BaseType_t xTimerResetFromISR( TimerHandle_t xTimer,BaseType_t *pxHigherPriorityTaskWoken );// 更改定时器的周期。如果定时器未运行,则会启动定时器。
BaseType_t xTimerChangePeriod( TimerHandle_t xTimer,TickType_t xNewPeriod,TickType_t xTicksToWait );// 从中断上下文更改定时器的周期。等效于 xTimerChangePeriod(),用于中断中调用。
BaseType_t xTimerChangePeriodFromISR( TimerHandle_t xTimer,TickType_t xNewPeriod,BaseType_t *pxHigherPriorityTaskWoken );

Managing Software Timers

xTimerStart()

xTimerStart() 用于启动一个软件定时器的运行

  • 如果定时器尚未运行,xTimerStart() 会计算一个到期时间,该时间相对于调用 xTimerStart() 的时刻
  • 如果定时器已经在运行,则 xTimerStart() 相当于调用了 xTimerReset(),即重置定时器
  • 定时器会在定义的周期后(即 xTimerStart() 调用后 n 个 tick)触发回调函数,除非定时器在此期间被停止、删除或重置
#include “FreeRTOS.h”
#include “timers.h”BaseType_t xTimerStart( TimerHandle_t xTimer, TickType_t xTicksToWait );

参数

  • xTimer:要启动、重置或重新启动的定时器句柄
  • xTicksToWait指定调用任务在 timer command queue 队列已满的情况下,等待空间可用的最大时间(单位为 tick)。这是任务在进入 Blocked 状态时的阻塞时间。如果队列已满,任务会被阻塞,直到有足够的空间来发送命令
    • 设置 xTicksToWaitportMAX_DELAY 将导致任务无限期等待,直到队列中有空间
    • 如果在调度器启动之前调用 xTimerStart(),则 xTicksToWait 会被忽略

当任务调用 xTimerStart() 或其他定时器相关 API 时,这些命令并不会立即由任务执行,而是通过一个队列传递给定时器服务任务
如果队列已满,新的命令会被阻塞,直到队列有空间可用。这时,调用 xTimerStart() 等 API 的任务会根据指定的阻塞时间(xTicksToWait)进入阻塞状态,等待队列空间变得可用
timer command queue 的大小由 FreeRTOS 的配置项决定。队列的大小设置影响系统可以同时处理多少个定时器命令。如果队列大小太小,可能会导致命令丢失或任务阻塞:
configTIMER_QUEUE_LENGTH:定义了 timer command queue 队列的最大长度(即可以存放多少个定时器命令)

  • configUSE_TIMERS:必须设置为 1,才能启用定时器功能和相关队列

返回值

  • pdPASS启动命令成功发送到定时器命令队列。如果指定了阻塞时间(即 xTicksToWait 不为零),则可能会因为队列已满,任务进入阻塞状态等待空间释放,直到数据成功写入队列
    • 定时器命令的处理时间会根据定时器服务任务的优先级而有所不同,但定时器的到期时间是相对于实际调用 xTimerStart() 时刻(从队列中取出命令并实际启动定时器)的
    • 定时器命令的处理时间受定时器服务任务优先级的影响,定时器服务任务的优先级由 configTIMER_TASK_PRIORITY 配置常量设置
  • pdFAIL启动命令未成功发送到定时器命令队列,原因是队列已满。如果指定了阻塞时间,任务会被阻塞等待队列有空间,直到指定的阻塞时间过期,但仍未成功写入数据到队列

注意事项(一般不用动)
FreeRTOSConfig.h 中,configUSE_TIMERS 必须设置为 1,才能使用 xTimerStart() 函数

xTimerStop()

xTimerStop() 用于停止一个运行中的软件定时器

  • 调用 xTimerStop() 可以停止一个正在运行的定时器。如果定时器已经停止或已过期,则调用 xTimerStop() 不会产生影响。
  • xTimerStop() 向定时器命令队列发送停止命令,定时器服务任务会在稍后处理该命令。
#include “FreeRTOS.h”
#include “timers.h”BaseType_t xTimerStop( TimerHandle_t xTimer, TickType_t xTicksToWait );

参数

  • xTimer要停止的定时器句柄。
  • xTicksToWait指定任务在定时器命令队列已满的情况下,最大等待时间(单位为 ticks)

返回值

  • pdPASS
  • pdFAIL

pcTimerGetName()

pcTimerGetName() 用于返回在创建定时器时分配的可读文本名称

#include “FreeRTOS.h”
#include “timers.h”const char * pcTimerGetName( TimerHandle_t xTimer );

返回值

  • 返回值为一个指向定时器名称的指针。
  • 定时器名称是一个标准的以 NULL 结尾的 C 字符串。

pvTimerGetTimerID()

pvTimerGetTimerID() 用于返回与定时器关联的标识符(ID)

  • 返回在创建定时器时分配的标识符,该标识符可以通过 vTimerSetTimerID() API 更新
  • 在回调函数中可以使用该标识符区分哪个定时器到期,特别是在多个定时器共享相同的回调函数时
#include “FreeRTOS.h”
#include “timers.h”void *pvTimerGetTimerID( TimerHandle_t xTimer );

返回值

  • 返回与指定定时器关联的标识符(指针类型)

xTimerReset()

xTimerReset() 用于重置、启动或重新启动一个软件定时器,能够起到 Watch Dog 的作用

  • 如果定时器正在运行,xTimerReset() 会将定时器的到期时间重新计算为相对于调用时间的周期
  • 如果定时器未运行,xTimerReset() 会启动定时器,并将到期时间计算为相对于调用时间的周期。此时等效于 xTimerStart()
  • 无论定时器当前是否运行,调用 xTimerReset() 后,定时器都将开始运行
#include “FreeRTOS.h”
#include “timers.h”BaseType_t xTimerReset( TimerHandle_t xTimer, TickType_t xTicksToWait );

返回值

  • pdPASS
  • pdFAIL

xTimerChangePeriod()

xTimerChangePeriod() 用于更改软件定时器的周期

  • 更改运行中定时器的周期
    • 如果定时器正在运行,则新周期将用于重新计算到期时间。
    • 新的到期时间相对于调用 xTimerChangePeriod() 的时刻,而不是定时器最初启动的时刻。
  • 启动未运行的定时器
    • 如果定时器未运行,则定时器将使用新的周期值计算到期时间,并开始运行。
#include “FreeRTOS.h”
#include “timers.h”BaseType_t xTimerChangePeriod( TimerHandle_t xTimer,TickType_t xNewPeriod,TickType_t xTicksToWait );

参数

  • xTimer需要更改周期的定时器句柄
  • xNewPeriod定时器的新周期(单位为 tick)。可使用 pdMS_TO_TICKS() 将毫秒转换为 tick
  • xTicksToWait阻塞任务的最大时间(单位为 tick),如果定时器命令队列已满,则等待空间可用

返回值

  • pdPASS
  • pdFAIL

Example Code:Using Software Timers

#include <stdio.h>  
#include <inttypes.h>  
#include "sdkconfig.h"  
#include "freertos/FreeRTOS.h"  
#include "freertos/task.h"  
#include "esp_chip_info.h"  
#include "esp_flash.h"  
#include "esp_system.h"  #include "freertos/timers.h" // 定时器头文件  void TimerCallback(TimerHandle_t xTimer)  
{  const char *pcTimerName = pcTimerGetName(xTimer);// 获取定时器名称  uint32_t *uiTimerID = (uint32_t *)pvTimerGetTimerID(xTimer);// 获取定时器ID  printf("%s expired, ID: %lu.\n", pcTimerName, *uiTimerID);// 打印定时器名称和ID  
}  int id1 = 0;  
int id2 = 1;  void app_main(void)  
{  TimerHandle_t TimerHandle1 = NULL;  TimerHandle1 = xTimerCreate("Timer1", pdMS_TO_TICKS(1000), pdTRUE, (void *)&id1, TimerCallback);// 创建一个周期为1000ms的定时器  xTimerStart(TimerHandle1, 0);// 启动定时器  TimerHandle_t TimerHandle2 = NULL;  TimerHandle2 = xTimerCreate("Timer2", pdMS_TO_TICKS(2000), pdTRUE, (void *)&id2, TimerCallback);// 与Timer1公用同一个回调函数,观察pcTimerGetName的输出  xTimerStart(TimerHandle2, 0);// 启动定时器  // for(int i = 0; i < 10; i++)  // {    //     vTaskDelay(pdMS_TO_TICKS(1000));    //     xTimerReset(TimerHandle2, 0);// 重置定时器,观察pcTimerGetName的输出,此时Timer2不会被打印  // }  vTaskDelay(pdMS_TO_TICKS(5000));  xTimerChangePeriod(TimerHandle2, pdMS_TO_TICKS(1000), 0);// 修改Timer2的周期为1000ms  vTaskDelay(pdMS_TO_TICKS(5000));  xTimerStop(TimerHandle1, 0);// 停止定时器  xTimerStop(TimerHandle2, 0);// 停止定时器  
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/478788.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【前端】ES6基础

1.开发工具 vscode地址 :https://code.visualstudio.com/download, 下载对应系统的版本windows一般都是64位的 安装可以自选目录&#xff0c;也可以使用默认目录 插件&#xff1a; 输入 Chinese&#xff0c;中文插件 安装&#xff1a; open in browser&#xff0c;直接右键文件…

代码美学:MATLAB制作渐变色

输入颜色个数n&#xff0c;颜色类型&#xff1a; n 2; % 输入颜色个数 colors {[1, 0, 0], [0, 0, 1]}; createGradientHeatmap(n, colors); 调用函数&#xff1a; function createGradientHeatmap(n, colors)% 输入检查if length(colors) ~ nerror(输入的颜色数量与n不一…

【Reinforcement Learning】强化学习下的多级反馈队列(MFQ)算法

&#x1f4e2;本篇文章是博主强化学习&#xff08;RL&#xff09;领域学习时&#xff0c;用于个人学习、研究或者欣赏使用&#xff0c;并基于博主对相关等领域的一些理解而记录的学习摘录和笔记&#xff0c;若有不当和侵权之处&#xff0c;指出后将会立即改正&#xff0c;还望谅…

103.【C语言】数据结构之TopK问题详细分析

目录 1.定义 2.实现 一个容易想到的方法 稍微改进的方法 最优的方法 分析方法的可行性 取出无序数组的取出前K个元素有几种可能 1.取的全是非TopK个元素中的 2.取的前K个既有非TopK个元素也有TopK个元素 3.取的前K个q恰为TopK个元素 代码实现 步骤 TestTopK代码 …

国土变更调查拓扑错误自动化修复工具的研究

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 一、拓扑错误的形成原因 1.边界不一致 2.不规则图形 3.尖锐角 4.局部狭长 5.细小碎面 6.更新层相互重叠 二、修复成果展示 1.边界不一致 2.不规则图形 3.尖锐角 4.局部狭…

【C++ 算法进阶】算法提升二十三

目录 左右数组相减绝对值最大值 &#xff08;题意代换&#xff09;题目题目分析 可整合数组 &#xff08;题意代换&#xff09;题目题目分析代码 水王问题题目题目分析代码水王问题变形思路讲解 合并石头的最低成本 &#xff08;动态规划&#xff09;题目题目分析代码 左右数组…

质量留住用户:如何通过测试自动化提供更高质量的用户体验

在当今竞争异常激烈的市场中&#xff0c;用户手头有无数种选择&#xff0c;但有一条真理至关重要&#xff1a; 质量留住用户。 产品的质量&#xff0c;尤其是用户体验 (UX)&#xff0c;直接决定了客户是留在您的品牌还是转而选择竞争对手。随着业务的发展&#xff0c;出色的用户…

Redis 可观测最佳实践

Redis 介绍 Redis 是一个开源的高性能键值对&#xff08;key-value&#xff09;数据库。它通常用作数据库、缓存和消息代理。Redis 支持多种类型的数据结构&#xff0c;Redis 通常用于需要快速访问的场景&#xff0c;如会话缓存、全页缓存、排行榜、实时分析等。由于其高性能和…

idea怎么打开两个窗口,运行两个项目

今天在开发项目的时候&#xff0c;前端希望运行一下以前的项目&#xff0c;于是就需要开两个 idea 窗口&#xff0c;运行两个项目 这里记录一下如何设置&#xff1a;首先依次点击&#xff1a; File -> Settings -> Appearance & Behavior ->System Settings 看到如…

加速科技精彩亮相中国国际半导体博览会IC China 2024

11月18日—20日&#xff0c;第二十一届中国国际半导体博览会&#xff08;IC China 2024&#xff09;在北京国家会议中心顺利举办&#xff0c;加速科技携重磅产品及全系测试解决方案精彩亮相&#xff0c;加速科技创始人兼董事长邬刚受邀在先进封装创新发展论坛与半导体产业前沿与…

JSON 性能测试 - WastJson 性能也很快

WAST 是一个高性能 Java 工具集库包&#xff0c;包括 JSON、YAML、CSV、HttpClient、JDBC 和 EL 引擎. WastJson 无论是小中大文本各种数据类型等性能都没有明显的短板&#xff0c;除了推广外可以说是六边形战士&#xff0c;更多测试参考 wast-jmh-test: wast性能测试 (并非所…

【小白学机器学习34】用python进行基础的数据统计 mean,var,std,median,mode ,四分位数等

目录 1 用 numpy 快速求数组的各种统计量&#xff1a;mean, var, std 1.1 数据准备 1.2 直接用np的公式求解 1.3 注意问题 1.4 用print() 输出内容&#xff0c;显示效果 2 为了验证公式的后背&#xff0c;下面是详细的展开公式的求法 2.1 均值mean的详细 2.2 方差var的…

视频推拉流EasyDSS互联网直播点播平台技术特点及应用场景剖析

在数字科技日新月异的今天&#xff0c;视频直播和点播已经成为互联网内容传播的重要方式之一。而互联网直播点播平台EasyDSS作为功能强大的流媒体直播点播视频能力平台&#xff0c;提供了一站式的视频推拉流、转码、直播、点播、时移回放、存储等视频服务&#xff0c;广泛应用于…

【测试工具JMeter篇】JMeter性能测试入门级教程(一)出炉,测试君请各位收藏了!!!

一、前言 Apache JMeter是纯Java的开源软件&#xff0c;最初由Apache软件基金会的Stefano Mazzocchi开发&#xff0c;旨在加载测试功能行为和测量性能。可以使用JMeter进行性能测试&#xff0c;即针对重负载、多用户和并发流量测试Web应用程序。 我们选择JMeter原因 是否测试过…

ffmpeg视频滤镜:提取缩略图-framestep

滤镜描述 官网地址 > FFmpeg Filters Documentation 这个滤镜会间隔N帧抽取一帧图片&#xff0c;因此这个可以用于设置视频的缩略图。总体上这个滤镜比较简单。 滤镜使用 滤镜参数 framestep AVOptions:step <int> ..FV....... set frame st…

Spring源码(十三):Spring全系列总结

Spring总结篇,不同于之前抽丝剥茧式地纵向深入源码,本次从横向的角度出发,希望可以带个读者一个完全不同的Spring视角。 2024年重置版,搞点不一样的东西。希望通过本篇的内容,将之前的文章全部给串起来。 相关前文: Spring Boot启动加载Spring Web请求处理流程Spring上…

【AIGC】如何准确引导ChatGPT,实现精细化GPTs指令生成

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: AIGC | 提示词Prompt应用实例 文章目录 &#x1f4af;前言&#x1f4af;准确引导ChatGPT创建爆款小红书文案GPTs指令案例&#x1f4af; 高效开发GPTs应用的核心原则明确应用场景和目标受众构建多样化风格模板提问与引…

电影风格城市夜景旅拍Lr调色教程,手机滤镜PS+Lightroom预设下载!

调色教程 电影风格城市夜景旅拍通过 Lightroom 调色&#xff0c;将城市夜晚的景色打造出如同电影画面般的质感和氛围。以独特的色彩和光影处理&#xff0c;展现出城市夜景的魅力与神秘。 预设信息 调色风格&#xff1a;电影风格预设适合类型&#xff1a;人像&#xff0c;街拍…

拥抱极简主义前端开发:NoCss.js 引领无 CSS 编程潮流

在前端开发的世界里&#xff0c;我们总是在不断追寻更高效、更简洁的方式来构建令人惊艳的用户界面。而今天&#xff0c;我要向大家隆重介绍一款具有创新性的工具 ——NoCss.js&#xff0c;它将彻底颠覆你对传统前端开发的认知&#xff0c;引领我们进入一个全新的无 CSS 编程时…

【JavaEE初阶】多线程初阶下部

文章目录 前言一、volatile关键字volatile 能保证内存可见性 二、wait 和 notify2.1 wait()方法2.2 notify()方法2.3 notifyAll()方法2.4 wait 和 sleep 的对比&#xff08;面试题&#xff09; 三、多线程案例单例模式 四、总结-保证线程安全的思路五、对比线程和进程总结 前言…