目录
一、时间片调度介绍
二、实验演示
1、宏修改
1.1、滴答定时器宏
1.2、调度器宏
2、实验程序
2.1.1、任务1,任务2不加临界区程序
2.1.2 实验现象
2.2.1、任务1,任务2加临界区程序
2.2.2 实验现象
一、时间片调度介绍
时间片:同等优先级任务轮流地享有相同的CPU时间
在FreeRTOS中,一个时间片等于SysTick中断周期。如果需要修改时间片时间长短,就要修改滴答定时器中断频率。
如果任务提前结束,直接进行下一个任务,没有用完的时间不会在使用,无论是下一个任务还是本任务再次执行都按一个时间片节拍运行。
运行过程:
1、Task1运行完一个时间片后,切换到Task2运行
2、Task2运行完一个时间片后,切换到Task3运行
3、Task3运行过程中,Task3阻塞了(系统延时或等待信号量等),此时直接切换到下一个任务
二、实验演示
1、宏修改
1.1、滴答定时器宏
#define configTICK_RATE_HZ 20 /* 定义系统时钟节拍频率, 单位: Hz, 无默认需定义 */
实验要求一个时间片是50ms,则设置为20Hz
1.2、调度器宏
#define configUSE_PREEMPTION 1 /* 1: 抢占式调度器, 0: 协程式调度器, 无默认需定义 */
#define configUSE_TIME_SLICING 1 /* 1: 使能时间片调度, 默认: 1 */
都设置为1
2、实验程序
2.1.1、任务1,任务2不加临界区程序
/******************************************************************************************************/
/*FreeRTOS配置*/
/* START_TASK 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define START_TASK_STACK_SIZE 128
#define START_TASK_PRIO 1
TaskHandle_t start_task_handler;
void start_task( void * pvParameters );
#define TASK1_STACK_SIZE 128
#define TASK1_PRIO 2
TaskHandle_t task1_handler;
void task1( void * pvParameters );
#define TASK2_STACK_SIZE 128
#define TASK2_PRIO 2
TaskHandle_t task2_handler;
void task2( void * pvParameters );
/******************************************************************************************************/
/**
* @brief FreeRTOS例程入口函数
* @param 无
* @retval 无
*/
void freertos_demo(void)
{
xTaskCreate( (TaskFunction_t ) start_task,
(char * ) "start_task",
(configSTACK_DEPTH_TYPE) START_TASK_STACK_SIZE,
(void * ) NULL,
(UBaseType_t ) START_TASK_PRIO,
(TaskHandle_t * ) &start_task_handler );
vTaskStartScheduler();
}
void start_task( void * pvParameters )
{
taskENTER_CRITICAL();/*进入临界区*/
xTaskCreate( (TaskFunction_t ) task1,
(char * ) "task1",
(configSTACK_DEPTH_TYPE) TASK1_STACK_SIZE,
(void * ) NULL,
(UBaseType_t ) TASK1_PRIO,
(TaskHandle_t * ) &task1_handler );
xTaskCreate( (TaskFunction_t ) task2,
(char * ) "task2",
(configSTACK_DEPTH_TYPE) TASK2_STACK_SIZE,
(void * ) NULL,
(UBaseType_t ) TASK2_PRIO,
(TaskHandle_t * ) &task2_handler );
vTaskDelete(NULL);
taskEXIT_CRITICAL(); /*退出临界区*/
}
void task1( void * pvParameters )
{
uint32_t task1_num = 0;
while(1)
{
printf("task1运行次数:%d\r\n",++task1_num);
delay_ms(10);//FreeRTOS的延迟函数会将任务挂载到阻塞列表,导致任务提前结束
//而delay_ms()只会死等
}
}
void task2( void * pvParameters )
{
uint32_t task2_num = 0;
while(1)
{
printf("task2运行次数:%d\r\n",++task2_num);
delay_ms(10);
}
}
2.1.2 实验现象
打印出运行次数,但是会出现打印的不完整。因为本次任务未执行完,调度器切换到下一个任务
2.2.1、任务1,任务2加临界区程序
/******************************************************************************************************/
/*FreeRTOS配置*/
/* START_TASK 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define START_TASK_STACK_SIZE 128
#define START_TASK_PRIO 1
TaskHandle_t start_task_handler;
void start_task( void * pvParameters );
#define TASK1_STACK_SIZE 128
#define TASK1_PRIO 2
TaskHandle_t task1_handler;
void task1( void * pvParameters );
#define TASK2_STACK_SIZE 128
#define TASK2_PRIO 2
TaskHandle_t task2_handler;
void task2( void * pvParameters );
/******************************************************************************************************/
/**
* @brief FreeRTOS例程入口函数
* @param 无
* @retval 无
*/
void freertos_demo(void)
{
xTaskCreate( (TaskFunction_t ) start_task,
(char * ) "start_task",
(configSTACK_DEPTH_TYPE) START_TASK_STACK_SIZE,
(void * ) NULL,
(UBaseType_t ) START_TASK_PRIO,
(TaskHandle_t * ) &start_task_handler );
vTaskStartScheduler();
}
void start_task( void * pvParameters )
{
taskENTER_CRITICAL();/*进入临界区*/
xTaskCreate( (TaskFunction_t ) task1,
(char * ) "task1",
(configSTACK_DEPTH_TYPE) TASK1_STACK_SIZE,
(void * ) NULL,
(UBaseType_t ) TASK1_PRIO,
(TaskHandle_t * ) &task1_handler );
xTaskCreate( (TaskFunction_t ) task2,
(char * ) "task2",
(configSTACK_DEPTH_TYPE) TASK2_STACK_SIZE,
(void * ) NULL,
(UBaseType_t ) TASK2_PRIO,
(TaskHandle_t * ) &task2_handler );
vTaskDelete(NULL);
taskEXIT_CRITICAL(); /*退出临界区*/
}
void task1( void * pvParameters )
{
uint32_t task1_num = 0;
while(1)
{
taskENTER_CRITICAL();/*进入临界区*/
printf("task1运行次数:%d\r\n",++task1_num);
delay_ms(10);//FreeRTOS的延迟函数会将任务挂载到阻塞列表,导致任务提前结束
//而delay_ms()只会死等
taskEXIT_CRITICAL(); /*退出临界区*/
}
}
void task2( void * pvParameters )
{
uint32_t task2_num = 0;
while(1)
{
taskENTER_CRITICAL();/*进入临界区*/
printf("task2运行次数:%d\r\n",++task2_num);
delay_ms(10);
taskEXIT_CRITICAL(); /*退出临界区*/
}
}
2.2.2 实验现象
可以看到由于临界区保护,都打印出了完整的信息