关于时间片轮询框架的理解
最近接触了时间片轮询的代码程序,估计很多大神都知道,但为了问题明确,我还是把这个框架说一下,免得产生误解。首先定义一个定时器产生一个时基中断。然后定义一个任务结构体,包括运行标记,轮询时间,任务函数指针等。定时器中断中通过for循环每个任务的时间减一个节拍,直到减为0,将运行标志位置一。然后主循环中同样通过for循环判断运行标志位是否为1,如果是则运行。具体是哪种框架,我还是放个链接吧,以确保百分百能明白我的问题。(我没权限加网址,看楼下能不能回复)
但是我对此有一个疑问。就是我之前设计程序时都同样初始化一个定时器时基,根据任务有啥Flag_10ms, Flag_20ms等时间标志,时间到了就在中断里面讲此标志置1.然后主循环里用if判断标志是否为1,是的话就执行功能函数,如下:
int main(void)
{
while(1)
{
if(true==Flag_10ms)
{
Flag_10ms =false;
Function1();
}
if(true==Flag_20ms)
{
Flag_20ms =false;
Function2();
}
..........
}
return 0;
}
我就觉得这两种都是一个原理啊,但为什么别人都推崇第一种呢。所以最终我有两个问题求大家解决一下:
1:这两种框架最终是不是一个原理?实现的功能效果完全一样?
2:为什么大家都比较推崇第一种,他有什么优势?是不是框架清晰,易于管理?
也不能发网址 不错,日积月累,共同提高。 没有本质区别,第一种就是规范点,可以通过初始化设定,运行过程中也可以改变,通用性强点 ayb_ice 发表于 2018-5-3 09:49
没有本质区别,第一种就是规范点,可以通过初始化设定,运行过程中也可以改变,通用性强点 ...
嗯,理解 时间片和OS都是 合理的分配CPU时间。 楼主,你的程序框架上如果一个任务运行超过了20ms运行时间,是会丢掉下一个任务的一次运行的。不能做到实时任务。做到实时任务是要时间片一结束,立即调度到下一个任务执行。 第一种叫时间片,第二种叫轮询式,需要程序能主动退出任务,早期的WIN3.2和苹果的iOS都是这样做的,各有优缺点。 本帖最后由 老陆693 于 2018-5-6 16:59 编辑
给楼主推荐一本书:《时间触发嵌入式系统设计模式》//定义一个结构
typedef struct
{
void (*pTask)(void); //函数指针
unsigned intsDelay; //休眠时间
unsigned intsPeriod; //休眠时标
unsigned char sRunMe; //运行时
}sTask;
sTask SCH_tasks_G;
unsigned char Error_code_G;
//使用单片机一个定时器做为Systemtick,这段代码放在定里器中断里面
定时器中断函数(void)
{
unsigned char uc_taskPoll;
//调试器任务查询
for(uc_taskPoll=0; uc_taskPoll<SCH_MAX_TASKS; ++uc_taskPoll)
{
if(SCH_tasks_G.pTask) //任务有分配
{
if(SCH_tasks_G.sDelay == 0) //有任务要开始
{
SCH_tasks_G.sRunMe += 1;
if(SCH_tasks_G.sPeriod)
SCH_tasks_G.sDelay = SCH_tasks_G.sPeriod;
}
else
SCH_tasks_G.sDelay -= 1;
}
}
}
//任务调度
void SCH_Disptch_Tasks(void)
{
unsigned char Index;
while(1){
for(Index=0; Index<SCH_MAX_TASKS; ++Index)
{
if(SCH_tasks_G.sRunMe > 0)
{
(*SCH_tasks_G.pTask)(); //执行任务
SCH_tasks_G.sRunMe -= 1; //清除任务需要执行的标志
if(SCH_tasks_G.sPeriod == 0) //如果这是个“单次”任务,将它从队列中删除
SCH_Delete_Task(Index);
}
//空闲任务
//SCH_Report_Status(); //报告系统状况
//SCH_Go_To_Sleep(); //进入体眠
}
}
//添加任务
//Delay:第一次运行延时,为0立即执行,以后执行按PERIOD循环时间
//单次任务将PERIOD设置为0
unsigned char SCH_Add_Task(void (* pFunction)(),
unsigned int Delay,
unsigned int PERIOD)
{
unsigned char Index = 0;
while((SCH_tasks_G.pTask != 0) && (Index < SCH_MAX_TASKS)) //找一个任务空隙放置任务
++ Index;
if(Index == SCH_MAX_TASKS) //任务列队已满
{
Error_code_G = ERROR_SCH_TOO_MANY_TASKS;
return SCH_MAX_TASKS;
}
SCH_tasks_G.pTask = pFunction;
SCH_tasks_G.sDelay = Delay;
SCH_tasks_G.sPeriod = PERIOD;
SCH_tasks_G.sRunMe = 0;
return Index;
}
//删除任务
unsigned char SCH_Delete_Task(unsigned char TASK_INDEX)
{
unsigned char Return_code;
if(SCH_tasks_G.pTask == 0)
{
//这里没有任务。。。设置全局错误变量
Error_code_G = ERROR_SCH_CANOT_DELETE_TASK;
Return_code = RETURN_ERROR;//返回错误代码
}
else
{
Return_code = RETURN_NORMAL;
//删除任务
SCH_tasks_G.pTask = 0x0000;
SCH_tasks_G.sDelay = 0;
SCH_tasks_G.sPeriod = 0;
SCH_tasks_G.sRunMe = 0;
}
return Return_code;
}
PS:上面代码仅供参考,涉及中断保护没有给出,随便使用,没有版权,后果自负。
这种结构易于维护,代码可读性高,写程序的时候注意一下时间片和执行时间,可以确定程序运行时间。
再有就是常常需要休眠降低功耗的场合灰常适用。
老陆693 发表于 2018-5-6 16:50
给楼主推荐一本书:《时间触发嵌入式系统设计模式》//定义一个结构
typedef struct
{
你这个任务的调度时间复杂度是 O(N) ,如果用查表优先级 O(C) ,常数C固定的,调度是时间固定,像uC/OS 一样的,可以搞16个任务优先级表来查询。 说的还不错 深入理解不错。
页:
[1]