时间片轮询法

注: 我看了,网上大多数博客都是用这份代码做讲解,所以我也是用它来说明自己的理解,我是在微信上看到的这篇文章,等我找到原作者,我再附上转载链接

在这里插入图片描述

序言

程序开发分为几种模式:裸机开发,时间片轮询,系统级开发。裸机开发,有过单片机开发经验的朋友应该都很熟悉了,这是一种没有任何架构设计的开发,一套程序从头到尾。时间片轮询,这是我们今天要介绍的对象,也是我最近新get到的技能,我们待会儿详说。系统级开发,这是我将来打算发展的方向,但是由于目前还在理论储备阶段,所以没有任何开发经验。等过几年再说。所以我们今天的主角是:时间片轮询法

基本思想

举个例子,有一个函数A,我们给它设置一个计数器B(程序多久执行一次)和一个状态标志位C(用来判断这个程序是否需要执行)还有一个计数填充值D,其中的B会被单片机自带的定时器中断服务函数不断地刷新(递减刷新),当B到0的时候C会被置位,同时B会被重新填满D值,当主程序运行到A的时候不会直接去运行它,而是先检查C,如果C没有被置位,说明还没有到A的执行时间,不执行A,如果C被置位了,就执行A,执行完后将C复位,让C再等上一段时间才再次被执行。

代码实现

任务结构体

下面是任务结构体,它包含了一个任务所需要的所有信息,包括运行状态标志位,计数器,计数器数值填充器(任务运行间隔时间)以及这个任务对应的函数指针

// 任务结构
typedef struct _TASK_COMPONENTS
{
    uint8 Run;                  // 程序运行标记:0-不运行,1运行
    uint8 Timer;                // 计时器
    uint8 ItvTime;              // 任务运行间隔时间
    void (*TaskHook)(void);    // 要运行的任务函数
} TASK_COMPONENTS;       // 任务定义

任务数组

下面是任务数组,当我们需要添加一个任务到时间片轮询队列中的时候,我只需要再这里添加函数指针,设置好相关参数就可以了

static TASK_COMPONENTS TaskComps[] = 
{
    {0, 60, 60, TaskDisplayClock},     // 显示时钟
    {0, 20, 20, TaskKeySan},           // 按键扫描
    {0, 30, 30, TaskDispStatus},       // 显示工作状态
 
     // 这里添加你的任务。。。。
};

任务列表

typedef enum _TASK_LIST
{
    TAST_DISP_CLOCK,            // 显示时钟
    TAST_KEY_SAN,             // 按键扫描
    TASK_DISP_WS,             // 工作状态显示
     // 这里添加你的任务。。。。
     TASKS_MAX                                           // 总的可供分配的定时任务数目
} TASK_LIST;

标志位处理函数

这个函数是用来更新每个任务的计数器以及它们的运行标志位的,它是写在单片机的定时器中断服务函数中的

void TaskRemarks(void)
{
    uint8 i;
 
    for (i=0; i<TASKS_MAX; i++)          // 逐个任务时间处理
    {
         if (TaskComps[i].Timer)          // 时间不为0
        {
            TaskComps[i].Timer--;         // 减去一个节拍
            if (TaskComps[i].Timer == 0)       // 时间减完了
            {
                 TaskComps[i].Timer = TaskComps[i].ItvTime;       // 恢复计时器值,从新下一次
                 TaskComps[i].Run = 1;           // 任务可以运行
            }
        }
   }
}

任务处理函数

这个函数用来判断任务是否到了执行时间,它会逐个检查任务列表中的任务,如果到了就执行,同时清空执行标志位,没到就不执行

void TaskProcess(void)
{
    uint8 i;
 
    for (i=0; i<TASKS_MAX; i++)           // 逐个任务时间处理
    {
         if (TaskComps[i].Run)           // 时间不为0
        {
             TaskComps[i].TaskHook();         // 运行任务
             TaskComps[i].Run = 0;          // 标志清0
        }
    }   
}

任务函数

/**************************************************************************************
* FunctionName   : TaskDisplayClock()
* Description    : 显示任务
 
* EntryParameter : None
* ReturnValue    : None
**************************************************************************************/
void TaskDisplayClock(void)
{
 
 
 
}
 
/**************************************************************************************
* FunctionName   : TaskKeySan()
* Description    : 扫描任务
* EntryParameter : None
* ReturnValue    : None
**************************************************************************************/
void TaskKeySan(void)
{
 
 
}
 
/**************************************************************************************
* FunctionName   : TaskDispStatus()
* Description    : 工作状态显示
* EntryParameter : None
* ReturnValue    : None
**************************************************************************************/
void TaskDispStatus(void)
{
 
 
}

中断服务函数

/**************************************************************************************
* FunctionName : TimerInterrupt()
* Description : 定时中断服务函数
* EntryParameter : None
* ReturnValue : None
**************************************************************************************/
void TimerInterrupt(void)
{
    TaskRemarks( );
}

主函数

/**************************************************************************************
* FunctionName   : main()
* Description    : 主函数
* EntryParameter : None
* ReturnValue    : None
**************************************************************************************/
int main(void) 
{ 
    InitSys();                  // 初始化
 
    while (1)
    {
        TaskProcess();             // 任务处理
    }
}

架构图解

下面这个图片可以帮助理解上面的代码的整体架构
在这里插入图片描述


总结

整个程序的执行流程就是:中断函数不断刷新着每一个任务的状态,任务处理函数根据这些状态来判断哪些函数要被执行,如果要执行,就立马执行。添加任务就是在任务数组中添加一个结构体信息,编写一个任务函数,在任务列表中添加一个函数。

  • 17
    点赞
  • 115
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
时间轮询是一种常见的实现多任务调度的方。它将 CPU 的时间片分配给多个任务,每个任务在一个时间段内运行一定的时间,在时间片结束之后,操作系统会切换到下一个任务,直至所有任务完成。以下是一个简单的时间轮询例程的伪代码: ``` while (true) { for (i = 0; i < num_tasks; i++) { if (tasks[i].state == RUNNING) { // 如果当前任务正在运行 tasks[i].run_time++; // 增加运行时间 if (tasks[i].run_time >= time_slice) { // 如果运行时间达到时间片 tasks[i].state = READY; // 将任务状态设置为就绪 tasks[i].run_time = 0; // 重置运行时间 } } } for (i = 0; i < num_tasks; i++) { if (tasks[i].state == READY) { // 如果当前任务处于就绪状态 tasks[i].state = RUNNING; // 将任务状态设置为运行 run_task(&tasks[i]); // 运行任务 } } } ``` 在这个例程中,我们假设有一个任务列表 `tasks`,每个任务包含一个状态(运行、就绪、阻塞等)和已经运行的时间。在时间轮询的过程中,我们逐个检查每个任务的状态,如果任务正在运行,就增加它的运行时间,并检查是否达到时间片的限制。如果是,则将任务状态设置为就绪,并将运行时间重置为 0。在第二个循环中,我们检查所有就绪的任务,并将它们的状态设置为运行,然后运行它们。 当然,实际的时间轮询例程可能会更加复杂,需要考虑任务的优先级、阻塞和唤醒等情况,但是以上的伪代码可以作为一个基本的框架来理解时间轮询的原理。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值