尚未崩坏 发表于 2024-9-22 19:07:32

浅谈架构方法之时间片轮询

PS:近来在逛CSDN的时间偶然发现了一篇文章讲到了这个架构,发现之前做过一个项目就用了这个东西,于是我搜了一下,感觉挺多文章都欠好理解,由于我也是近来才打仗到这个东西,所以我决定本身也写一篇,加深印象。
架构的类型

        起首,在嵌入式中有三种架构,除了我们熟知的裸机系统和操作系统,第三种就是这个时间片轮询。我认为这种架构是介于二者之间的过渡。
        裸机系统能够处理一些相对简朴的使命,但是功能单一,只会一直按顺序实行死循环里的使命,CPU只会全力做完一件事才会进行下一项使命,延时的时间也只会等候,浪费资源。
        操作系统的实时性和可靠性高还能同时实行多个使命,但是操作系统较为复杂,需要额外的学习成本,而且其对内存空间的要求需要我们注意内存的大小。
        而时间片轮询不光能够实现多使命,包管实时性,而且结构简朴,占用内存小,在实际开发中也节省时间和精力。
        对于简朴且实时性强的简朴使命可以利用时间片轮询,但是当使命数较多的时间还是诚实用操作系统更好。
代码实现

        这里我只叙述原理,不设定具体的使命,将整个代码拆分来看,防止看的太乱,整体代码放在最后。
        我设置了三个使命,分别是5ms使命、10ms使命和20ms使命。
        在开始之前,我们需要在主函数里进行一个延时。这个延时一样平常是最大的时间片时间,像这个例子里,我可以延时20ms。
        起首,我们定义一个最大使命数为3的宏:
#define TASKS_MAX   (3)          接下来定义一个结构体,其内成员含义如下:
                步伐运行标志位。
                倒计时时间。
                重装载倒计时。
                使命指针。
        它们的含义会在后面讲。
typedef struct _TASK_COMPONENTS
{
    uint8_t Run;            
    uint16_t Timer;            
    uint16_t ItvTime;              
    void (*TaskHook)(void);  
} TASK_COMPONENTS;          接下来我们创建一个结构体数组用来存放我们定义的结构体成员变量。
        数组中每个元素都对应着我们定义的结构体成员。
/* 任务数组 */
static TASK_COMPONENTS TaskComps[] = 
{
    {0, 5, 5, task_5ms},            // 5ms任务
    {0, 10, 10, task_10ms},         // 10ms任务
    {0, 20, 20, task_20ms},         // 20ms任务
};         接下来是重点了。
        这个函数需要放到系统定时器中断中实行,同时对所有使命进行计时。
        当有使命的值为0时,将其代入for()循环实行。
        当每个使命的Timer不为0时,进行减减操作,即倒计时。当其减到0的时间,将ItvTime的值赋给Timer,以方便下次计时。同时将步伐运行标志位Run置1.
/* 任务启动倒计时 */
void TaskRemarks(void)
{
    uint8_t i;

    for (i=0; i<TASKS_MAX; i++)          
    {
         if (TaskComps.Timer)        
        {
           TaskComps.Timer--;         
           if (TaskComps.Timer == 0)       
           {
             TaskComps.Timer = TaskComps.ItvTime; 
             TaskComps.Run = 1;           
           }
        }
   }
}         下面这个函数依然是从0开始遍历每个使命,判定它们的Run是否为1,假如是1则实行对应的使命,然后将标志位置0。
void TaskProcess(void)
{
    uint8_t i;

    for (i=0; i<TASKS_MAX; i++)           
    {
         if (TaskComps.Run)           
        {
             TaskComps.TaskHook();         
             TaskComps.Run = 0;          
        }
    }   
}          至于使命里面实现什么功能,就任由我们按实际需求了。
        当20ms使命实行过一次之后,一个周期就结束了。假如我们把TaskRemarks()放到SysTick的中断服务函数中,那么当这个中断实行的时间,滴答计时器的计数就会重置,同时TaskRemarks()函数也会重新实行,从而达到时间片轮询的效果。
完整代码

#define TASKS_MAX   (3)typedef struct _TASK_COMPONENTS
{
    uint8_t Run;            
    uint16_t Timer;            
    uint16_t ItvTime;              
    void (*TaskHook)(void);  
} TASK_COMPONENTS; /* 任务数组 */
static TASK_COMPONENTS TaskComps[] = 
{
    {0, 5, 5, task_5ms},            // 5ms任务
    {0, 10, 10, task_10ms},         // 10ms任务
    {0, 20, 20, task_20ms},         // 20ms任务
};/* 任务启动倒计时 */
void TaskRemarks(void)
{
    uint8_t i;

    for (i=0; i<TASKS_MAX; i++)          
    {
         if (TaskComps.Timer)        
        {
           TaskComps.Timer--;         
           if (TaskComps.Timer == 0)       
           {
             TaskComps.Timer = TaskComps.ItvTime; 
             TaskComps.Run = 1;           
           }
        }
   }
}void TaskProcess(void)
{
    uint8_t i;

    for (i=0; i<TASKS_MAX; i++)           
    {
         if (TaskComps.Run)           
        {
             TaskComps.TaskHook();         
             TaskComps.Run = 0;          
        }
    }   
}void task_5ms(void){ }void task_10ms(void){ }void task_20ms(void){ }

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 浅谈架构方法之时间片轮询