FreeRTOS任务优先级和系统心跳Tick

1. FreeRTOS任务优先级介绍

当我们使用xTaskCreate() API函数创建一个任务的时候,会为任务赋予一个初始的优先级,当然这个优先级可以在调度器启动后,我们可以使用vTaskPrioritySet() API函数来进行优先级修改的。

void vTaskPrioritySet( TaskHandle_t xTask, UBaseType_t uxNewPriority );

其中xTask参数是传递进某个任务的句柄,NULL则表示修改自己的优先级。uxNewPriority参数表示新设置的优先级,取值范围0~(configMAX_PRIORITIES – 1)。

使用uxTaskPriorityGet来获得任务的优先级:

UBaseType_t uxTaskPriorityGet( const TaskHandle_t xTask );

xTask参数是某个任务句柄,NULL表示获取自己的优先级。返回值就是该任务的优先级。

优先级的取值范围是:0~(configMAX_PRIORITIES – 1),数值越大优先级越高。其中configMAX_PRIORITIES这个宏的值可以在FreeRTOSConfig.h 中设定。FreeRTOS虽然没有规定这个宏的最大值,但是实际开发中,我们应该尽量选择一个合适的取值,因为这个值越大,那么内核对内存的开销就越大。

FreeRTOS的调度器总是会确保:

  • 在所有可以运行的任务中,选择其中具有最高优先级的任务运行;
  • 对于优先级相同的、可以运行的任务,轮流执行。

2. 系统心跳 — tick

对于相同优先级的任务,FreeRTOS要轮流执行的话,就需要有系统心跳。系统心跳来源于SysTick系统定时器产生周期性中断,比如我们设置SysTick定时器10ms产生一次中断,那么FreeRTOS的心跳就是10ms。

如下图所示:
在这里插入图片描述

  • 其中t1、t2、t3时刻发生定时器中断
  • 两次中断的时间间隔,称为时间片(time slice、tick period)
  • 时间片的长度在在FreeRTOSConfig.h 文件中,由configTICK_RATE_HZ这个宏确定,比如设定为1000,那么时间片长度就是1/1000s,也就是1ms。

那么对于相同优先级的任务,他们是怎么轮流进行切换的呢?如下图可以概括:
在这里插入图片描述

  • Task2任务是后面创建的,所以会首先运行Tssk2任务;
  • Task2任务运行完一个时间片长度后,发生SysTick系统定时器中断,进入对于的中断处理函数:
    • 中断处理函数选择下一个可以运行的任务
    • 执行完中断处理函数后,就跳转到新的任务,即Task1任务继续运行
  • Task1运行t2~t3这个时间片;
  • 上图也可以看出,进行任务切换的时候,需要使用到中断处理函数,中断运行也需要时间的。所以任务的运行并不是在t1,t2,t3的这些时间点上运行的。

使用系统心跳来进行延时:

很明显系统心跳—Tick可以用来衡量时间,自然我们就可以用它来实现延时。FreeRTOS提供了专门的API延时函数给我们使用,函数原型如下:

void vTaskDelay( const TickType_t xTicksToDelay );

该函数使用时会引起使用的任务进入阻塞态。其中,参数xTicksToDelay就是我们想要延时的时间长度,延时多长除了和该参数大小有关,还与设置的系统心跳频率有关。

用法如下:

/* 假设configTICK_RATE_HZ=100, Tick周期时10ms, 那么等待2个Tick,也就是等待20ms */
vTaskDelay(2); 
/* 还可以使用pdMS_TO_TICKS宏把ms转换为tick */
vTaskDelay(pdMS_TO_TICKS(100)); 		// 等待100ms

使用vTaskDelay函数时,建议以ms为单位,使用pdMS_TO_TICKS把时间转换为Tick。这样的代码就与configTICK_RATE_HZ无关,即使配置项configTICK_RATE_HZ改变了,我们也不用去修改代码。

3. 优先级示例代码

示例代码创建2个任务。

任务1代码如下:

/* Task1,Task2都不会进入阻塞或者暂停状态,根据优先级决定谁能运行*/
void vTask1( void *pvParameters )
{
    UBaseType_t uxPriority;
      
    /* 得到Task1自己的优先级 */
    uxPriority = uxTaskPriorityGet( NULL );
    
    for( ; ; )
    {
        printf( "Task 1 is running\r\n" );
        printf("About to raise the Task 2 priority\r\n" );
        
        /* 提升Task2的优先级高于Task1,Task2会即刻执行 */
        vTaskPrioritySet( xTask2Handle, ( uxPriority + 1 ) );
    }
}

任务2代码如下:

/* Task1,Task2都不会进入阻塞或者暂停状态,根据优先级决定谁能运行*/
void vTask2( void *pvParameters )
{
    UBaseType_t uxPriority;
      
    /* 得到Task2自己的优先级 */
    uxPriority = uxTaskPriorityGet( NULL );
    
    for( ; ; )
    {
        printf( "Task 2 is running\r\n" );
        printf("About to lower the Task 2 priority\r\n" );
        
        /* 降低了Task2的优先级,使得它的优先级比Task1还小,那么Task1会马上得到运行 */
        vTaskPrioritySet( xTask2Handle, ( uxPriority - 2 ) );
    }
}

main函数

#include <stdio.h>

#include "bsp_usart.h"
#include "FreeRTOS.h"
#include "task.h"

TaskHandle_t xTask2Handle;

int main( void )
{
    USART_Config();		// 串口初始化
    
    /* Task1的优先级更高, Task1先执行 */
    xTaskCreate( vTask1, "Task 1", 1000, NULL, 2, NULL );
    xTaskCreate( vTask2, "Task 2", 1000, NULL, 1, &xTask2Handle );
    
    /* 启动调度器 */
    vTaskStartScheduler();
    /* 如果程序运行到了这里就表示出错了, 一般是内存不足 */
    return 0;
}

代码运行过程如下:

  • 首先创建任务1和任务2,因为任务1优先级更高,所以任务1首先运行。
  • 为了让任务2有机会运行,在任务1中提升任务2的优先级高于任务1
  • 由于任务1提升了任务2的优先级,所以任务2此时在运行,然后任务2降低自己的优先级
  • 这时任务1优先级最高,任务1得以运行
  • 反复以上循环
  • 由于任务1和2都不会进入阻塞状态,所以空闲任务永远也不会得到执行

如下图可直观了解整个运行过程:
在这里插入图片描述

  • 4
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
FreeRTOS 中,中断优先级任务优先级是两个独立的概念。 中断优先级用于确定不同中断之间的优先级关系。通常,芯片的中断控制器会提供多个中断通道,每个中断通道都有一个可配置的优先级。当多个中断同时发生时,具有更高优先级的中断会被优先处理。 任务优先级用于确定不同任务之间的调度顺序。FreeRTOS 使用优先级抢占调度算法,具有更高优先级任务将抢占正在运行的低优先级任务,以确保高优先级任务能够及时执行。 在 FreeRTOS 中,任务优先级的范围通常是从 0 到 configMAX_PRIORITIES-1,其中 configMAX_PRIORITIES 是 FreeRTOS 配置文件中定义的最大任务优先级数。而中断优先级的范围则取决于芯片和中断控制器的具体实现。 当一个任务和一个中断同时发生时,如果中断的优先级高于或等于任务优先级,则中断会打断任务的执行,并立即执行中断服务程序。当中断服务程序完成后,系统会根据任务优先级重新进行调度。 需要注意的是,中断服务程序(ISR)应该尽量保持简短,并尽可能避免在 ISR 中进行阻塞操作或长时间的计算。这是因为在 ISR 中,任务调度器是被禁止的,而且其他中断也无法打断当前的中断服务程序。因此,长时间的 ISR 可能会导致系统响应性能下降。 总结来说,中断优先级用于确定中断之间的优先级关系,而任务优先级用于确定任务之间的调度顺序。在设计和使用 FreeRTOS 系统时,合理配置中断和任务优先级是至关重要的。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值