一、简介
**时间片调度:**同等优先级任务轮流地享有相同的CPU时间(可设置),叫时间片,在FreeRTOS中,一个时间片就等于SysTick中断周期;
二、实验
实验设计:

把滴答定时器中断频率设置为50ms,需要修改FreeRTOSConfig.h里面的宏:
1s / 50ms = 20Hz
#define configTICK_RATE_HZ ( ( TickType_t ) 20) // 系统节拍频率,20Hz(50ms 一个节拍)

代码:
main.c
cs
#include "stm32f10x.h"
#include "FreeRTOS.h"
#include "task.h"
#include "freertos_demo.h"
#include "Delay.h"
#include "sys.h"
#include "usart.h"
#include "LED.h"
#include "Key.h"
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组 4
uart_init(115200);
delay_init();
// 创建任务
FrrrRTOS_Demo();
}
freertos_demo.c
cs
#include "FreeRTOS.h"
#include "task.h"
#include "LED.h"
#include "Key.h"
#include "usart.h"
#include "delay.h"
/******************************************************************任务配置****************************************************/
//任务优先级
#define START_TASK_PRIO 1
//任务堆栈大小
#define START_TASK_STACK_SIZE 128
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters);
//任务优先级
#define TASK1_PRIO 2
//任务堆栈大小
#define TASK1_STACK_SIZE 128
//任务句柄
TaskHandle_t Task1_Handler;
//任务函数
void task1(void *pvParameters);
//任务优先级
#define TASK2_PRIO 2
//任务堆栈大小
#define TASK2_STACK_SIZE 128
//任务句柄
TaskHandle_t Task2_Handler;
//任务函数
void task2(void *pvParameters);
/******************************************************************任务函数****************************************************/
void FrrrRTOS_Demo(void)
{
//创建开始任务
xTaskCreate((TaskFunction_t )start_task, //任务函数
( char* )"start_task", //任务名称
(uint16_t )START_TASK_STACK_SIZE, //任务堆栈大小
(void* )NULL, //传递给任务函数的参数
(UBaseType_t )START_TASK_PRIO, //任务优先级
(TaskHandle_t* )&StartTask_Handler); //任务句柄
// 启动任务调度
vTaskStartScheduler();
}
void start_task(void *pvParameters)
{
taskENTER_CRITICAL(); //进入临界区
//创建1任务
xTaskCreate((TaskFunction_t )task1,
(const char* )"task1",
(uint16_t )TASK1_STACK_SIZE,
(void* )NULL,
(UBaseType_t )TASK1_PRIO,
(TaskHandle_t* )&Task1_Handler);
//创建2任务
xTaskCreate((TaskFunction_t )task2,
(const char* )"task2",
(uint16_t )TASK2_STACK_SIZE,
(void* )NULL,
(UBaseType_t )TASK2_PRIO,
(TaskHandle_t* )&Task2_Handler);
vTaskDelete(NULL); //删除开始任务
taskEXIT_CRITICAL(); //退出临界区
}
//1 任务函数
void task1(void *pvParameters)
{
uint32_t task1_num = 0;
while(1)
{
taskENTER_CRITICAL(); //进入临界区
printf("任务1运行次数:%d\r\n",++task1_num);
taskEXIT_CRITICAL(); //退出临界区
delay_xms(10);
}
}
//2 任务函数
void task2(void *pvParameters)
{
uint32_t task2_num = 0;
while(1)
{
taskENTER_CRITICAL(); //进入临界区
printf("任务2运行次数:%d\r\n",++task2_num);
taskEXIT_CRITICAL(); //退出临界区
delay_xms(10);
}
}
实验解析 :
不加临界区:

平均每个任务打印4次;这时候就有人问了为什么滴答定时器的中断中期是50ms,而打印时间间隔是10ms,50/10 = 5;却只打印了四次?
因为打印也需要时间,所以打印次数可能是4~5次;
看上图打印的时候有些信息未打印完整,就开始任务切换了,那是因为一个时间片只有50ms,可能没打印完就到时间了。
添加临界区:

添加临界区就会强制执行完打印信息在切换,就不会出现上述问题了。
三、重点
滴答定时中断周期频率设置:
1000(ms)/ 中断周期 = 一个周期所需要时间
#define configTICK_RATE_HZ ( ( TickType_t ) 20 ) // 系统节拍频率,1000Hz(50ms 一个节拍)
时间片特性:
给任务分配的一个时间片,不管任务是否完成都不会继续等待;未使用完的时间片,直接丢弃;下次轮到这个任务重新分配一个时间片。