FreeRTOS 任务调度和任务的状态

简介: FreeRTOS 任务调度和任务的状态

什么是任务调度?

调度器就是使用相关的调度算法来决定当前需要执行的哪个任务。


FreeRTOS中开启任务调度的函数是 vTaskStartScheduler() ,但在 CubeMX 中被封装为 osKernelStart() 。


FreeRTOS的任务调度规则是怎样的?

FreeRTOS 是一个实时操作系统,它所奉行的调度规则:


1. 高优先级抢占低优先级任务,系统永远执行最高优先级的任务(即抢占式调度)


2. 同等优先级的任务轮转调度(即时间片调度)


还有一种调度规则是协程式调度,但官方已明确表示不更新,主要是用在小容量的芯片上,用得 也不多。


抢占式调度运行过程

2ed9d36adf7ae8976d9caef647054b02_de7ddab016e04e8ab4dbe9e5895cf355.png

总结:


1. 高优先级任务,优先执行;


2. 高优先级任务不停止,低优先级任务无法执行;


3. 被抢占的任务将会进入就绪态


时间片调度运行过程

10bf6ddd313edaec3d59503227568286_050d30a54fee47d69afb095b05695468.png

总结:


1. 同等优先级任务,轮流执行,时间片流转;


2. 一个时间片大小,取决为滴答定时器中断周期;


3. 注意没有用完的时间片不会再使用,下次任务 Task3 得到执行,还是按照一个时间片的时钟 节拍运行


任务的状态

FreeRTOS中任务共存在4种状态:


  • Running 运行态

当任务处于实际运行状态称之为运行态,即CPU的使用权被这个任务占用(同一时间仅一个任务 处于运行态)。


  • Ready 就绪态

处于就绪态的任务是指那些能够运行(没有被阻塞和挂起),但是当前没有运行的任务,因为同 优先级或更高优先级的任务正在运行。


  • Blocked 阻塞态

如果一个任务因延时,或等待信号量、消息队列、事件标志组等而处于的状态被称之为阻塞态。


  • Suspended 挂起态

类似暂停,通过调用函数 vTaskSuspend() 对指定任务进行挂起,挂起后这个任务将不被执行, 只有调用函数 xTaskResume() 才可以将这个任务从挂起态恢复。


总结:


  • 1. 仅就绪态可转变成运行态
  • 2. 其他状态的任务想运行,必须先转变成就绪态

任务调度和任务的状态案例分析

实验需求


创建 4 个任务:taskLED1,taskLED2,taskKEY1,taskKEY2,任务要求如下:


taskLED1:间隔 500ms 闪烁 LED1;


taskLED2:间隔 1000ms 闪烁 LED2;


taskKEY1:如果 taskLED1 存在,则按下 KEY1 后删除 taskLED1 ,否则创建 taskLED1 ;


taskKEY2:如果 taskLED2 正常运行,则按下 KEY2 后挂起 taskLED2 ,否则恢复 taskLED2。


1.打开CubeMX,将FreeRTOS移植到STM32F103C8T6,具体看我之前写过的文章


将FreeRTOS移植到STM32F103C8T6


2.然后创建四个任务


c0b7999677eb51a4e0aee9c0520cf979_0898e9d30c514726826a645414f7ff54.png


3.查看原理图配置按键跟LED灯引脚,导出代码


代码示例:

uart.c 重定向printf

#include "stdio.h"
int fputc(int ch,FILE *f)
{
  unsigned char temp[1] = {ch};
  HAL_UART_Transmit(&huart1,temp,1,0xffff);
  return ch;
}

freertos.c

void StartTaskLED1(void const * argument)
{
  for(;;)
  {
    HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_8);
    osDelay(500);
  }
}
 
void StartTask02(void const * argument)
{
  for(;;)
  {
    HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_9);
    osDelay(1000);
  }
}
 
void StartTaskKey1(void const * argument)
{
  for(;;)
  {
    if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET)
    {
      osDelay(20); // 延时消抖
            if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET)
            {
          printf("Key1 被按下\r\n");
          if(TaskLED1Handle == NULL)
          {
            printf("任务1不存在,准备创建任务1\r\n");
            osThreadDef(TaskLED1, StartTaskLED1, osPriorityNormal, 0, 128);
            TaskLED1Handle = osThreadCreate(osThread(TaskLED1), NULL);
            if(TaskLED1Handle != NULL)
            {
              printf("任务1创建成功\r\n");
            }
          }
          else
          {
            printf("删除任务1\r\n");
            osThreadTerminate(TaskLED1Handle);
            TaskLED1Handle = NULL;
          }
            }
      while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET);
    }
        osDelay(10);
  }
}
 
void StartTaskKey2(void const * argument)
{
  static int flag = 0;  
  for(;;)
  {
    if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_RESET)
    {
      osDelay(20); // 延时消抖
            if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_RESET)
            {
          printf("Key2 被按下\r\n");
          if(flag == 0)
          {
            osThreadSuspend(TaskLED2Handle);
            printf("任务2被挂起暂停\r\n");
            flag = 1;
          }
          else
          {
            osThreadResume(TaskLED2Handle);
            printf("任务2重新恢复\r\n");
            flag = 0;
          }
           }
            while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_RESET);
    }
        osDelay(10);
  }
}


编译烧录代码后打开串口助手:

相关文章
|
负载均衡 Ubuntu 应用服务中间件
|
API 调度
【FreeRTOS】互斥锁的使用
【FreeRTOS】互斥锁的使用
401 0
|
芯片
SPI+DMA驱动和控制WS2812彩色RGB灯
SPI+DMA驱动和控制WS2812彩色RGB灯
903 0
SPI+DMA驱动和控制WS2812彩色RGB灯
|
安全 PHP
easyupload及BurpSuite抓包、改包、放包
easyupload及BurpSuite抓包、改包、放包
573 0
|
文字识别
解析pdf图片格式的表格到excel表格
解析pdf图片格式的表格到excel表格,原理是把pdf转换成图片,根据直方图定位表格单元格线条位置,按照单元格切分原始pdf,按顺序ocr单元格内容,最终拼接成完整excel
420 1
|
API 调度
FreeRTOS学习笔记—任务创建和删除
本文学习了如何创建和删除任务。最后,分析解决了遇到的问题。
544 0
|
网络协议 网络安全 虚拟化
DNS服务器搭建(Windows版本)
DNS服务器搭建(Windows版本)
2559 0
|
监控 前端开发 PHP
PHP短信验证码防刷方案
短信验证码是通过发送验证码到手机的一种有效的验证码系统。利用短信验证码来注册会员,大大降低了非法注册的数据。
PHP短信验证码防刷方案
|
JavaScript 前端开发
探索3D魔力:与Three.js共舞的五大库和工具
探索3D魔力:与Three.js共舞的五大库和工具
474 0

热门文章

最新文章