目录
什么是任务调度?
FreeRTOS的任务调度规则是怎样的?
抢占式调度运行过程
时间片调度运行过程
任务的状态
任务综合小实验
实验需求
cubeMX配置
什么是任务调度?
调度器就是使用相关的调度算法来决定当前需要执行的哪个任务。
FreeRTOS
中开启任务调度的函数是
vTaskStartScheduler()
,但在
CubeMX
中被封装为
osKernelStart()
。
FreeRTOS的任务调度规则是怎样的?
FreeRTOS
是一个实时操作系统,它所奉行的调度规则:
1.
高优先级抢占低优先级任务,系统永远执行最高优先级的任务(即
抢占式调度
)
2.
同等优先级的任务轮转调度(即
时间片调度
)
还有一种调度规则是协程式调度,但官方已明确表示不更新,主要是用在小容量的芯片上,用得
也不多。
抢占式调度运行过程
Task 1
:玩游戏
Task 2
:老妈喊你吃饭
Task 3
:女朋友喊你看电视
总结:
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
cubeMX配置
freertos.c
void StartTskLED1(void const * argument)
{
/* USER CODE BEGIN StartTskLED1 */
/* Infinite loop */
for(;;)
{
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_8);
osDelay(500);
}
/* USER CODE END StartTskLED1 */
}
/* USER CODE BEGIN Header_StartTskLED2 */
/**
* @brief Function implementing the TskLED2 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTskLED2 */
void StartTskLED2(void const * argument)
{
/* USER CODE BEGIN StartTskLED2 */
/* Infinite loop */
for(;;)
{
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_9);
osDelay(1000);
}
/* USER CODE END StartTskLED2 */
}
/* USER CODE BEGIN Header_StartTaskKey1 */
/**
* @brief Function implementing the TaskKey1 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTaskKey1 */
void StartTaskKey1(void const * argument)
{
/* USER CODE BEGIN StartTaskKey1 */
/* Infinite loop */
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(TskLED1Handle==NULL){
printf("任务一不存在,准备创建\r\n");
osThreadDef(TskLED1, StartTskLED1, osPriorityNormal, 0, 128);
TskLED1Handle = osThreadCreate(osThread(TskLED1), NULL);
if(TskLED1Handle!=NULL){
printf("任务一创建成功\r\n");
}
}else{
printf("任务一删除成功\r\n");
osThreadTerminate(TskLED1Handle);
TskLED1Handle = NULL;
}
}
while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)==GPIO_PIN_RESET);
}
osDelay(10);
}
/* USER CODE END StartTaskKey1 */
}
/* USER CODE BEGIN Header_StartTaskKey2 */
/**
* @brief Function implementing the TaskKey2 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTaskKey2 */
void StartTaskKey2(void const * argument)
{
/* USER CODE BEGIN StartTaskKey2 */
static int flag = 0;
/* Infinite loop */
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(TskLED2Handle);
printf("任务2已暂停\r\n");
flag = 1;
}else{
osThreadResume(TskLED2Handle);
printf("任务2已恢复\r\n");
flag = 0;
}
}
while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1)==GPIO_PIN_RESET);
}
osDelay(10);
}
/* USER CODE END StartTaskKey2 */
}