STM32基于时间片轮询机制

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芯片编写)

  1. 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<TaskCount;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");//调试用
}

  1. 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

  1. 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);
	}
}

  1. bsp_time.h
#ifndef __TIME_H
#define __TIME_H

#include "stm32f10x.h"
#include "API_Schedule.h"

void Time2_Init(u16 arr,u16 psr);

#endif

  1. main.c
#include "stm32f10x.h"
#include "bsp_time.h"
#include "API_Schedule.h"


int main(void)
{
	Time2_Init(71,1000);	
	PeachOSRun();
}


  • 8
    点赞
  • 79
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值