当前位置: 首页 > article >正文

FreeRTOS学习11——时间片任务调度

时间片任务调度

    • 时间片任务调度

时间片任务调度

概念:时间片调度主要针对优先级相同的任务,当多个任务的优先级相同时,任务调度器会在每一次系统时钟节拍到的时候切换任务,也就是说 CPU 轮流运行优先级相同的任务,每个任务运行的时间就是一个系统时钟节拍。

同等优先级任务轮流地享有相同的 CPU 时间(可设置), 叫时间片,在FreeRTOS中,一个时间片就等于SysTick 中断周期

特点:

  • 同等优先级任务,轮流执行;时间片流转
  • 一个时间片大小,取决为滴答定时器中断频率
  • 注意没有用完的时间片不会再使用,下个任务得到执行还是按照一个时间片的时钟节拍运行

下面我们举个例子详细说

image-20241111200848938

我们创建优先级相同的几个任务,其运行流程如下

  1. 首先Task1运行完一个时间片后,切换至Task2运行
  2. Task2运行完一个时间片后,切换至Task3运行
  3. Task3运行过程中(还不到一个时间片),Task3阻塞了(系统延时或等待信号量等),此时直接切换到下一个任务Task1
  4. Task1运行完一个时间片后,切换至Task2运行

接下来用一个实验来验证我们的理论

​ 实验设计:将设计三个任务:start_task、task1、task2,其中task1和task2优先级相同均为2。为了使现象明显,将滴答定时器的中断频率设置为50ms中断一次,即一个时间片50ms

​ 三个任务的功能如下:

  • start_task:用来创建其他的2个任务
  • task1:通过串口打印task1的运行次数
  • task2:通过串口打印task2的运行次数

注意:使用时间片调度需把宏 configUSE_TIME_SLICING 和configUSE_PREEMPTION 置1

在打印任务运行次数的时候需要使用到串口硬件,为了避免多个任务“同时”使用同一个硬件,因此在使用串口硬件打印任务运行次数之前,进入临界区,在使用串口硬件打印任务运行次数之后,再退出临界区

实验代码freertos_demo.c

#include "freertos_demo.h"
#include "usart.h"
#include "led.h"
#include "key.h"
#include "delay.h"
/*FreeRTOS********************************************************************/
#include "FreeRTOS.h"
#include "task.h"
/*****************************************************************************/
/*FreeRTOS 配置*/
/* START_TASK 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define START_TASK_PRIO 1 							/* 任务优先级 */
#define START_STK_SIZE 128 							/* 任务堆栈大小 */
TaskHandle_t StartTask_Handler; 				/* 任务句柄 */
void start_task(void *pvParameters); 		/* 任务函数 */
/* TASK1 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define TASK1_PRIO 2 										/* 任务优先级 */
#define TASK1_STK_SIZE 128 							/* 任务堆栈大小 */
TaskHandle_t Task1Task_Handler;			 		/* 任务句柄 */
void task1(void *pvParameters); 				/* 任务函数 */
/* TASK2 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define TASK2_PRIO 2										/* 任务优先级 */
#define TASK2_STK_SIZE 128 							/* 任务堆栈大小 */
TaskHandle_t Task2Task_Handler;			 		/* 任务句柄 */
void task2(void *pvParameters); 				/* 任务函数 */



/*****************************************************************************/

/**
* @brief FreeRTOS 例程入口函数
* @param 无
* @retval 无
*/
void freertos_demo(void)
{
	 xTaskCreate((TaskFunction_t )start_task, 				/* 任务函数 */
							 (const char* )"start_task", 					/* 任务名称 */
							 (uint16_t )START_STK_SIZE, 					/* 任务堆栈大小 */
							 (void* )NULL, 												/* 传入给任务函数的参数 */
							 (UBaseType_t )START_TASK_PRIO,				/* 任务优先级 */
							 (TaskHandle_t* )&StartTask_Handler); /* 任务句柄 */
	 vTaskStartScheduler();                           /* 开启任务调度 */
}
/**
* @brief start_task
* @param pvParameters : 无
* @retval 无
*/
void start_task(void *pvParameters)
{
		 taskENTER_CRITICAL(); /* 进入临界区 在临界区内不进行任务调度,保证新创建的任务不会抢占start_task,也就是等所有任务创建完后再开始任务调度*/
		 /* 创建任务 1 */
		 xTaskCreate((TaskFunction_t )task1,
								 (const char* )"task1",
								 (uint16_t )TASK1_STK_SIZE,
								 (void* )NULL,
								 (UBaseType_t )TASK1_PRIO,
								 (TaskHandle_t* )&Task1Task_Handler);
								 /* 创建任务 2 */
		 xTaskCreate((TaskFunction_t )task2,
								 (const char* )"task1",
								 (uint16_t )TASK2_STK_SIZE,
								 (void* )NULL,
								 (UBaseType_t )TASK2_PRIO,
								 (TaskHandle_t* )&Task2Task_Handler);
			vTaskDelete(NULL);			/* 删除开始任务 */
		 taskEXIT_CRITICAL(); 	 /* 退出临界区 */
}
/**
* @brief task1
* @param pvParameters : 无
* @retval 无
*/
/* task1实现LED0每200ms闪烁一次*/
void task1(void *pvParameters)
{

	static uint16_t num;
	while(1)
	 {
		 taskENTER_CRITICAL();
		 num++;
		printf("任务1运行次数:%d\r\n",num);
		 taskEXIT_CRITICAL();
		 delay_ms(10);         
		}
}


/* task2 列表项的插入和删除*/
void task2(void *pvParameters)
{
	static uint16_t num;
	while(1)
	 {
		 taskENTER_CRITICAL();
		 num++;
			printf("任务2运行次数:%d\r\n",num);
		 taskEXIT_CRITICAL();
		 delay_ms(10);
	 }
}

实验现象
在这里插入图片描述
每个任务执行 四到五次
与理论相符

delay_ms(10);延时为 “死延时” 在延时时不会进行任务调度
vTaskDelay(1000);该函数在延时时会进行任务调度


http://www.kler.cn/a/389664.html

相关文章:

  • 【Java SE】接口类型
  • 【计算机网络】Socket编程接口
  • 学Linux的第八天
  • nginx部署H5端程序与PC端进行区分及代理多个项目及H5内页面刷新出现404问题。
  • [HarmonyOS]简单说一下鸿蒙架构
  • 常用中间件介绍
  • 基于多设计模式下的同步异步日志系统
  • C0028.在Clion中快速生成头文件中声明的函数的方法
  • 「Mac畅玩鸿蒙与硬件29」UI互动应用篇6 - 多选问卷小应用
  • Qt QCustomplot 在采集信号领域的应用
  • 5G NR协议栈分层
  • 2024年【R2移动式压力容器充装】考试试题及R2移动式压力容器充装操作证考试
  • AscendC从入门到精通系列(三)基于自定义算子工程开发AscendC算子
  • FastHTML快速入门:调试模式和 URL中的变量
  • CSS——选择器、PxCook软件、盒子模型
  • C++动态库和静态库的特点以及区别
  • WPF中Prism框架的简单使用
  • Linux——gcc编译过程详解与ACM时间和进度条的制作
  • 批量从Excel某一列中找到符合要求的值并提取其对应数据
  • 【笔记】LLC电路工作频点选择 2-1 输出稳定性的限制
  • 数学建模-----假设性检验引入+三个经典应用场景(三种不同的假设性检验类型)
  • 【React】深入理解 JSX语法
  • ReactPress 安装指南:从 MySQL 安装到项目启动
  • Pr 视频过渡:沉浸式视频 - VR 随机块
  • 去中心化存储:Web3中的数据安全新标准
  • linux网络管理基本知识