目录
一、时间片调度介绍
二、实验演示
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 实验现象
可以看到由于临界区保护,都打印出了完整的信息