5.1本章介绍与适用范围

软件计时器用于在将来的设定时间或以固定频率周期性地调度功能的执行。 软件计时器执行的功能称为软件计时器的回调功能。

软件计时器由FreeRTOS内核实现并受其控制。 它们不需要硬件支持,并且与硬件计时器或硬件计数器无关。

请注意,与使用创新设计以确保最大效率的FreeRTOS理念一致,除非软件计时器回调函数正在实际执行,否则软件计时器不会使用任何处理时间。

软件计时器功能是可选的。 包括软件计时器功能:

  1. 作为项目的一部分,构建FreeRTOS源文件FreeRTOS / Source / timers.c。
  2. 在FreeRTOSConfig.h中将configUSE_TIMERS设置为1。

范围

本章旨在使读者更好地理解:

  • 与任务的特征相比,软件计时器的特征。
  • RTOS守护程序任务。
  • 计时器命令队列。
  • 单次软件计时器和定期软件计时器之间的差异。
  • 如何创建,启动,重置和更改软件计时器的周期。

5.2软件计时器回调功能

软件计时器回调函数被实现为C函数。 它们的唯一特殊之处在于它们的原型,该原型必须返回void,并将软件计时器的句柄作为其唯一参数。 清单72演示了回调函数原型。

清单72.软件计时器回调函数原型

软件计时器回调函数从头到尾执行,然后以正常方式退出。 它们应保持简短,并且不得进入“阻止”状态。

注意:可以看到,软件计时器回调函数在FreeRTOS调度程序启动时自动创建的任务的上下文中执行。 因此,至关重要的是,软件计时器回调函数切勿调用FreeRTOS API函数,这将导致调用任务进入“阻止”状态。 可以调用xQueueReceive()之类的函数,但前提是该函数的xTicksToWait参数(指定该函数的阻止时间)设置为0。调用vTaskDelay()之类的函数并不如调用vTaskDelay()那样。 将始终将调用任务置于“阻止”状态。

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

软件计时器的周期

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

单次和自动重装定时器

有两种类型的软件计时器:

1.单次计时器
一旦启动,单次计时器将仅执行一次其回调函数。 单次计时器可以手动重新启动,但不会自行重新启动。

2.自动重装计时器
一旦启动,自动重载计时器将在每次到期时自动重新启动,从而导致其回调函数的定期执行。

图38显示了单触发定时器和自动重载定时器之间的行为差异。 垂直虚线标记了滴答中断发生的时间。

图38一键式和自动重装软件计时器之间的行为差异

参考图38:

  • Timer 1
    计时器1是单次计时器,周期为6个滴答。 它在时间t1开始,因此其回调函数在时间t7之后执行6个滴答。 由于计时器1是单次计时器,因此其回调函数不会再次执行。

  • Timer 2
    定时器2是一个自动重载定时器,周期为5个滴答。 它在时间t1开始,因此其回调函数在时间t1之后每5个滴答执行一次。 在图38中,这是在时间t6,t11和t16。

软件计时器状态

软件计时器可以处于以下两种状态之一:

  • 休眠
    休眠软件计时器存在,并且可以由其句柄引用,但未运行,因此其回调函数将不会执行。
  • 运行
    自从软件计时器进入“运行”状态或自从最后一次重置软件计时器以来的时间等于其运行时间之后,“正在运行的软件计时器”将执行其回调功能。

图39和图40分别显示了自动重载定时器和单触发定时器在休眠和运行状态之间的可能转换。 这两个图之间的主要区别在于计时器到期后进入的状态; 自动重载定时器执行其回调函数,然后重新进入运行状态,单触发定时器执行其回调函数,然后进入休眠状态。

xTimerDelete()API函数删除一个计时器。 可以随时删除计时器。

图39自动重载软件计时器状态和转换


图40单次软件计时器状态和转换

5.4软件计时器的上下文

RTOS守护程序(计时器服务)任务

所有软件计时器回调函数均在同一RTOS守护程序(或“计时器服务”)任务1的上下文中执行。

守护程序任务是标准的FreeRTOS任务,它在调度程序启动时自动创建。 它的优先级和堆栈大小分别由configTIMER_TASK_PRIORITY和configTIMER_TASK_STACK_DEPTH编译时间配置常量设置。 这两个常量都在FreeRTOSConfig.h中定义。

软件计时器回调函数不得调用FreeRTOS API函数,否则将导致调用任务进入“阻止”状态,否则将导致守护程序任务进入“阻止”状态。

计时器命令队列

软件计时器API函数在称为“计时器命令队列”的队列上将命令从调用任务发送到守护程序任务。 如图41所示。命令示例包括“启动计时器”,“停止计时器”和“重置计时器”。

计时器命令队列是标准FreeRTOS队列,在调度程序启动时会自动创建。 计时器命令队列的长度由FreeRTOSConfig.h中的configTIMER_QUEUE_LENGTH编译时间配置常量设置。

图41软件计时器API函数使用计时器命令队列与RTOS守护程序任务进行通信

守护程序任务调度

守护程序任务的安排与其他FreeRTOS任务一样; 当它是可以运行的最高优先级任务时,它将仅处理命令或执行计时器回调函数。 图42和图43演示了configTIMER_TASK_PRIORITY设置如何影响执行模式。

图42显示了守护程序任务的优先级低于调用xTimerStart()API函数的任务的优先级时的执行模式。

图42当调用xTimerStart()的任务的优先级高于守护程序任务的优先级时的执行模式

参考图42,其中任务1的优先级高于守护程序任务的优先级,并且守护程序任务的优先级高于空闲任务的优先级:

  1. 在时间t1
    任务1处于“正在运行”状态,守护程序任务处于“已阻止”状态。
    如果将命令发送到计时器命令队列(在这种情况下它将处理该命令),或者如果软件计时器到期(在这种情况下它将执行软件计时器的回调函数),则守护程序任务将退出“已阻止”状态。
  2. 在时间t2
    任务1调用xTimerStart()。
    xTimerStart()将命令发送到计时器命令队列,导致守护程序任务退出“已阻止”状态。任务1的优先级高于守护程序任务的优先级,因此守护程序任务不会抢占任务1。
    任务1仍处于“运行”状态,并且守护程序任务已离开“已阻止”状态并进入“就绪”状态。
  3. 在时间t3
    任务1完成了xTimerStart()API函数的执行。任务1从函数开始到函数结束执行了xTimerStart(),而没有离开“运行”状态。
  4. 在时间t4
    任务1调用一个API函数,该函数导致其进入“阻止”状态。现在,守护程序任务是处于“就绪”状态的优先级最高的任务,因此调度程序选择守护程序任务作为进入“运行”状态的任务。然后,守护程序任务开始处理任务1发送到计时器命令队列的命令。
    注意:启动软件计时器将到期的时间是从“启动计时器”命令发送到计时器命令队列的时间开始计算的,而不是从守护程序任务收到“启动计时器”的时间开始计算的时间计时器命令队列中的命令。
  5. 在时间t5
    守护程序任务已完成对任务1发送给它的命令的处理,并尝试从计时器命令队列中接收更多数据。 timer命令队列为空,因此守护程序任务重新进入Blocked状态。 如果将命令发送到计时器命令队列,或者软件计时器到期,则守护程序任务将再次离开“已阻止”状态。
    现在,“空闲”任务是处于“就绪”状态的优先级最高的任务,因此调度程序选择“空闲”任务作为进入“运行”状态的任务。

图43显示了类似于图42所示的场景,但是这次守护程序任务的优先级高于调用xTimerStart()的任务的优先级。

图43当调用xTimerStart()的任务的优先级低于守护程序任务的优先级时的执行模式

参考图43,其中守护程序任务的优先级高于任务1的优先级,而任务1的优先级高于空闲任务的优先级:

  1. 在时间t1
    与以前一样,任务1处于“运行”状态,守护程序任务处于“已阻止”状态。
  2. 在时间t2
    任务1调用xTimerStart()。
    xTimerStart()将命令发送到计时器命令队列,导致守护程序任务退出“已阻止”状态。 守护程序任务的优先级高于任务1的优先级,因此调度程序选择守护程序任务作为进入运行状态的任务。
    任务1在完成执行xTimerStart()函数之前已被守护程序任务抢占,现在处于就绪状态。
    守护程序任务开始处理任务1发送到计时器命令队列的命令。
  3. 在时间t3
    守护程序任务已完成对任务1发送给它的命令的处理,并尝试从计时器命令队列中接收更多数据。 timer命令队列为空,因此守护程序任务重新进入Blocked状态。
    现在,任务1是处于“就绪”状态的优先级最高的任务,因此调度程序选择任务1作为进入“运行”状态的任务。
  4. 在时间t4
    任务1在完成执行xTimerStart()函数之前已被守护程序任务抢占,并且仅在重新进入运行状态后才退出xTimerStart()(从中返回)。
  5. 在时间t5
    任务1调用一个API函数,该函数导致其进入“阻止”状态。 现在,“空闲”任务是处于“就绪”状态的优先级最高的任务,因此调度程序选择“空闲”任务作为进入“运行”状态的任务。

在图42所示的场景中,任务1向计时器命令队列发送命令与守护程序任务接收和处理命令之间的时间间隔。 在图43所示的场景中,守护程序任务在任务1从发送命令的函数返回之前,已经接收并处理了任务1发送给它的命令。

发送到计时器命令队列的命令包含时间戳。 时间戳记用于说明应用程序任务发送的命令与守护程序任务处理的同一命令之间经过的任何时间。 例如,如果发送了一个“启动计时器”命令来启动一个周期为10滴答的计时器,则时间戳将用于确保正在启动的计时器在该命令发送后10滴答应到期,而不是在发送命令后10滴答应到期。 该命令已由守护程序任务处理。

5.5 创建和启动软件计时器

xTimerCreate()API函数

FreeRTOS V9.0.0还包括xTimerCreateStatic()函数,该函数分配在编译时静态创建计时器所需的内存:必须先显式创建一个软件计时器,然后才能使用它。

软件计时器由类型为TimerHandle_t的变量引用。 xTimerCreate()用于创建软件计时器,并返回TimerHandle_t引用其创建的软件计时器。 软件计时器在休眠状态下创建。

可以在调度程序运行之前创建软件计时器,也可以在调度程序启动之后根据任务创建软件计时器。

第0节描述了所使用的数据类型和命名约定。

清单73. xTimerCreate()API函数原型

表27. xTimerCreate()参数和返回值

参数名称/返回值 描述
pcTimerName 计时器的描述性名称。 FreeRTOS不会以任何方式使用它。 它纯粹是作为调试辅助工具包含在内的。 通过人类可读的名称来标识计时器比尝试通过其句柄来标识计时器要简单得多。
xTimerPeriodInTicks 计时器的周期,以刻度为单位。 pdMS_TO_TICKS()宏可用于将以毫秒为单位的时间转换为以刻度为单位的时间。
uxAutoReload 将uxAutoReload设置为pdTRUE以创建自动重装计时器。 将uxAutoReload设置为pdFALSE可以创建一个一次性计时器。
pvTimerID 每个软件计时器都有一个ID值。 该ID是一个空指针,可由应用程序编写者出于任何目的使用。 当多个软件计时器使用相同的回调函数时,该ID特别有用,因为它可用于提供特定于计时器的存储。 本章中的示例演示了如何使用计时器ID。 pvTimerID为正在创建的任务的ID设置初始值。
pxCallbackFunction 软件计时器回调函数只是符合清单72中所示原型的C函数。pxCallbackFunction参数是指向该函数的指针(实际上,只是函数名称),用作创建的软件计时器的回调函数。
Returned value 如果返回NULL,则无法创建软件计时器,因为FreeRTOS没有足够的堆内存来分配必要的数据结构。返回的非NULL值表示已成功创建软件计时器。 返回的值是创建的计时器的句柄。第2章提供了有关堆内存管理的更多信息。

xTimerStart()API函数

xTimerStart()用于启动处于休眠状态的软件计时器,或重置(重新启动)处于运行状态的软件计时器。 xTimerStop()用于停止处于“运行”状态的软件计时器。 停止软件计时器与将计时器转换为休眠状态相同。

可以在启动调度程序之前调用xTimerStart(),但是完成此操作后,软件计时器将不会真正启动,直到调度程序启动时为止。

注意:切勿从中断服务程序中调用xTimerStart()。 应在其位置使用中断安全版本xTimerStartFromISR()。

清单74. xTimerStart()API函数原型
表28. xTimerStart()参数和返回值

参数名称/返回值 描述
xTimer 正在启动或重置软件计时器的句柄。 该句柄将从用于创建软件计时器的xTimerCreate()的调用中返回。
xTicksToWait xTimerStart()使用计时器命令队列将“ tart a timer”命令发送给守护程序任务。 xTicksToWait指定在队列已满的情况下,调用任务应保持在“阻塞”状态以等待计时器命令队列上的空间可用的最长时间。如果xTicksToWait为零且计时器命令队列已满,则xTimerStart()将立即返回。堵塞时间以滴答周期指定,因此它表示的绝对时间取决于滴答频率。 宏pdMS_TO_TICKS()可用于将以毫秒为单位的时间转换为以刻度为单位的时间。如果在FreeRTOSConfig.h中将INCLUDE_vTaskSuspend设置为1,则将xTicksToWait设置为portMAX_DELAY将导致调用任务无限期地保持在Blocked状态(没有超时),以等待计时器命令队列中的可用空间。如果在启动调度程序之前调用了xTimerStart(),则xTicksToWait的值将被忽略,并且xTimerStart()的行为就像xTicksToWait被设置为零。
Returned value 有两个可能的返回值:1. pdPASS 仅当“启动计时器”命令成功发送到计时器命令队列时,才会返回pdPASS。 如果守护程序任务的优先级高于名为xTimerStart()的任务的优先级,则调度程序将确保在xTimerStart()返回之前处理启动命令。这是因为一旦计时器命令队列中有数据,守护程序任务就会抢占名为xTimerStart()的任务。如果指定了阻止时间(xTicksToWait不为零),则有可能将调用任务置于“阻止”状态,以等待计时器命令队列中的空间在函数返回之前可用,但数据已成功写入阻止时间到期之前的计时器命令队列。2. pdFALSE 如果由于队列已满而无法将“启动计时器”命令写入计时器命令队列,则将返回pdFALSE。如果指定了阻塞时间(xTicksToWait不为零),则调用任务将被置于“阻塞”状态,以等待守护程序任务在计时器命令队列中腾出空间,但是指定的阻塞时间在此之前已过期。

例子13.创建单次和自动重装计时器

本示例创建并启动一个单次触发定时器和一个自动重载定时器,如清单75所示。

清单75.创建和启动示例13中使用的计时器

计时器的回调函数只会在每次调用时打印一条消息。 清单76显示了单次计时器回调函数的实现。清单77显示了自动重载计时器回调函数的实现。


执行此示例将产生图44所示的输出。图44显示了自动重载计时器的回调函数,该回调函数以固定的500滴答周期执行(清单75中的mainAUTO_RELOAD_TIMER_PERIOD设置为500),而单次计时器的回调函数仅执行 一次,滴答计数为3333(清单75中的mainONE_SHOT_TIMER_PERIOD设置为3333)。

5.6 计时器ID

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

创建软件计时器时,会为ID分配一个初始值,之后可以使用vTimerSetTimerID()API函数更新ID,然后使用pvTimerGetTimerID()API函数查询ID。

与其他软件计时器API函数不同,vTimerSetTimerID()和pvTimerGetTimerID()直接访问软件计时器-y不要将命令发送到计时器命令队列。

vTimerSetTimerID()API函数

表29. vTimerSetTimerID()参数

参数名称/返回值 描述
xTimer 用新的ID值更新软件计时器的句柄。 该句柄将从用于创建软件计时器的xTimerCreate()的调用中返回。
pvNewID 设置软件计时器ID的值。

pvTimerGetTimerID()API函数

参数名称/返回值 描述
xTimer 正在查询的软件计时器的句柄。 该句柄将从用于创建软件计时器的xTimerCreate()的调用中返回。
Returned value 查询的软件定时器的ID。

例子14.使用回调函数参数和软件计时器ID

相同的回调函数可以分配给多个软件计时器。 完成此操作后,将使用回调函数参数来确定哪个软件计时器已到期。

例13使用了两个单独的回调函数。 单次计时器使用一个回调函数,自动重载计时器使用另一个回调函数。 示例14创建了与示例13创建的功能类似的功能,但是为两个软件计时器都分配了一个回调函数。

示例14中使用的main()函数与示例13中使用的main()函数几乎相同。唯一的区别是创建软件计时器的位置。 清单80显示了这种差异,其中prvTimerCallback()用作两个计时器的回调函数。

当任一计时器到期时,将执行prvTimerCallback()。 prvTimerCallback()的实现使用该函数的参数来确定是由于单次计时器到期还是自动重载计时器到期而被调用。

prvTimerCallback()还演示了如何将软件计时器ID用作计时器特定的存储。 每个软件计时器都会在其自己的ID中保留其过期次数的计数,而自动重载计时器会在第五次执行时使用该计数自行停止。

清单79显示了prvTimerCallback()的实现。


例14产生的输出如图45所示。可以看出,自动重载定时器仅执行5次。

5.7更改计时器的时间

每个官方的FreeRTOS官方端口都提供一个或多个示例项目。 大多数示例项目都是自检项目,并且LED用于给出项目状态的视觉反馈。 如果自检始终通过,则LED缓慢切换;如果自检失败,则快速切换LED。

一些示例项目在任务中执行自检,并使用vTaskDelay()函数控制LED切换的速率。 其他示例项目在软件计时器回调函数中执行自检,并使用计时器周期来控制LED切换的速率。

xTimerChangePeriod()API函数

使用xTimerChangePeriod()函数可以更改软件计时器的周期。

如果使用xTimerChangePeriod()更改已经运行的计时器的周期,则该计时器将使用新的周期值重新计算其到期时间。 重新计算的到期时间与调用xTimerChangePeriod()的时间有关,而不与最初启动计时器的时间有关。

如果使用xTimerChangePeriod()更改处于休眠状态的计时器(未运行的计时器)的时间段,则该计时器将计算到期时间,并转换为正在运行状态(计时器将开始运行) 。

注意:切勿从中断服务程序中调用xTimerChangePeriod()。 应在其位置使用中断安全版本xTimerChangePeriodFromISR()。

参数名称/返回值 描述
xTimer 用新的周期值更新软件计时器的句柄。 该句柄将从用于创建软件计时器的xTimerCreate()的调用中返回。
xTimerPeriodInTicks 软件计时器的新周期,以刻度为单位。 pdMS_TO_TICKS()宏可用于将以毫秒为单位的时间转换为以刻度为单位的时间。
xTicksToWait xTimerChangePeriod()使用计时器命令队列将“更改周期”命令发送到守护程序任务。 xTicksToWait指定在队列已满的情况下,调用任务应保持在“阻塞”状态以等待计时器命令队列上的空间可用的最长时间。 如果xTicksToWait为零并且计时器命令队列已满,则xTimerChangePeriod()将立即返回。宏pdMS_TO_TICKS()可用于将以毫秒为单位的时间转换为以刻度为单位的时间。如果在启动调度程序之前调用了xTimerChangePeriod(),则xTicksToWait的值将被忽略,并且xTimerChangePeriod()的行为就像xTicksToWait被设置为零一样。
Returned value 有两个可能的返回值:1. pdPASS 仅当数据成功发送到计时器命令队列时,才会返回pdPASS。如果指定了阻止时间(xTicksToWait不为零),则有可能将调用任务置于“阻止”状态,以等待计时器命令队列中的空间在函数返回之前可用,但数据已成功写入 阻止时间到期之前的计时器命令队列。2. pdFALSE 如果由于队列已满而无法将“更改时间”命令写入计时器命令队列,则将返回pdFALSE。如果指定了阻塞时间(xTicksToWait不为零),则调用任务将被置于“阻塞”状态,以等待守护程序任务在队列中腾出空间,但是指定的阻塞时间在此之前已过期。

清单83显示了在软件计时器回调函数中包含自检功能的FreeRTOS示例如何使用xTimerChangePeriod()提高自检失败时LED切换的速率。 执行自检的软件计时器称为检查计时器?

5.8重置软件定时器

重置软件计时器意味着重新启动计时器; 计时器的到期时间重新计算是相对于计时器重置的时间,而不是相对于计时器最初启动的时间。 图46演示了这一点,该图显示了一个计时器,该计时器的周期为6,开始计时,然后复位两次,最后终止并执行其回调函数。

参考图46:

  • 定时器1在时间t1启动。 它的周期为6,因此执行回调函数的时间最初计算为t7,即启动后的6个滴答。
  • 在到达时间t7之前,即在定时器1到期并执行其回调函数之前,将其重置。 计时器1在时间t5重置,因此它将执行其回调函数的时间重新计算为t11,即重置后的6个滴答。
  • 定时器1在时间t11之前再次复位,因此在其到期并执行其回调函数之前再次复位。 计时器1在时间t9重置,因此它将执行其回调函数的时间重新计算为t15,即上一次重置后的6个滴答。
  • 定时器1不会再次复位,因此它将在时间t15到期,并相应地执行其回调函数。

xTimerReset()API函数

使用xTimerReset()API函数重置计时器。

xTimerReset()也可用于启动处于休眠状态的计时器。

注意:切勿从中断服务程序中调用xTimerReset()。 应在其位置使用中断安全版本xTimerResetFromISR()。

参数名称/返回值 描述
xTimer 重置或启动软件计时器的句柄。 该句柄将从用于创建软件计时器的xTimerCreate()的调用中返回。
xTicksToWait xTimerChangePeriod()使用计时器命令队列将“重置”命令发送到守护程序任务。 xTicksToWait指定在队列已满的情况下,调用任务应保持在“阻塞”状态以等待计时器命令队列上的空间可用的最长时间。如果xTicksToWait为零并且计时器命令队列已满,则xTimerReset()将立即返回。如果在FreeRTOSConfig.h中将INCLUDE_vTaskSuspend设置为1,则将xTicksToWait设置为portMAX_DELAY将导致调用任务无限期地保持在Blocked状态(没有超时),以等待计时器命令队列中的可用空间。
Returned value 有两个可能的返回值:1. pdPASS 仅当数据成功发送到计时器命令队列时,才会返回pdPASS。 如果指定了阻止时间(xTicksToWait不为零),则有可能将调用任务置于“阻止”状态,以等待计时器命令队列中的空间在函数返回之前可用,但数据已成功写入 阻止时间到期之前的计时器命令队列。 2. pdFALSE 如果由于队列已满而无法将“重置”命令写入计时器命令队列,则将返回pdFALSE。 如果指定了阻塞时间(xTicksToWait不为零),则调用任务将被置于“阻塞”状态,以等待守护程序任务在队列中腾出空间,但是指定的阻塞时间在此之前已过期。

例子15.重置软件计时器

本示例模拟手机上的背光灯行为。 背光:

  • 按下按键时打开。
  • 在一定时间段内按下的其他键仍然保留。
  • 如果在一定时间内没有按键操作,则自动关闭。

单次软件计时器用于实现此行为:

  • 按下某个键时,[模拟]背光将打开,而在软件计时器的回调功能中将其关闭。
  • 每按一次键,软件计时器都会重置一次。
  • 因此,必须按下一个键以防止背光关闭的时间段等于软件计时器的时间段; 如果在计时器到期之前未通过按键重置软件计时器,则计时器的回调函数将执行,并且背光灯将关闭。
    xSimulatedBacklightOn变量保留背光状态。 xSimulatedBacklightOn设置为pdTRUE表示背光打开,而pdFALSE设置为背光关闭。

清单85显示了软件计时器回调函数。


示例15创建一个轮询键盘2的任务。 清单86中显示了该任务,但是由于下一段所述的原因,清单86并不旨在代表最佳设计。

使用FreeRTOS可以使您的应用程序受事件驱动。 事件驱动的设计非常有效地利用了处理时间,因为仅在发生事件时才使用处理时间,并且不会浪费时间来轮询未发生的事件。 无法使用事件驱动示例15,因为使用FreeRTOS Windows端口处理键盘中断不切实际,因此必须使用效率低得多的轮询技术。 如果清单86是中断服务程序,则将使用xTimerResetFromISR()代替xTimerReset()。


执行示例15时产生的输出如图47所示。参考图47:

  • 第一次滴答计数为812时发生第一次按键。那时,背光打开,并且单次计时器启动。
  • 刻度线计数分别为1813、3114、4015和5016时,会发生进一步的按键操作。所有这些按键操作导致计时器在计时器到期之前被重置。
  • 滴答计数为10016时,计时器到期。那时背光关闭。

    从图47中可以看出,计时器的周期为5000个滴答声; 上次按下按键后,将背光灯精确地关闭了5000个滴答声,因此在最后一次重置计时器之后又将5000个滴答声关闭了。

  1. 该任务以前称为“计时器服务任务”,因为该任务最初仅用于执行软件计时器回调函数。 现在,同一任务也用于其他用途,因此以“ RTOS守护程序任务”的更通用名称而闻名。 ↩︎

  2. 打印到Windows控制台,并从Windows控制台读取密钥,均会导致执行Windows系统调用。 Windows系统调用(包括使用Windows控制台,磁盘或TCP / IP堆栈)可能会对FreeRTOS Windows端口的行为产生不利影响,通常应避免使用。 ↩︎

FreeRTOS —— 5.软件计时器管理相关推荐

  1. FreeRTOS——软件计时器

    FreeRTOS 基础系列文章  基本对象   FreeRTOS--任务   FreeRTOS--队列   FreeRTOS--信号量   FreeRTOS--互斥量   FreeRTOS--任务通知 ...

  2. 两个要素:人和思考——《软件人才管理的艺术》书评

    [转自]http://blog.csdn.net/lingyun2005/archive/2010/11/25/6035942.aspx 还记得曾经听过某位成功人士读书的方法,或者说对一本书是否有价值 ...

  3. Linux学习笔记-软件安装管理

    0 Linux 软件安装管理概述 一.软件包管理简介 二.rpm命令管理 三.yum在线管理 四.源码包管理 五.脚本安装包 1 软件包管理简介 软件包的分类 源码包 二进制包 源码包的特点 开源,如 ...

  4. 服务器远程管理app,用什么软件远程管理服务器最好? - 选择攻略!

    用什么软件远程管理服务器最好? - 选择攻略! (2012-06-13 01:59:02) 标签: 服务器 管理 最好 杂谈 用什么软件远程管理服务器最好? - 选择攻略! 远程控制就是从一台计算机上 ...

  5. Windows软件授权管理工具 slmgr命令详解

    slmgr是Software LicenseManger的简称,是Windows软件授权管理工具.slmgr是管理系统激活和密钥.证书的主要组件.slmgr的所有功能都是通过slmgr.vbs提供的, ...

  6. Linux软件安装管理 - CentOS (二) ---- yum在线安装

    1. 软件包管理简介 2. rpm命令管理(Redhat Package Manager) 3. yum在线安装 3.1 yum源文件 vi /etc/yum.repos.d/CentOS-Base. ...

  7. 计算机软件基础-(软件开发过程管理)

    软件开发过程管理包括:软件开发模型.软件开发过程控制. 软件开发模型从软件开发过程的总体建模,偏重研究构建合理的过程模型. 软件开发过程控制从项目管理的角度,偏重于软件开发过程中具体管理制度 和规范的 ...

  8. FreeRTOS 之五 动态内存管理(heap_1.c)详解

    写在前面   写这篇文章时,网上已经有了铺天盖地的文章来介绍 FreeRTOS 的动态内存.之所以还去写这篇博文,主要还是记录自己的学习过程.结合源代码一步一步分析一下FreeRTOS究竟是怎么实现的 ...

  9. 读书笔记:软件人才-管理的艺术

    图灵之前送了两本书,一本是<软件人才-管理的艺术>,还有一本书<***与画家>.这几天把第一本书看完了,虽然有些章节不是那么好,但总体上来说还是不错的,所以才有下面的读书笔记与 ...

最新文章

  1. DDD领域驱动设计之聚合、实体、值对象
  2. Flash,一次Bug的思考
  3. 为什么我使用了索引,查询还是慢?
  4. java main是多线程的吗_Java多线程之线程及其常用方法
  5. CentOS6.9 下编译安装MySQL5.7.19
  6. 尤雨溪写的100多行的“玩具 vite”,十分有助于理解 vite 原理
  7. jzoj4638-第三条跑道【欧拉函数,线段树】
  8. 外设驱动库开发笔记14:DS18B20温度变送器驱动
  9. 需要vmwareinstalldisk上的文件vmnet_手机上一键就能进行PDF与其他文件的相互转换,果然厉害到不行...
  10. iOS开发之使用Runtime给Model类赋值
  11. php文章上一篇,thinkphp5实现文章上一篇,下一篇
  12. 详细图解MySQL(win7x64 5.7.16版本)下载、安装、配置与使用
  13. ffmpeg实现摄像头拉流_ffmpeg推流拉流的几种方式
  14. 流程图制作软件绘图技巧:快速学会怎么画流程图
  15. pom 备注_POM 500P物性表
  16. vue-element-admin 增删改查(五)
  17. POJ_1849 Two
  18. JS jQuery 赋值取值整理
  19. 如何看待大数据「杀熟」?
  20. ThreeJS - 修复摄像机近距离模型或者摄像机在某些观察角度3D模型部分或者全部不可见的问题

热门文章

  1. 安卓手机安装Linux教程 多图
  2. 世炬网络受邀参加2022高通创投CEO峰会
  3. 使用time命令测试程序
  4. UBIFS文件系统分析六之wear-leveling
  5. rpa打开浏览器_典型应用 | RPA技术之个人征信机器人
  6. Fiora一款二次元的Web多人在线网络聊天系统
  7. mac下mysql的DMG格式安装卸载方法
  8. JavaWeb购物商城
  9. 读写csv文件时出现‘gbk‘问题
  10. pygame的init()