1. 基于时间片的轮询调度算法(仅局限单核CPU芯片):
利用定时器为每个任务函数设定执行时间间隔,保证使用频率高的函数多次被调用,提高单核芯片的资源利用率。如果只是简单地将A、B两个函数放在while中,那么在一定时间内这两个函数调用的次数是一致的,,这样就浪费了单核芯片的资源。
2. 例子:
函数A(100μs执行一次----使用频率高),
函数B(1000μs执行一次----使用频率低)。
那么在1ms 内 函数A 执行了10次,而函数B只执行1次
当然你要保证函数A在100μs内执行完毕、函数B在1000μs内执行完毕
如果超出时间的话系统会变得卡顿。有部分的函数可能没有别执行到。毕竟单核芯片只在很短时间内只做一件事。
3. PS
1、从微观上单核芯片在某一个和短时间时间段只执行一件事。从宏观上 (比如:1S):单核芯片执行多件事情;
2、任务函数最好不要出现delay等延时函数,不然整个系统变得卡顿。
4. 为了更好地理解上述描述,可以结合以下代码理解(基于STM32F103C8T6芯片编写)
API_Schedule.c
#include "API_Schedule.h"
#include "stdlib.h"
/************任务初始化,每一个结构体都代表一个任务,添加任务和删减任务都在这里完成************/
struct TaskStruct TaskST[]=
{
// 计时 多少ms调用一次 任务运行标志位 任务函数指针
{ 0, 5000, 0, LedFlash},
{ 0, 1000, 0, UARTFC},
{ 0, 500, 0, UserTestMode},
};
/*******************************搭建时间片轮询机制代码框架********************************/
//记录任务数量
u8 TaskCount= sizeof(TaskST)/sizeof(TaskST[0]);
//放在“TIM2_IRQHandler”中断执行,用于任务计时
void OS_IT_RUN(void)
{
u8 i;
for(i=0;i if(!TaskST[i].TaskStatus) { if(++TaskST[i].TaskTickNow >= TaskST[i].TaskTickMax)//计时,并判断是否到达定时时间 { TaskST[i].TaskTickNow = 0; TaskST[i].TaskStatus = 1; } } } } //放在main函数中执行,自带死循环,用于执行挂起的任务 void PeachOSRun(void) { u8 j=0; while(1) { if(TaskST[j].TaskStatus)//判断一个任务是否被挂起 { TaskST[j].FC(); //执行该任务函数 TaskST[j].TaskStatus=0; //取消任务的挂起状态 } if(++j>=TaskCount)//相当于不断循环遍历所有的任务 j=0; } } /*************************计划表中的任务*****************************/ void LedFlash(void) { //printf("Led n");//调试用,需要自己添加uart外设后再使用这段代码 } void UARTFC(void) { //printf("UARTFC n");//调试用 } void UserTestMode(void) { //printf("UserTestMode n");//调试用 } API_Schedule.h #ifndef __API_SCHEDULE_H__ #define __API_SCHEDULE_H__ #include "stm32f10x.h" //框架运行所需的函数声明 void PeachOSRun(void); void OS_IT_RUN(void); /* 用与存储一个任务运行的数据 */ struct TaskStruct { u16 TaskTickNow;//用于计时 u16 TaskTickMax;//设置计时时间 u8 TaskStatus;//任务运行标志位 void (*FC)();//任务函数指针 }; extern struct TaskStruct TaskST[]; //声明为结构体数据,那样多个任务时方便管理 //用于示例的任务函数声明 void LedFlash(void); void UARTFC(void); void UserTestMode(void); #endif bsp_time.c #include "bsp_time.h" //中断初始化 void Time2_NVIC_Init() { NVIC_InitTypeDef NVIC_InitStruct; NVIC_InitStruct.NVIC_IRQChannel = TIM2_IRQn; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2; NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2; NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); NVIC_Init(&NVIC_InitStruct); } //定时器初始化 void Time2_Init(u16 arr,u16 psr) { TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); TIM_TimeBaseInitStruct.TIM_ClockDivision = 0; TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInitStruct.TIM_Period = arr; TIM_TimeBaseInitStruct.TIM_Prescaler = psr; TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct); TIM_ITConfig(TIM2, TIM_IT_Update,ENABLE); TIM_Cmd(TIM2, ENABLE); Time2_NVIC_Init(); } //定时器中断 void TIM2_IRQHandler(void) { if(TIM_GetITStatus(TIM2,TIM_IT_Update) != RESET) { OS_IT_RUN(); TIM_ClearITPendingBit(TIM2,TIM_IT_Update); } } bsp_time.h #ifndef __TIME_H #define __TIME_H #include "stm32f10x.h" #include "API_Schedule.h" void Time2_Init(u16 arr,u16 psr); #endif main.c #include "stm32f10x.h" #include "bsp_time.h" #include "API_Schedule.h" int main(void) { Time2_Init(71,1000); PeachOSRun(); }
上一篇:STM32F1系列HAL库配置串口通信(2)——串口重定向以及log信息格式输出
下一篇:STM32串口空闲中断的使用
推荐阅读最新更新时间:2024-11-12 10:17
设计资源 培训 开发板 精华推荐
- LTC6262IDC 低功率、低失真 ADC 驱动器、运算放大器的典型应用
- 24V 三相 BLDC 电机控制演示 - 搅拌机应用
- LT1171HVCT、5V/2.5A 升压转换器的典型应用
- 使用符合 EN55022 A 类(双输出)EMC 滤波的 RP40-2415SFR DC/DC 转换器的典型应用
- NCP300LSN34T1 3.4V LED条形图电压监视器的典型应用
- LTC2633-LZ12 双路 12 位数模转换器的典型应用
- NCP4545 生态开关的典型应用具有低 RON 的高级负载管理控制负载开关,用于外部泄放电阻器,具有开启延迟和压摆率的单电容器调整
- MDK-ST10,基于 ST10F276 闪存微控制器的运动开发套件
- AD566A高速12位单片数模转换器的典型应用
- 使用 Analog Devices 的 LTC1450CN 的参考设计