实现所有演示应用程序使用的任务的文件
位于 FreeRTOS/Demo/Common/Minimal 目录中。 在
FreeRTOS/Demo/Common/Full 目录中的文件已不再使用,但仍然提供,
以确保仍然可以构建非常旧的示例。
以下文档是有些过时,因为此页面不再全面
维护。 请参阅包含在
FreeRTOS/Demo/Common/Minimal 目录中的源文件顶部的注释,以获得更多信息。
BlockQ.c
创建在以下三个队列上运行的六个任务:
前两个任务向队列发送和从队列接收递增号码。一个任务充当创建器,另一个任务充当使用器。使用器拥有比创建器更高的优先级,并且设置为阻塞队列读取操作。队列只有一个项目的空间,生产者在队列上发布消息后,消费者会在生产者之前,立即取消阻塞状态,并删除该项目。
后两个任务起相反作用。同样,所使用的队列仅有容纳一个项目的空间。此时使用器的优先级低于创建器。当队列已满时,创建器将尝试在队列上发布阻塞。当使用器醒来时,它将从队列中删除该项目,从而导致创建器取消阻塞,预先占用使用器,并立即重新填充队列。
最后两项任务使用相同的队列创建器和使用器函数。此时队列有足够的空间容纳大量项目,且任务以相同的优先级运行。生产者执行操作,将项目放入队列。当队列已满(导致生产者阻塞)或发生上下文切换(相同优先级的任务将切换时间片)时,消费者将开始执行。
blocktim.c
测试不同场景,以确保任务不会过早退出阻塞状态。 代码本身包含测试的描述。
创建在中断驱动的串行端口上运行的两个任务。必须使用环回连接器,以便也接收传输的所有内容。串行端口不使用任何流控制。在标准的 9Way 'D' 连接器上,应将引脚二和引脚三连接在一起。
第一个任务将字符串反复发送到队列,每次 () 个字符。串行端口中断将清空队列并传输字符。在重新发送字符串之前,任务会阻塞一个伪随机周期。
所述第二任务在队列上阻塞等待一个字符被接收。由串行端口中断例程接收的字符被发布到队列中,取消阻塞任务使其准备好执行。如果这是准备运行的最高优先级任务,则它将立即运行,同时中断服务例程结束时会发生上下文切换。接收字符的任务的优先级高于传输字符的任务。
在环回连接器到位后,一个任务将传输一个字符串,另一个任务将立即接收该字符串。接收任务知道它准备接收的字符串,因此可以检测到错误。
这种情况会创建第三个任务。这用于测试来自 ISR 的信号量的使用情况,没有什么相关。
注意: 使用队列发送字符进出 ISR 非常低效。
在本演示中,会故意如此操作以加载系统,并在此过程中测试
RTOS 端口。 真正的应用程序应使用DMA、RAM 缓冲区或其他更有效的技术。
使用计数信号量的简单演示。
创建一个周期性动态创建其他四个任务的单个持久性任务。最初的任务被称为“创建者任务” ,它创建的四个任务被称为“自杀任务”。
创建的两个自杀任务在自行删除之前会删除另一个自杀任务,只留下原始任务。
必须在执行所有其他演示应用程序任务后生成创建者任务,因为它会检查 RTOS 调度器控制下的任务数。它预计会检查到的正在运行的任务数量应始终小于创建者任务生成时存在的任务数量,加上一组四个自杀任务,加上空闲任务和任选的定时器服务任务。如果超出此数字,将标记为错误。
第一个测试会创建三个任务——两个计数器任务(一个连续计数和一个有限计数)和一个控制器。“计数”变量在所有三个任务之间共享。两个计数器任务绝不应同时处于“准备就绪”状态。控制器任务以与连续计数任务以相同的优先级运行,并且优先级低于有限计数任务。
一个计数器任务无限循环,递增每个迭代上的共享计数变量。为了确保它对变量的独占访问权限,它在每次增量之前将其优先级提升到高于控制器任务的优先级,并在开始下一个迭代之前将其再次降低到其原始优先级。
另一个计数任务在其循环中递增每个迭代上的共享计数变量,直到计数已达到上限 0xff——此时它会自行暂停。在控制器任务通过调用 vTaskResume() 使其再次“准备就绪”之前,它不会启动新的循环。第二计数器任务以比控制器任务更高的优先级操作,因此无需担心计数器变量的相互排除。
控制器任务分为两部分。第一部分控制和监控连续计数任务。当此部分处于操作状态时,有限计数任务将被暂停。同样,第二部分控制并监视有限计数任务。当此部分处于操作状态时,连续计数任务将被暂停。
在第一部分中,控制器任务首先获取共享计数变量的副本。为了确保避免计数变量的相互排除,它暂停连续计数任务,并在复制完成后再次将其恢复。然后,控制器任务睡眠一段固定时间,在此期间,连续计数任务将执行并增加共享变量。当控制器任务唤醒时,它通过将共享变量的副本与其当前值进行比较来检查连续计数任务是否已执行。此时,为了确保避免相互排除,RTOS 调度器通过调用 vTaskSuspendAll () 自行暂停。此操作仅用于演示目的,由于其效率低下,因此不推荐此技术。
在固定数量的迭代之后,控制器任务会暂停连续计数任务,并且移动到其第二部分。
在第二部分开始时,共享变量会被清零。通过调用 vTaskResume (),有限计数任务将从其暂停中唤醒。由于此计数器任务以比控制器任务更高的优先级操作,因此控制器任务不应再次运行,直到共享变量的计数达到限定值,导致计数器任务自行暂停。因此,vTaskResume() 之后的下一行是检查共享变量,以确保一切如预期。
第二个测试包括一些非常简单的任务,当 RTOS 调度器被暂停时,这些任务将发布到队列中。此测试已添加到第一次测试未执行的 RTOS 调度器的测试部分。
创建一组任务,每个任务以不同的速率闪烁 LED。第一个 LED 每 125 毫秒闪烁一次,第二个每 250 毫秒闪烁一次,第三个每 375 毫秒闪烁一次,以此类推。
LED 闪烁任务提供即时视觉反馈。它们显示 RTOS 调度器仍在运行。
创建一组任务,每个任务循环连续执行(模拟或真实,取决于目标)浮点计算。
所有任务都以空闲优先级运行,从不阻塞或让出。这会导致所有任务的时间被切片,用空闲任务分隔。以空闲优先级运行意味着这些任务将在其他任务准备好运行或发生时间切片时被抢占。抢占往往会发生中间计算,从而创建 RTOS 调度器上下文切换机制的良好测试——产生意外结果的计算可能是任务上下文出现损坏的症状。
注意:更新的演示会创建更复杂的“寄存器测试”任务,以便对上下文切换机制进行更强大的测试。
测试一系列队列和互斥锁 API 函数。
文件中提供了更多信息。
它与 flop.c 相同,但使用的是长整型变量,而不是 double 类型变量
定义更复杂的一组演示/测试任务之一。 它们旨在通过伪同步来自两个不同优先级和中断的任务的多次读取和多次写入
以对队列实现进行压力测试。 对中断分配优先级,以确保嵌套发生(对于支持嵌套的端口)。
测试确保,当有三个任务和两个中断进行访问时,发送到队列的所有数据也来自同一队列,从而不会发送或接收重复项目。
测试还确保,当更高优先级的任务尝试读取或写入队列时,低优先级任务永远无法成功进行相同的操作。
这是一个非常简单的队列测试。如需更全面的版本,请参阅 BlockQ.c 文档。
创建两个通过单个队列进行通信的任务。一个任务充当创建器,另一个任务充当使用器。
创建器循环进行三次迭代,每次循环都将递增号码发布到队列上。然后延迟一段固定时间,再做完全相同的操作。
使用器循环清空队列。检查从队列中删除的每个项目,以确保其包含预期值。当队列为空时,它会阻塞一段固定时间,然后再次执行同样的操作。
所有队列访问不会被阻塞。每次运行时,使用器都会完全清空队列,因此创建器永远不会发现队列已满。
如果使用器获得意外值或创建器发现队列已满,则标记错误。
创建三个显示队列窥视行为的任务。 每个任务被赋予不同的优先级,以演示从队列中查看数据时任务被唤醒的顺序。
演示使用递归互斥元素。
此演示创建了三个任务,所有这些任务都访问相同的递归互斥锁:
-
prvRecursiveMutexControllingTask() 具有最高优先级,因此首先
执行并获取互斥锁。 然后它会执行一些递归访问——
在每次访问之间它会短暂睡眠,
让低优先级任务执行。 当它完成了它的演示功能
它会在互斥锁在自行暂停之前将其交还。
-
prvRecursiveMutexBlockingTask() 尝试通过执行
阻塞性'获得' 阻塞任务的优先级低于
控制 任务,所以当它执行时,互斥锁
已被控制任务获得, 致使所述阻塞任务被阻塞。 它
在控制任务交还互斥锁之前不会退出阻塞,
并且在控制任务暂停之前,它不会实际自行
运行(由于相对优先级)。 当它最终获得
互斥锁后,只需在自行暂停之前将互斥锁
交还。 此时,控制任务和阻塞任务都
已挂起。
-
prvRecursiveMutexPollingTask() 以空闲优先级运行。 随后围绕
一个紧密循环旋转,试图通过非阻断调用获得互斥锁。 作为
最低优先级任务,它将不会成功获得互斥锁,直到
所述控制任务和阻塞任务均暂停。 一旦它最终
获得互斥锁,它首先在交还互斥锁之前
取消暂停控制任务和阻塞任务——导致轮询
任务暂时继承控制任务的优先级。
创建两组两个任务。每组内的任务共享一个变量,其访问由信号量保护。
每个任务都从尝试获取信号量开始。在获取信号量时,任务检查以确保受保护的变量具有预期值。然后,它将变量清除为零,然后以 1 的增量将其计数回归到预期值。每次增量后,检查变量以确保它包含刚刚设置的值。当再次达到起始值时,任务释放信号量,使组内的另一个任务有机会执行完全相同的事情。起始值足够高,以确保在增量循环期间可能发生 tick。
如果在此过程的任何时间发现共享变量具有与预期值不同的值,则会标记错误。这种情况表明相互排除机制中有一个错误,使对变量的访问受到限制。
第一组两个任务轮询它们的信号量。第二组使用阻塞调用。
Copyright (C) Amazon Web Services, Inc. or its affiliates. All rights reserved.