首页 > 其他分享 >《Mastering the FreeRTOS Real Time Kernel》读书笔记(4)软定时器

《Mastering the FreeRTOS Real Time Kernel》读书笔记(4)软定时器

时间:2023-10-13 15:16:26浏览次数:37  
标签:Real Kernel 定时器 读书笔记 timer 计时器 xTimer 软件 ID

5.软件定时器管理

软件定时器由FreeRTOS内核实现,并受其控制。它们不需要硬件支持,也与硬件计时器或硬件计数器无关。
软件定时器功能是可选的。包括软件定时器功能:1。作为项目的一部分,构建FreeRTOS源文件FreeRTOS/source/timers.c。2.在FreeRTOSConfig.h中将configUSE_TIMERS设置为1。

5.2 软件定时器回调函数

void ATimerCallback( TimerHandle_t xTimer );

返回值为void,并将软件计时器的句柄作为其唯一参数。
软件定时器回调函数是在启动FreeRTOS调度器时自动创建的任务的上下文中执行的。因此,重要的是,软件计时器回调函数永远不要调用FreeRTOS API函数,这将导致调用任务进入阻止状态。可以调用xQueueReceive()等函数,但前提是函数的xTicksToWait参数(指定函数的块时间)设置为0。

5.3 软件计时器的属性和状态

周期

软件定时器的“周期”是软件定时器启动和软件定时器回调功能执行之间的时间。

一次性与自动装载

1.一次性计时器一旦启动,一次性计时器将只执行一次回调功能。一次性计时器可以手动重新启动,但不会自行重新启动。
2.自动重新加载定时器一旦启动,自动重新加载计时器将在每次到期时重新启动,从而定期执行其回调功能。

两种状态

1.休眠状态:只有句柄,但是回调函数是没有反应的。
2.运行状态:正常状态,回调函数可以被触发。一次性计时器执行完一次回调函数后,回到休眠状态。

5.4 软件定时器的环境

OS的守护进程(Daemon Task)

守护进程,又有叫精灵进程。很多博文都介绍说守护进程是伴随创建其的那个进程(A进程)而存在的。如果A进程没了,其守护进程就没了。OS的守护进程是随着OS启动便一直运行,它是一个标准的FreeRTOS任务,也有优先级和堆栈,分别由configTIMER_TASK_priority和configTIMER_TASK_stack_DEPTH编译时配置常量设置。
软定时器的检测和运行都在RTOS的守护进程中。

定时器命令队列

通过向定时器命令队列发送命令以控制软件定时器,命令有启动定时器、停止定时器、重置定时器。
这个队列是一个标准的FreeRTOS队列,它是在调度程序启动时自动创建的。队列的长度由FreeRTOSConfig.h中的configTIMER_queue_length编译时配置常量设置。
守护进程中的软定时器功能,会接受定时器命令队列中的命令,来进行操作。

守护进程的优先级

守护进程的优先级可以小于包含软件定时器开始和停止命令的任务的优先级,也可以大于其优先级。这两种方式的程序有不同的用途。
通过改变configTIMER_TASK_PRIORITY设置会实现两种执行模式。

5.5 创建和启动一个软件定时器

主要包括创建函数和启动函数。

xTimerCreate()

TimerHandle_t xTimerCreate( const char * const pcTimerName,
                            TickType_t xTimerPeriodInTicks,
                            UBaseType_t uxAutoReload,
                            void * pvTimerID,
                            TimerCallbackFunction_t pxCallbackFunction );

1.pcTimerName:描述性命名。人类可读的命名比单纯的句柄名称好理解得多。
2.xTimerPeriodInTicks:以刻度为单位指定的计时器周期。可使用pdMS_TO_TICKS()宏。
3.uxAutoReload:设置为pdTRUE以创建自动重新加载计时器。设置为pdFALSE以创建一次性计时器。
4.pvTimerID:ID是一个空指针,应用程序编写器可以将其用于任何目的。当多个软件计时器使用相同的回调函数时,ID特别有用,因为它可以用于提供特定于计时器的存储。万用指针。
5.pxCallbackFunction:是指向回调函数名称的指针,用作正在创建的软件计时器的回调函数。
6.返回值:如果返回NULL,则无法创建软件计时器,因为没有足够的堆内存可用于FreeRTOS分配必要的数据结构。

xTimerStart() & xTimerStop()

xTimerStart() 用于启动处于休眠状态的软件定时器,或重置(重新启动)处于运行状态的软件计时器。相同的xTimerStop()用于停止处于运行状态的软件计时器。

BaseType_t xTimerStart( TimerHandle_t xTimer, TickType_t xTicksToWait );

1.xTimer:正在启动或重置的软件计时器的句柄。句柄将从用于创建软件计时器的xTimerCreate()调用中返回。
2.xTicksToWait:启动命令是需要发送到定时器命令队列的,这里的参数解释与队列发送的xTicksToWait解释相同。
3.返回值:与发送消息给队列的返回值解释相同。

例子13是分别创建一次性和自动装填软件定时器的例程。

5.6 定时器的ID

每个软件定时器都有一个ID,这是一个标签值,应用程序编写器可以将其用于任何目的。ID存储在一个void指针(void*)中,因此可以直接存储一个整数值,指向任何其他对象,或用作函数指针。

创建软件计时器时,会为ID分配一个初始值,之后可以使用vTimerSetTimerID()API函数更新ID,并使用pvTimerGetTimerID()API函数查询ID。与其他软件计时器API函数不同的是,vTimerSetTimerID()和pvTimerGetTimerID()直接访问软件计时器—它们不向计时器命令队列发送命令。

vTimerSetTimerID()

void vTimerSetTimerID( const TimerHandle_t xTimer, void *pvNewID );

pvTimerGetTimerID()

void *pvTimerGetTimerID( TimerHandle_t xTimer );

例子14:定时器ID的使用场景

示例14创建了与示例13创建的功能类似的功能,但为两个软件定时器分配了相同的回调功能。

/* Create the one shot timer software timer, storing the handle in xOneShotTimer. */
xOneShotTimer = xTimerCreate( "OneShot",
                                mainONE_SHOT_TIMER_PERIOD,
                                pdFALSE,
                                /* The timer’s ID is initialized to 0. */
                                0,
                                /* prvTimerCallback() is used by both timers. */
                                prvTimerCallback );

/* Create the auto-reload software timer, storing the handle in xAutoReloadTimer */
xAutoReloadTimer = xTimerCreate( "AutoReload",
                                  mainAUTO_RELOAD_TIMER_PERIOD,
                                  pdTRUE,
                                  /* The timer’s ID is initialized to 0. */
                                  0,
                                  /* prvTimerCallback() is used by both timers. 
                                  这里使用了相同的回调函数 */
                                  prvTimerCallback );

static void prvTimerCallback( TimerHandle_t xTimer )
{
TickType_t xTimeNow;
uint32_t ulExecutionCount;
  /* A count of the number of times this software timer has expired is stored in the         timer's
  ID. Obtain the ID, increment it, then save it as the new ID value. The ID is a void
  pointer, so is cast to a uint32_t. */
  ulExecutionCount = ( uint32_t ) pvTimerGetTimerID( xTimer );
  ulExecutionCount++;
  vTimerSetTimerID( xTimer, ( void * ) ulExecutionCount );
  /* Obtain the current tick count. */
  xTimeNow = xTaskGetTickCount();
  /* The handle of the one-shot timer was stored in xOneShotTimer when the timer was   created.
  Compare the handle passed into this function with xOneShotTimer to determine if it was the
  one-shot or auto-reload timer that expired, then output a string to show the time at which
  the callback was executed. */
  if( xTimer == xOneShotTimer )
  {
    vPrintStringAndNumber( "One-shot timer callback executing", xTimeNow );
  }
  else
  {
    /* xTimer did not equal xOneShotTimer, so it must have been the auto-reload timer that
    expired. */
    vPrintStringAndNumber( "Auto-reload timer callback executing", xTimeNow );
    if( ulExecutionCount == 5 )
    {
      /* Stop the auto-reload timer after it has executed 5 times. This callback function
      executes in the context of the RTOS daemon task so must not call any functions that
      might place the daemon task into the Blocked state. Therefore a block time of 0 is
      used. */
      xTimerStop( xTimer, 0 );
    }
  }
}

在同一个回调函数中,判断是哪个定时器触发的,并且执行该定时器相应的打印任务。

5.7 更改定时器的值

可以实现类似呼吸灯等需要改变“重装填值”的效果。

BaseType_t xTimerChangePeriod( TimerHandle_t xTimer,
                                TickType_t xNewTimerPeriodInTicks,
                                TickType_t xTicksToWait );

1.xTimer:定时器的句柄,由create返回。
2.xNewTimerPeriodInTicks:新的重装填值。
3.xTicksToWait:由于这个函数也算是一个命令,所以也需要发送到命令队列,也必须有一个最长等待时间。

5.8 重置一个软件定时器

官方解释:重置软件计时器意味着重新启动计时器;计时器的到期时间将重新计算为相对于计时器重置的时间,而不是计时器最初启动的时间。

也就是将定时器内部已经积累的计数值清零。

BaseType_t xTimerReset( TimerHandle_t xTimer, TickType_t xTicksToWait );

这个函数也是一个命令,需要发送到定时器命令队列。

例子15讲述了如何使用重置软件定时器功能,来阻止一些定时事件的发生。

总结

其实软件定时器,在裸机程序中,就应该是已经很好用的了。
使用一个1ms的硬件定时器,通过每次进硬件中断后进行++的计数。并在每次都判断计数值是否达到阈值,以达到比如10ms软定时器中断、100ms软定时器中断、1s的软定时器中断。但是这些中断不能处理很多信息,一定不能超过1ms,不然会影响下一次进硬中断,导致程序卡死。

本章节就是讲了一下如何使用FreeRTOS的框架实现软件定时器的,利用前面讲的任务和队列,将软件定时器的实现规范化,使得在FreeRTOS的心跳时钟下,还能分出很多软件定时器和它们的回调函数,来处理不同的信息。

具体的使用和自己的案例就不在读书笔记中分享了。

标签:Real,Kernel,定时器,读书笔记,timer,计时器,xTimer,软件,ID
From: https://www.cnblogs.com/HYBZ/p/17761607.html

相关文章

  • 《Mastering the FreeRTOS Real Time Kernel》读书笔记(3)队列管理
    4.队列管理队列,在一些系统中被称为消息队列,可以理解为信息中转站。是任务和任务,任务和中断之间可以互相读和写的一个共享空间。4.2队列的特征存储数据队列本质上是一个先进先出的缓冲区(FIFO),所以可以存储一定容量的数据。有两种方式可以实现FIFO队列:1.将发送给队列的数据复......
  • Dear Reality推出SPATIAL CONNECT for Wwise——XR音频制作新高度
    (DearReality演示视频截图)游戏混音的未来在头戴式设备中DearReality推出SPATIALCONNECTforWwise——XR音频制作新高度沉浸式音频专家DearReality宣布启动“SPATIALCONNECTforWwise”项目,该项目旨在支持游戏音频设计师在交互式VR和AR音频制作中实现完全沉浸式工作。这项......
  • 为什么我们需要不断的开发不同的机器学习模型 —— Do we Need Hundreds of Classifie
        ==========================================  论文:《DoweNeedHundredsofClassifierstoSolveRealWorldClassificationProblems?》  论文地址:https://jmlr.org/papers/volume15/delgado14a/delgado14a.pdf        =========......
  • English conversation in real life
    常见疑问句Whatdoyoufeel?你感觉如何Doyouthinkyoucanmakeitsitdown?Yes,Ishouldmakeittothebench.你认为你能走到那里坐下来吗?是的,我应该能走到长椅那里。Whatdoyoufancy?你想做什么?Whatareyouthinking?你有什么想法?I'vegotanidea;howabo......
  • Semantic Kernel .NET SDK 的 v1.0.0 Beta1 发布
    介绍SemanticKernel(SK)是一个开源的将大型语言模型(LLM)与流行的编程语言相结合的SDK,Microsoft将SemanticKernel(简称SK)称为轻量级SDK,结合了OpenAI,AzureOpenAI和HuggingFace等AILLM的集成。它使开发人员能够通过编排AI组件并将其与现有代码集成来创建AI应用。SDK提供对J......
  • 《Mastering the FreeRTOS Real Time Kernel》读书笔记(2)任务管理
    3.任务管理如何为每个任务分配处理时间,如何选择在任何给定时间执行何种任务,任务优先级,任务状态。3.2任务功能每个任务必须返回void,并接受一个void类型指针。这些任务一般会写成一个无限循环,由内核来调度,完成任务安排,创建和删除。3.3顶层任务状态由于一般单片机处理器为单核......
  • 《Mastering the FreeRTOS Real Time Kernel》读书笔记(1)堆内存管理
    这是161204的版本,不完全覆盖目前最新版本的内核。0.关于freeRTOS首先提出了了在小型嵌入式系统中为何需要多任务管理的问题,介绍了freeRTOS的用途。然后开始做广告,吹了一波freeRTOS的好处。其中要注意一些关键的名词:任务优先级分配、任务通知、队列、信号量、互斥锁、软定时器、......
  • 《流畅的Python》 读书笔记 第二章数据结构(2) 231011
    2.5对序列使用+和*通常+号两侧的序列由相同类型的数据所构成,在拼接的过程中,两个被操作的序列都不会被修改,Python会新建一个包含同样类型数据的序列来作为拼接的结果+和*都遵循这个规律,不修改原有的操作对象,而是构建一个全新的序列l1=[1,2,3]l2=[4,5,6]print(id(l......
  • 《架构师之路:软件架构之美》第四,五章读书笔记
    第四章:系统可伸缩性的重要性第四章讨论了系统可伸缩性的重要性。在现代软件开发中,可伸缩性是一个关键概念,它涉及到系统在不同负载下的性能表现。以下是一些关键观点:可伸缩性是应对用户增长和数据量增加的关键。一个好的架构应该能够轻松扩展以满足这些需求,而不需要完全重新设......
  • KdMapper扩展实现之REALiX(hwinfo64a.sys)
    1.背景  KdMapper是一个利用intel的驱动漏洞可以无痕的加载未经签名的驱动,本文是利用其它漏洞(参考《【转载】利用签名驱动漏洞加载未签名驱动》)做相应的修改以实现类似功能。需要大家对KdMapper的代码有一定了解。 2.驱动信息 驱动名称hwinfo64a.sys 时间戳5472......