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);// 停止定时器  
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

探秘嵌入式位运算:基础与高级技巧

目录 一、位运算基础知识 1.1. 位运算符 1.1.1. 与运算&#xff08;&&#xff09; 1.1.2. 或运算&#xff08;|&#xff09; 1.1.3. 异或运算&#xff08;^&#xff09; 1.1.4. 取反运算&#xff08;~&#xff09; 1.1.5. 双重按位取反运算符&#xff08;~~&#xf…

SpringBoot - 优雅的实现【账号登录错误次数的限制和锁定】

文章目录 Pre需求实现步骤简易实现1. 添加依赖2. 配置文件3. 自定义注解4. AOP切面5. 使用自定义注解&#xff1a;6. 测试 附总结 Pre SpringBoot - 优雅的实现【流控】 需求 需求描述&#xff1a; 登录错误次数限制&#xff1a;在用户登录时&#xff0c;记录每个账号的登录错…

SRIO DRP动态速率配置说明(详细讲解)

目录 一、SRIO IP时钟结构 1、时钟内部结构 2、时钟直接的关系 3、时钟计算原理 ​二、SRIO DRP介绍 ​1、MMCM DRP配置(xapp888) 2、CPLL DRP配置(ug476) 关于CPLL DRP配置详细介绍&#xff1a; GTX中CPLL、QPLL DRP动态配置方法&#xff08;详解&#xff09;-CSDN博客…

动态规划之背包问题

0/1背包问题 1.二维数组解法 题目描述&#xff1a;有一个容量为m的背包&#xff0c;还有n个物品&#xff0c;他们的重量分别为w1、w2、w3.....wn&#xff0c;他们的价值分别为v1、v2、v3......vn。每个物品只能使用一次&#xff0c;求可以放进背包物品的最大价值。 输入样例…

推荐一款龙迅HDMI2.0转LVDS芯片 LT6211UX LT6211UXC

龙迅的HDMI2.0转LVDS芯片LT6211UX和LT6211UXC是两款高性能的转换器芯片&#xff0c;它们在功能和应用上有所差异&#xff0c;同时也存在一些共同点。以下是对这两款芯片的详细比较和分析&#xff1a; 一、LT6211UX 主要特性&#xff1a; HDMI2.0至LVDS和MIPI转换器。HDMI2.0输…

深度学习模型:循环神经网络(RNN)

一、引言 在深度学习的浩瀚海洋里&#xff0c;循环神经网络&#xff08;RNN&#xff09;宛如一颗独特的明珠&#xff0c;专门用于剖析序列数据&#xff0c;如文本、语音、时间序列等。无论是预测股票走势&#xff0c;还是理解自然语言&#xff0c;RNN 都发挥着举足轻重的作用。…

[STM32]从零开始的STM32 FreeRTOS移植教程

一、前言 如果能看到这个教程的话&#xff0c;说明大家已经学习嵌入式有一段时间了。还记得嵌入式在大多数时候指的是什么吗&#xff1f;是的&#xff0c;我们所说的学习嵌入式大部分时候都是在学习嵌入式操作系统。从简单的一些任务状态机再到复杂一些的RTOS&#xff0c;再到最…

《操作系统 - 清华大学》5 -4:虚拟技术

文章目录 0. 虚拟存储的定义1. 目标2.局部性原理3. 虚拟存储的思路与规则4. 虚拟存储的基本特征5. 虚拟页式存储管理5.1 页表表项5.2 示例 0. 虚拟存储的定义 1. 目标 虚拟内存管理技术&#xff0c;简称虚存技术。那为什么要虚存技术&#xff1f;在于前面覆盖和交换技术&#…

2024APMCM亚太杯数学建模C题【宠物行业】原创论文分享

大家好呀&#xff0c;从发布赛题一直到现在&#xff0c;总算完成了2024 年APMCM亚太地区大学生数学建模竞赛C题的成品论文。 给大家看一下目录吧&#xff1a; 目录 摘 要&#xff1a; 10 一、问题重述 14 二&#xff0e;问题分析 15 2.1问题一 15 2.2问题二 15 2.3问题三…

YOLOv8模型pytorch格式转为onnx格式

一、YOLOv8的Pytorch网络结构 model DetectionModel((model): Sequential((0): Conv((conv): Conv2d(3, 64, kernel_size(3, 3), stride(2, 2), padding(1, 1))(act): SiLU(inplaceTrue))(1): Conv((conv): Conv2d(64, 128, kernel_size(3, 3), stride(2, 2), padding(1, 1))(a…

零基础3分钟快速掌握 ——Linux【终端操作】及【常用指令】Ubuntu

1.为啥使用Linux做嵌入式开发 能广泛支持硬件 内核比较高效稳定 原码开放、软件丰富 能够完善网络通信与文件管理机制 优秀的开发工具 2.什么是Ubuntu 是一个以桌面应用为主的Linux的操作系统&#xff0c; 内核是Linux操作系统&#xff0c; 具有Ubuntu特色的可视…

VScode 连不上远程云服务器

今天下午写代码&#xff0c;打开 VScode 突然发现连不上云服务器了&#xff0c;一开始以为自己密码输错了&#xff0c;试了好多次&#xff0c;依然是这样的 经过查资料发现&#xff0c;应该是版本的自动升级导致的&#xff01;解决方案如下&#xff1a; 1、删除 windows 端的 …

图像分割——区域增长

一 区域增长 图像灰度阈值分割技术都没有考虑到图像像素空间的连通性。区域增长法则正好相反,顾及像素的连接性. 方法&#xff1a;1&#xff09;选择一个或一组种子&#xff1b; 2&#xff09;选择特征及相似性判决准则&#xff1b; 3&#xff09;从该种子开始向外生长&#x…

音视频相关的一些基本概念

音视频相关的一些基本概念 文章目录 音视频相关的一些基本概念RTTH264profile & levelI帧 vs IDRMP4 封装格式AAC封装格式TS封装格式Reference RTT TCP中的RTT指的是“往返时延”&#xff08;Round-Trip Time&#xff09;&#xff0c;即从发送方发送数据开始&#xff0c;到…

春秋云境 CVE 复现

CVE-2022-4230 靶标介绍 WP Statistics WordPress 插件13.2.9之前的版本不会转义参数&#xff0c;这可能允许经过身份验证的用户执行 SQL 注入攻击。默认情况下&#xff0c;具有管理选项功能 (admin) 的用户可以使用受影响的功能&#xff0c;但是该插件有一个设置允许低权限用…

Linux—进程概念学习-03

目录 Linux—进程学习—31.进程优先级1.1Linux中的进程优先级1.2修改进程优先级—top 2.进程的其他概念3.进程切换4.环境变量4.0环境变量的理解4.1环境变量的基本概念4.2添加环境变量—export4.3Linux中环境变量的由来4.4常见环境变量4.5和环境变量相关的命令4.6通过系统调用获…

go语言逆向-基础basic

文章目录 go 编译命令 ldflags -w -s的作用和问题使用 file 命令查看文件类型 go 语言逆向参考go ID版本GOROOT和GOPATHGOROOTGOPATHGOROOT和GOPATH的关系示例 go build和 go modpclntab &#xff08;Program Counter Line Table 程序计数器行数映射表&#xff09;Moduledata程…

RAG架构类型

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

PostgreSQL详细安装教程

#安装PostgreSQL的yum仓库 sudo yum install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm#安装PostgreSQL 15版本 sudo yum install -y postgresql15-server#初始化数据库&#xff08;若要自定义数据库存储目录…

uniapp介入极光推送教程 超级详细

直接按照下面教程操作 一步一步来 很快就能 完成 下面的文章非常详细 &#xff0c;我就不班门弄斧了 直接上原文链接 https://blog.csdn.net/weixin_52830464/article/details/143823231