FreeRTOS学习笔记(十)软件定时器

文章目录

  • 前言
  • 一、软件定时器
    • [1.1 软件定时器的引入](#1.1 软件定时器的引入)
    • [1.2 定时器服务](#1.2 定时器服务)
    • [1.3 运行机制](#1.3 运行机制)
  • 二、软件定时器的实现
    • [2.1 相关配置](#2.1 相关配置)
    • [2.2 相关API](#2.2 相关API)
      • [2.2.1 创建软件定时器](#2.2.1 创建软件定时器)
      • [2.2.2 复位软件定时器](#2.2.2 复位软件定时器)
      • [2.2.3 开启软件定时器](#2.2.3 开启软件定时器)
      • 2.2.4停止软件定时器

前言

FreeRTOS 软件定时器是一种方便的工具,适用于对时间精度要求不高的延时任务或周期性任务。通过软件定时器,任务可以在不占用大量资源的情况下实现定时功能,而不需要手动管理硬件定时器或复杂的中断逻辑。


一、软件定时器

1.1 软件定时器的引入

提到MCU的开发,我们就绕不过一个老朋友------定时器,有的 MCU 其定时器功能异常强大,通过定时器我们可以完成需要周期性处理的事务。但是硬件资源终究还是有限的,对此我们也可以使用FreeRTOS提供的定时器功能,不过是软件定时器,软件定时器的精度肯定没有硬件定时器那么高,但是对于普通的精度要求不高的周期性处理的任务来说够了。

FreeRTOS 的软件定时器(Software Timers)是一种灵活的机制,允许任务以延时的方式执行特定功能,且无需占用大量系统资源。软件定时器不像硬件定时器那样直接依赖于物理计时硬件,而是通过 FreeRTOS 的时钟滴答(tick count)来驱动,从而为任务提供定时回调功能。

1.2 定时器服务

定时器是一个可选的、不属于 FreeRTOS 内核的功能,它是由定时器服务(也叫Daemon)任务来提供的。FreeRTOS 提供了很多定时器有关的 API 函数,这些 API 函数大多都使用 FreeRTOS的队列发送命令给定时器服务任务。这个队列叫做定时器命令队列,它是提供给FreeRTOS 的软件定时器使用的,用户不能直接访问。

左侧部分属于用户应用程序的一部分,并且会在某个用户创建的用户任务中调用。图中右侧部分是定时器服务任务的任务函数,定时器命令队列将用户应用任务和定时器服务任务连接在一起。在这个例子中,应用程序调用了函数 xTimerReset(),结果就是复位命令会被发送到定时器命令队列中,定时器服务任务会处理这个命令。应用程序是通过函数 xTimerReset()间接的向定时器命令队列发送了复位命令,并不是直接调用类似 xQueueSend()这样的队列操作函数发送的。

1.3 运行机制

由于所有定时器事件都是通过定时器服务任务来调度和处理的,所以当我们使用 FreeRTOS 的软件定时器 API(如 xTimerCreate()、xTimerStart() 等)时,你无需自行管理定时器中断或滴答定时器。简单机制如下:

  1. 创建定时器:使用 API 创建定时器后,定时器不会立即运行,而是注册到定时器服务任务中。
  2. 定时器服务任务调度:FreeRTOS 中有一个特殊的定时器服务任务,负责监控所有注册的定时器。
  3. 触发时执行回调函数:当定时器达到指定的超时时间后,定时器服务任务就会调用你为定时器定义的回调函数。
    注:超时回调函数是在Daemon中作用的,要尽快处理不要使用延时操作,以便于不影响其他的软件定时器。

二、软件定时器的实现

2.1 相关配置

configUSE_TIMERS

如果要使用软件定时器的话宏 configUSE_TIMERS 一定要设置为 1,当设置为 1 的话定时器服务任务就会在启动 FreeRTOS 调度器的时候自动创建。

configTIMER_TASK_PRIORITY

设置软件定时器服务任务的任务优先级(0 ~ configMAX_PRIORITIES-1)。优先级一定要根据实际的应用要求来设置。如果定时器服务任务的优先级设置的高的话,定时器命令队列中的命令和定时器回调函数就会及时的得到处理。

configTIMER_QUEUE_LENGTH

此宏用来设置定时器命令队列的队列长度。

configTIMER_TASK_STACK_DEPTH

此宏用来设置定时器服务任务的任务堆栈大小,单位为字(16 bit)。对于 STM32 来说一个字是 4 字节。由于定时器服务任务中会执行定时器的回调函数,因此任务堆栈的大小一定要根据定时器的回调函数来设置。

2.2 相关API

2.2.1 创建软件定时器

这里我们常用xTiemrCreate(),此函数用于创建一个软件定时器,所需要的内存通过动态内存管理方法分配。新创建的软件定时器处于休眠状态 ,可以利用其他函数使其进入活动状态,此函数的原型如下:

c 复制代码
TimerHandle_t xTimerCreate( const char * const pcTimerName,
 			TickType_t xTimerPeriodInTicks, UBaseType_t uxAutoReload,
 			void * pvTimerID, TimerCallbackFunction_t pxCallbackFunction )
  • 参数:
    • pcTimerName: 软件定时器名字,名字是一串字符串,用于调试使用。
    • xTimerPeriodInTicks : 软件定时器的定时器周期, 单位是时钟节拍数。
      注:可以借助portTICK_PERIOD_MS 将 ms 单位转换为时钟节拍数。举个例子,定时器的周期为 100 个时钟节拍的话,那么 xTimerPeriodInTicks 就为100,当定时器周期为 500ms 的时候 xTimerPeriodInTicks 就可以设置为(500/ portTICK_PERIOD_MS)。
    • uxAutoReload: 设置定时器模式
      • pdTRUE:周期定时器;
      • pdFALSE: 单次定时器
    • pvTimerID: 定时器 ID 号,回调函数会根据ID 号来处理不同的定时器
    • pxCallbackFunction: 定时器回调函数,当定时器定时周期到了以后就会调用这个函数
  • 返回值:
    • 成功:创建成功的软件定时器句柄
    • 失败:NULL

2.2.2 复位软件定时器

有时候我们可能会在定时器正在运行的时候需要复位软件定时器,复位软件定时器的话重新计算定时周期到达的时间点,这个新的时间点是相对于复位定时器的那个时刻计算的,并不是第一次启动软件定时器的那个时间点。

xTimerReset( )

复位一个软件定时器,此函数只能用在任务中,调用函数xTimerReset( )恢复软件定时器其实就是向定时器命令队列发送一条 tmrCOMMAND_START 命令,既然是向队列发送消息,那肯定会涉及到入队阻塞时间的设置。,函数原型如下:

c 复制代码
BaseType_t xTimerReset( TimerHandle_t xTimer, TickType_t xTicksToWait )
  • 参数:
    • xTimer: 要复位的软件定时器的句柄。
    • xTicksToWait: 设置阻塞时间
  • 返回值:
    • 成功:pdPASS
    • 失败:pdFAIL

xTimerResetFromISR( )

* *此函数是 xTimerReset()的中断版本,此函数用于中断服务函数中!

c 复制代码
BaseType_t xTimerResetFromISR( TimerHandle_t xTimer, BaseType_t *
	 			pxHigherPriorityTaskWoken );
  • 参数:
    • xTimer: 要开启的软件定时器的句柄
    • pxHigherPriorityTaskWoken: 标记退出此函数以后是否进行任务切换
  • 返回值:
    • 成功:pdPASS
    • 失败:pdFAIL

2.2.3 开启软件定时器

如果软件定时器停止运行的话可以使用 FreeRTOS 提供的两个开启函数来重新启动软件定时器。

xTimerStart( )

启动软件定时器,函数 xTimerStartFromISR()是这个函数的中断版本,可以用在中断服务函数中。如果软件定时器没有运行的话调用函数 xTimerStart()就会计算定时器到期时间,如果软件定时器正在运行的话调用函数 xTimerStart()的结果和 xTimerReset()一样。

c 复制代码
BaseType_t xTimerStart( TimerHandle_t xTimer, TickType_t xTicksToWait )
  • 参数:
    • xTimer: 要开启的软件定时器的句柄
    • xTicksToWait: 设置阻塞时间
  • 返回值:
    • 成功:pdPASS
    • 失败:pdFAIL

xTimerStartFromISR( )

此函数是函数 xTimerStart()的中断版本,用在中断服务函数中,此函数是一个宏,此函数原型如下:

c 复制代码
BaseType_t xTimerStartFromISR( TimerHandle_t xTimer,
	BaseType_t * pxHigherPriorityTaskWoken );
  • 参数:
    • xTimer: 要开启的软件定时器的句柄
    • pxHigherPriorityTaskWoken: 标记退出此函数以后是否进行任务切换
  • 返回值:
    • 成功:pdPASS
    • 失败:pdFAIL

2.2.4停止软件定时器

既然有开启软件定时器的 API 函数,那么肯定也有停止软件定时器的函数,FreeRTOS 也提供了两个用于停止软件定时器的 API 函数。

xTimerStop( )

此函数用于停止一个软件定时器,此函数用于任务中,不能用在中断服务函数中,函数原型如下:

c 复制代码
BaseType_t xTimerStop ( TimerHandle_t xTimer, TickType_t xTicksToWait )
  • 参数:
    • xTimer: 要停止的软件定时器的句柄
    • xTicksToWait: 设置阻塞时间
  • 返回值:
    • 成功:pdPASS
    • 失败:pdFAIL

xTimerStopFromISR( )

此函数是 xTimerStop()的中断版本,此函数用于中断服务函数中。

c 复制代码
BaseType_t xTimerStopFromISR( TimerHandle_t xTimer,BaseType_t * 
		pxHigherPriorityTaskWoken );
  • 参数:
    • xTimer: 要开启的软件定时器的句柄
    • pxHigherPriorityTaskWoken: 标记退出此函数以后是否进行任务切换
  • 返回值:
    • 成功:pdPASS
    • 失败:pdFAIL

免责声明:本文参考了网上公开资料,仅用于学习交流,若有错误或侵权请联系笔者。

相关推荐
架构文摘JGWZ6 分钟前
Kafka 消息丢失如何处理?
学习
LHNC20 分钟前
9.18 微信小程序开发笔记
笔记
waterHBO1 小时前
R语言 基础笔记
开发语言·笔记·r语言
GEEKVIP1 小时前
如何在没有备份的情况下恢复 Mac 上丢失的数据
经验分享·笔记·安全·macos·电脑·笔记本电脑·改行学it
linly12193 小时前
python学习笔记目录
笔记·学习
LvManBa4 小时前
Vue学习记录之四(computed的用法)
前端·vue.js·学习
Li小李同学Li5 小时前
git学习【持续更新中。。。】
git·学习·elasticsearch
·云扬·5 小时前
Shiro框架
笔记·学习·java-ee
优思学院6 小时前
优思学院|如何从零开始自己学习六西格玛?
大数据·运维·服务器·学习·六西格玛黑带·cssbb
LN花开富贵6 小时前
stm32g431rbt6芯片中VREF+是什么?在电路中怎么设计?
笔记·stm32·单片机·嵌入式硬件·学习