FreeRTOS常用任务函数——任务管理

FreeRTOS常用任务函数

任务挂起函数

vTaskSuspend()

任务可以调用 vTaskSuspend()这个函数来挂起任务自身,但是在挂起自身的时候会进行一次任务上下文切换,需要挂起自身就将 xTaskToSuspend 设置为 NULL 传递进来即可。无论任务是什么状态都可以被挂起,只要调用了 vTaskSuspend()这个函数就会挂起成
功,不论是挂起其他任务还是挂起任务自身
将所有的任务都挂起

vTaskSuspendAll()

挂起所有任务就是挂起任务调度器。 调度器被挂起后则不能进行上下文切换, 但是中断还是使能的。 当调度器被挂起的时候,如果有中断需要进行上下文切换, 那么这个任务将会被挂起,在调度
器恢复之后才执行切换任务。 调度器恢复可以调用xTaskResumeAll()函数,调用了多少次的 vTaskSuspendAll()就要调用多少次xTaskResumeAll()进行恢复,
任务恢复函数

vTaskResume()
xTaskResumeFromISR()

xTaskResumeFromISR()与 vTaskResume()一样都是用于恢复被挂起的任务,不一样的是 xTaskResumeFromISR() 专 门 用 在 中 断 服 务 程 序 中 。 无 论 通 过 调 用 一 次 或 多 次
vTaskSuspend()函数而被挂起的任务,也只需调用一次 xTaskResumeFromISR()函数即可解挂 。

xTaskResumeAll()

当调用了 vTaskSuspendAll()函数将调度器挂起,想要恢复调度器的时候我们就需要调用 xTaskResumeAll()函数,调 用 了 多 少 次vTaskSuspendAll()函数就必须同样调用多少次 xTaskResumeAll()函数,
任务删除函数

vTaskDelete()

当一个任务删除另外一个任务时, 形参为要删除任务创建时返回的任务句柄,如果是删除自身, 则形参为 NULL。
任务延时函数
相对延时函数

vTaskDelay()

绝对延时函数

vTaskDelayUntil()

vTaskDelayUntil() 与 vTaskDelay () 一 样 都 是 用 来 实 现 任 务 的 周 期 性 延 时 。 但vTaskDelay ()的延时是相对的,是不确定的,它的延时是等 vTaskDelay ()调用完毕后开始计算的。 并且 vTaskDelay ()延时的时间到了之后,如果有高优先级的任务或者中断正在执行,被延时阻塞的任务并不会马上解除阻塞,所有每次执行任务的周期并不完全确定。而vTaskDelayUntil()延时是绝对的,适用于周期性执行的任务。 当(*pxPreviousWakeTime + xTimeIncrement)时间到达后, vTaskDelayUntil()函数立刻返回,如果任务是最高优先级的,那么任务会立马解除阻塞,

无论是溢出还是没有溢出,都要求在下次唤醒任务之前,当前任务主体代码必须被执行完。也就是说任务执行的时间必须小于任务周期时间 xTimeIncrement,总不能存在任务周期为 10ms 的任务,其主体代码执行时间为 20ms,这样子根本执行不完任务主体代码。计算的唤醒时间合法后,就将当前任务加入延时列表,同样延时列表也有两个。每次产生系统节拍中断,都会检查这两个延时列表,查看延时的任务是否到期,如果时间到,则将任务从延时列表中除,重新加入就绪列表,任务从阻塞态变成就绪态, 如果此时的任务优先级是最高的,则会触发一次上下文切换

FreeRTOS 中程序运行的上下文包括:
中断服务函数
普通任务
空闲任务
中断服务函数是一种需要特别注意的上下文环境,它运行在非任务的执行环境下(一般为芯片的一种特殊运行模式(也被称作特权模式)),在这个上下文环境中不能使用挂起当前任务的操作,不允许调用任何会阻塞运行的 API 函数接口。另外需要注意的是,中
断服务程序最好保持精简短小,快进快出,一般在中断服务函数中只做标记事件的发生,然后通知任务,让对应任务去执行相关处理,因为中断服务函数的优先级高于任何优先级的任务,如果中断处理时间过长,将会导致整个系统的任务无法正常运行。所以在设计的时候必须考虑中断的频率、中断的处理时间等重要因素,以便配合对应中断处理任务的工作。
任务看似没有什么限制程序执行的因素,似乎所有的操作都可以执行。但是做为一个优先级明确的实时系统,如果一个任务中的程序出现了死循环操作(此处的死循环是指没有阻塞机制的任务循环体),那么比这个任务优先级低的任务都将无法执行,当然也包括
了空闲任务,因为死循环的时候,任务不会主动让出 CPU,低优先级的任务是不可能得到CPU 的使用权的,而高优先级的任务就可以抢占 CPU。这个情况在实时操作系统中是必须注意的一点,所以在任务中不允许出现死循环。如果一个任务只有就绪态而无阻塞态,势必会影响到其他低优先级任务的执行,所以在进行任务设计时,就应该保证任务在不活跃的时候,任务可以进入阻塞态以交出 CPU 使用权,这就需要我们自己明确知道什么情况下让任务进入阻塞态,保证低优先级任务可以正常运行。在实际设计中,一般会将紧急的处理事件的任务优先级设置得高一些。
闲任务(idle 任务)是 FreeRTOS 系统中没有其他工作进行时自动进入的系统任务。因为处理器总是需要代码来执行——所以至少要有一个任务处于运行态。 FreeRTOS 为了保证这一点,当调用 vTaskStartScheduler()时, 调度器会自动创建一个空闲任务,空闲任务是一个非常短小的循环。 用户可以通过空闲任务钩子方式,在空闲任务上钩入自己的功能函数。通常这个空闲任务钩子能够完成一些额外的特殊功能,例如系统运行状态的指示,系统省电模式等。除了空闲任务钩子, FreeRTOS 系统还把空闲任务用于一些其他的功能,比如当系统删除一个任务或一个动态任务运行结束时, 在执行删除任务的时候,并不会释放任务的内存空间,只会将任务添加到结束列表中, 真正的系统资源回收工作在空闲任务完成,空闲任务是唯一一个不允许出现阻塞情况的任务,因为 FreeRTOS 需要保证系统永远都有一个可运行的任务。
对于空闲任务钩子上挂接的空闲钩子函数,它应该满足以下的条件:
永远不会挂起空闲任务;
不应该陷入死循环,需要留出部分时间用于系统处理系统资源回收。
任务的执行时间:任务的执行时间一般是指两个方面,一是任务从开始到结束的时间,二是任务的周期。
在系统设计的时候这两个时间候我们都需要考虑,例如,对于事件 A 对应的服务任务Ta,系统要求的实时响应指标是 10ms,而 Ta 的最大运行时间是 1ms,那么 10ms 就是任务Ta 的周期了, 1ms 则是任务的运行时间,简单来说任务 Ta 在 10ms 内完成对事件 A 的响应即可。此时,系统中还存在着以 50ms 为周期的另一任务 Tb,它每次运行的最大时间长度是 100us。在这种情况下,即使把任务 Tb 的优先级抬到比 Ta 更高的位置,对系统的实时性指标也没什么影响,因为即使在 Ta 的运行过程中, Tb 抢占了 Ta 的资源,等到 Tb 执行完毕,消耗的时间也只不过是 100us,还是在事件 A 规定的响应时间内(10ms), Ta 能够安全完成对事件 A 的响应。但是假如系统中还存在任务 Tc,其运行时间为 20ms,假如将 Tc的优先级设置比 Ta 更高,那么在 Ta 运行的时候,突然间被 Tc 打断,等到 Tc 执行完毕,那 Ta 已经错过对事件 A(10ms)的响应了,这是不允许的。所以在我们设计的时候,必须考虑任务的时间,一般来说处理时间更短的任务优先级应设置更高一些。

你可能感兴趣的:(stm32,freertos)