目录
什么是任务调度?
FreeRTOS的任务调度规则是怎样的?
抢占式调度运行过程编辑
时间片调度运行过程编辑
任务的状态
任务调度和任务的状态案例分析
什么是任务调度?
调度器就是使用相关的调度算法来决定当前需要执行的哪个任务。
FreeRTOS中开启任务调度的函数是 vTaskStartScheduler() ,但在 CubeMX 中被封装为 osKernelStart() 。
FreeRTOS的任务调度规则是怎样的?
FreeRTOS 是一个实时操作系统,它所奉行的调度规则:
1. 高优先级抢占低优先级任务,系统永远执行最高优先级的任务(即抢占式调度)
2. 同等优先级的任务轮转调度(即时间片调度)
还有一种调度规则是协程式调度,但官方已明确表示不更新,主要是用在小容量的芯片上,用得 也不多。
抢占式调度运行过程
总结:
1. 高优先级任务,优先执行;
2. 高优先级任务不停止,低优先级任务无法执行;
3. 被抢占的任务将会进入就绪态
时间片调度运行过程
总结:
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.然后创建四个任务
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);}
}
编译烧录代码后打开串口助手: