FreeRTOS学习——任务调度

一、什么是任务调度?

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

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

1、CubeMX中任务调度

二、FreeRTOS中的任务调度规则?

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

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

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

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

2.1、抢占式调度运行过程

总结:

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

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

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

2.2、时间片调度运行过程

总结:

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

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

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

三、任务的状态

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

        Running 运行态

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

        Ready 就绪态

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

        Blocked 阻塞态

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

        Suspended 挂起态

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

总结:

1. 仅就绪态可转变成运行态

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

四、实操

4.1、任务需求

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

taskLED1:间隔 500ms 闪烁 LED1;

taskLED2:间隔 1000ms 闪烁 LED2;

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

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

4.2、代码实现

1、freertos.c

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * File Name          : freertos.c
  * Description        : Code for freertos applications
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "cmsis_os.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN Variables */

/* USER CODE END Variables */
osThreadId TaskLED1Handle;
osThreadId TaskLED2Handle;
osThreadId TaskKEY1Handle;
osThreadId TaskKEY2Handle;

/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes */

/* USER CODE END FunctionPrototypes */

void StartTaskLED1(void const * argument);
void StartTaskLED2(void const * argument);
void StartTaskKEY1(void const * argument);
void StartTaskKEY2(void const * argument);

void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */

/* GetIdleTaskMemory prototype (linked to static allocation support) */
void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize );

/* USER CODE BEGIN GET_IDLE_TASK_MEMORY */
static StaticTask_t xIdleTaskTCBBuffer;
static StackType_t xIdleStack[configMINIMAL_STACK_SIZE];

void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize )
{
  *ppxIdleTaskTCBBuffer = &xIdleTaskTCBBuffer;
  *ppxIdleTaskStackBuffer = &xIdleStack[0];
  *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
  /* place for user code */
}
/* USER CODE END GET_IDLE_TASK_MEMORY */

/**
  * @brief  FreeRTOS initialization
  * @param  None
  * @retval None
  */
void MX_FREERTOS_Init(void) {
  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* USER CODE BEGIN RTOS_MUTEX */
  /* add mutexes, ... */
  /* USER CODE END RTOS_MUTEX */

  /* USER CODE BEGIN RTOS_SEMAPHORES */
  /* add semaphores, ... */
  /* USER CODE END RTOS_SEMAPHORES */

  /* USER CODE BEGIN RTOS_TIMERS */
  /* start timers, add new ones, ... */
  /* USER CODE END RTOS_TIMERS */

  /* USER CODE BEGIN RTOS_QUEUES */
  /* add queues, ... */
  /* USER CODE END RTOS_QUEUES */

  /* Create the thread(s) */
  /* definition and creation of TaskLED1 */
  osThreadDef(TaskLED1, StartTaskLED1, osPriorityNormal, 0, 128);
  TaskLED1Handle = osThreadCreate(osThread(TaskLED1), NULL);			/*创建任务,成功返回返回任务句柄,失败返回NULL*/

  /* definition and creation of TaskLED2 */
  osThreadDef(TaskLED2, StartTaskLED2, osPriorityNormal, 0, 128);
  TaskLED2Handle = osThreadCreate(osThread(TaskLED2), NULL);

  /* definition and creation of TaskKEY1 */
  osThreadDef(TaskKEY1, StartTaskKEY1, osPriorityNormal, 0, 128);
  TaskKEY1Handle = osThreadCreate(osThread(TaskKEY1), NULL);

  /* definition and creation of TaskKEY2 */
  osThreadDef(TaskKEY2, StartTaskKEY2, osPriorityIdle, 0, 128);
  TaskKEY2Handle = osThreadCreate(osThread(TaskKEY2), NULL);

  /* USER CODE BEGIN RTOS_THREADS */
  /* add threads, ... */
  /* USER CODE END RTOS_THREADS */

}

/* USER CODE BEGIN Header_StartTaskLED1 */
/**
  * @brief  Function implementing the TaskLED1 thread.
  * @param  argument: Not used
  * @retval None
  */
/* USER CODE END Header_StartTaskLED1 */
void StartTaskLED1(void const * argument)
{
  /* USER CODE BEGIN StartTaskLED1 */
  /* Infinite loop */
  for(;;)
  {
		HAL_GPIO_TogglePin(GPIOB ,GPIO_PIN_8);
    osDelay(500);
  }
  /* USER CODE END StartTaskLED1 */
}

/* USER CODE BEGIN Header_StartTaskLED2 */
/**
* @brief Function implementing the TaskLED2 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTaskLED2 */
void StartTaskLED2(void const * argument)
{
  /* USER CODE BEGIN StartTaskLED2 */
  /* Infinite loop */
  for(;;)
  {
    HAL_GPIO_TogglePin(GPIOB ,GPIO_PIN_9);
    osDelay(1000);
  }
  /* USER CODE END StartTaskLED2 */
}

/* 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(TaskLED1Handle == NULL)			/*判断任务是否存在,创建任务的时候,成功返回任务句柄,失败返回NULL*/
				{
					printf("TaskLED1不存在,准备创建任务\r\n");
					osThreadDef(TaskLED1, StartTaskLED1, osPriorityNormal, 0, 128);
					TaskLED1Handle = osThreadCreate(osThread(TaskLED1), NULL);			/*创建任务,成功返回返回任务句柄,失败返回NULL*/
					if(TaskLED1Handle != NULL)
						printf("TaskLED1任务创建成功\r\n");
					else
						printf("TaskLED1任务创建失败\r\n");
				}
				else
				{
					printf("TaskLED1存在,删除任务\r\n");
					vTaskDelete(TaskLED1Handle);		/*删除任务,参数为任务句柄*/
					TaskLED1Handle = NULL;					/*删除任务后,需要将任务句柄指向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 char TaskLED2_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(TaskLED2_flag == 0)				/*任务存在*/			
				{
					vTaskSuspend(TaskLED2Handle);
					printf("TaskLED2正常运行,挂起(暂停)任务\r\n");
					TaskLED2_flag = 1;
				}
				else
				{
					vTaskResume(TaskLED2Handle);
					printf("TaskLED2任务恢复\r\n");
					TaskLED2_flag = 0;
				}
			}
			while(HAL_GPIO_ReadPin(GPIOA ,GPIO_PIN_1) == GPIO_PIN_RESET);			/*防止按键按下被多次触发*/
		}
    osDelay(10);
  }
  /* USER CODE END StartTaskKEY2 */
}

/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */

/* USER CODE END Application */

2.uart.c

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    usart.c
  * @brief   This file provides code for the configuration
  *          of the USART instances.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "usart.h"

/* USER CODE BEGIN 0 */
#include <stdio.h>
/*printf重定向*/
int fputc(int ch, FILE *f)
{
	unsigned char temp[1]={ch};
	HAL_UART_Transmit(&huart1,temp,1,0xffff);
	return ch;
}

/* USER CODE END 0 */

UART_HandleTypeDef huart1;

/* USART1 init function */

void MX_USART1_UART_Init(void)
{

  /* USER CODE BEGIN USART1_Init 0 */

  /* USER CODE END USART1_Init 0 */

  /* USER CODE BEGIN USART1_Init 1 */

  /* USER CODE END USART1_Init 1 */
  huart1.Instance = USART1;
  huart1.Init.BaudRate = 115200;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART1_Init 2 */

  /* USER CODE END USART1_Init 2 */

}

void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(uartHandle->Instance==USART1)
  {
  /* USER CODE BEGIN USART1_MspInit 0 */

  /* USER CODE END USART1_MspInit 0 */
    /* USART1 clock enable */
    __HAL_RCC_USART1_CLK_ENABLE();

    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**USART1 GPIO Configuration
    PA9     ------> USART1_TX
    PA10     ------> USART1_RX
    */
    GPIO_InitStruct.Pin = GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /* USER CODE BEGIN USART1_MspInit 1 */

  /* USER CODE END USART1_MspInit 1 */
  }
}

void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
{

  if(uartHandle->Instance==USART1)
  {
  /* USER CODE BEGIN USART1_MspDeInit 0 */

  /* USER CODE END USART1_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_USART1_CLK_DISABLE();

    /**USART1 GPIO Configuration
    PA9     ------> USART1_TX
    PA10     ------> USART1_RX
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9|GPIO_PIN_10);

  /* USER CODE BEGIN USART1_MspDeInit 1 */

  /* USER CODE END USART1_MspDeInit 1 */
  }
}

/* USER CODE BEGIN 1 */

/* USER CODE END 1 */

  • 34
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
FreeRTOS中任务的优先级通过配置文件FreeRTOSConfig.h中的configMAX_PRIORITIES宏定义进行设置。用户可以将可用的优先级范围从0到configMAX_PRIORITIES - 1进行配置。建议将configMAX_PRIORITIES的最大值设置为不超过32。空闲任务的优先级为0,而任务的优先级数值越小,优先级越低。 通常情况下,任务的优先级可以根据以下几个方案进行分配: 1. 中断任务:这些任务是通过中断服务程序触发的,应该设置为所有任务中优先级最高的。 2. 高优先级后台任务:例如按键检测、触摸检测、USB消息处理、串口消息处理等,这类任务可以归为高优先级后台任务。 3. 低优先级的时间片调度任务:例如emWin的界面显示、LED数码管的显示等不需要实时执行的任务,可以归为低优先级的时间片调度任务。 4. 空闲任务:空闲任务是系统任务。 需要注意的是,中断的优先级永远高于任何任务的优先级,即任务在执行的过程中,中断来了就开始执行中断服务程序。因此,中断优先级的数值越小,优先级越高;任务优先级数值越小,优先级越低。 关于为什么设置最大优先级为32个的疑惑,实际上,虽然一般十几个优先级就足够使用了,但是最大优先级的设置还是有一些限制条件的。具体限制条件可能与系统硬件或软件的实现有关,但是没有提供具体的信息。 在FreeRTOS中,任务的调度器会根据优先级来选择就绪任务进行执行。调度器会从优先级最高的任务开始查找就绪任务,如果找到了就会跳出循环,将找到的任务分配给TCB任务控制块去执行。然后,将找到的优先级传递给uxTopReadyPriority变量。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [FreeRTOS任务优先级](https://blog.csdn.net/m0_55744970/article/details/125951720)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [FreeRTOS学习(二)——任务优先级问题](https://blog.csdn.net/qq_39397153/article/details/123666584)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值