打印
[技术问答]

单片机简单的时间片轮询

[复制链接]
1575|37
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
modesty3jonah|  楼主 | 2024-9-27 15:30 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
时间片轮询调度
1.创建一个结构体链表

typedef struct taskMember
{
    pfuntion taskName;
    volatile uint32_t tick;
    uint32_t taskID;
    uint32_t taskStatus;
    struct taskMember *listNext;
}task_t;
2.声明一个链表头。

static task_t taskListHead;
task_t *currentTask = 0;
3.任务创建,每个任务都对应唯一id号码

uint32_t createTask(pfuntion taskName,uint32_t taskID)
{
    task_t *listHead = &taskListHead;
    task_t *temp = 0;
    uint32_t ret = 1;

    temp = (task_t *)malloc(sizeof(task_t));
    if(temp == 0)
    {
        free(temp);
        return 0;
    }

    temp->taskName = taskName;
    temp->taskStatus = 0;
    temp->taskID = taskID;
    temp->listNext = 0;
    while(listHead->listNext != 0)
    {
        listHead = listHead->listNext;
        if(listHead->taskID == taskID)
        {
            ret = 0;
            free(temp);
            break;
        }
    }
    if(ret == 1)
    {
        listHead->listNext = temp;
    }

    return ret;
}

4.任务调度,在中断定时器中调用,一般1ms一次

void taskScheduler(void)
{
    task_t *listHead = &taskListHead;

    while(listHead->listNext != 0)
    {
        listHead = listHead->listNext;
        if(listHead->tick > 0)
        {
            listHead->tick--;
        }   
    }
}
5.任务延时

void taskDelayMs(uint32_t tick)
{
    currentTask->tick = tick;
}
6.任务开始,在主循环调用

void taskRuning(void)
{
    task_t *listHead = taskListHead.listNext;

    while(1)
    {   
        if(listHead->tick == 0 && listHead->taskStatus == 0)
        {
            currentTask = listHead;
            listHead->taskName();
            if(listHead->tick < 1)
            {
                listHead->tick = 1;
            }
        }
        if(listHead->listNext != 0)
        {
            listHead = listHead->listNext;
        }
        else
        {
            listHead = taskListHead.listNext;
        }   
    }

}
7.任务挂起和恢复

void taskDelete(uint32_t taskID)
{
    task_t *listHead = &taskListHead;
    task_t *last = &taskListHead;

    while(listHead-> listNext != 0)
    {
        listHead = listHead->listNext;
        if(listHead->taskID == taskID)
        {
            last->listNext = listHead->listNext;
            free(listHead);
            break;
        }
        else
        {
            last = listHead;
        }   
    }
}


task_t * searchList(task_t * head,uint32_t taskID)
{
    task_t * temp = head;

    while(temp->listNext != 0)
    {
        temp = temp->listNext;
        if(temp->taskID == taskID)
        {
            break;
        }
    }
    return  currentTask;
}
//任务挂起
void taskPending(uint32_t taskID)
{
     task_t *temp = searchList(&taskListHead,taskID);
     if(temp != 0)
     {
         temp->taskStatus = 1;
     }   
}

//任务恢复
void taskResume(uint32_t taskID)
{
     task_t *temp = searchList( &taskListHead,taskID);
     if(temp != 0)
     {
         temp->taskStatus = 0;
         temp->tick = 0;
     }
}
这是一个简单的任务轮询调度,可以创建无数个,方便简单。

/****************************使用例子**********************/
void ledtask(void)//led间隔500ms翻转一次
{

使用特权

评论回复
沙发
药无尘| | 2024-9-28 14:53 | 只看该作者
简单的一个任务轮询

使用特权

评论回复
板凳
wangdezhi| | 2024-10-7 13:52 | 只看该作者

单片机中的时间片轮询是一种常见的多任务处理方法,它允许单片机在多个任务之间分配处理器时间,从而实现看似“并行”的操作。

使用特权

评论回复
地板
updownq| | 2024-10-7 20:15 | 只看该作者
单片机中的时间片轮询是一种简单的任务调度方法,它允许多个任务共享CPU资源,每个任务在一个固定的时间片内执行。

使用特权

评论回复
5
earlmax| | 2024-10-8 11:51 | 只看该作者
如果某个任务执行时间超过了其时间片,可能会导致其他任务的执行被推迟,影响整个系统的实时性。

使用特权

评论回复
6
i1mcu| | 2024-10-8 14:38 | 只看该作者
时间片轮询的调度方式相对固定,缺乏灵活性。它不能根据任务的优先级或者任务的紧急程度动态地调整任务的执行顺序,所有任务都按照预先设定的顺序和时间片进行执行。

使用特权

评论回复
7
nomomy| | 2024-10-8 16:14 | 只看该作者
这种方法适用于任务相对简单且实时性要求不是特别高的系统。

使用特权

评论回复
8
eefas| | 2024-10-8 17:54 | 只看该作者
#include <stdint.h>
#include <stdbool.h>

#define TASK_COUNT 3 // 定义任务数量
#define TIME_SLICE 100 // 定义每个任务的时间片长度(毫秒)

// 假设的任务函数
void Task1(void);
void Task2(void);
void Task3(void);

// 任务数组
void (*TaskArray[TASK_COUNT])(void) = {Task1, Task2, Task3};

// 任务索引
uint8_t taskIndex = 0;

// 无限循环
while (1) {
    // 获取当前任务
    void (*currentTask)(void) = TaskArray[taskIndex];
   
    // 执行当前任务
    currentTask();
   
    // 延时当前任务的时间片
    Delay(TIME_SLICE);
   
    // 更新任务索引
    taskIndex++;
   
    // 如果到达最后一个任务,重置索引
    if (taskIndex >= TASK_COUNT) {
        taskIndex = 0;
    }
}

// 延时函数,这里只是一个示例,实际实现依赖于单片机的定时器或软件延时
void Delay(uint16_t ms) {
    // 实现延时逻辑
}

使用特权

评论回复
9
jackcat| | 2024-10-8 20:56 | 只看该作者
在每个任务执行完毕后,更新任务的状态变量。例如,任务 1 在执行完一次闪烁 LED 灯的操作后,可以将task1_state设置为一个表示等待下一次执行的状态值,这样在下一个时间片轮到任务 1 时,可以根据状态变量决定是否再次执行任务。

使用特权

评论回复
10
jkl21| | 2024-10-9 09:51 | 只看该作者
使用单片机的定时器来产生周期性的中断。这个中断的频率应该足够高,以确保所有任务都能在给定的时间片内得到执行。定时器的中断服务程序(ISR)将作为任务调度的核心。

使用特权

评论回复
11
yeates333| | 2024-10-9 15:58 | 只看该作者
时间片轮询是一种在单片机编程中用于多任务处理的简单方法。它的基本思想是将 CPU 的运行时间划分成若干个时间片,每个任务按照顺序在自己的时间片内运行。当一个任务的时间片用完后,就轮到下一个任务运行,依次循环。这样可以在单个 CPU 上模拟多个任务同时运行的效果。

使用特权

评论回复
12
deliahouse887| | 2024-10-9 20:00 | 只看该作者
时间片轮询不是真正的多线程或多任务处理,因为它在同一时刻只执行一个任务。但是,通过合理地分配时间片,可以有效地模拟多任务处理,特别是在资源受限的单片机系统中。

使用特权

评论回复
13
mmbs| | 2024-10-11 10:10 | 只看该作者
这种方法的优点是简单易实现,但缺点是不灵活,因为所有任务的时间片都是固定的,无法根据任务的实际需求动态调整。

使用特权

评论回复
14
xiaoyaodz| | 2024-10-11 16:22 | 只看该作者
尽管时间片轮询在单片机上实现起来可能相对简单,但它仍然是一种有效的多任务处理方法,特别适用于那些对实时性要求不是特别高、但需要在单个硬件平台上运行多个任务的场景。

使用特权

评论回复
15
mickit| | 2024-10-11 21:45 | 只看该作者
通过优化代码结构和算法,减少任务切换时的上下文保存和恢复操作,提高系统效率。

使用特权

评论回复
16
micoccd| | 2024-10-12 16:43 | 只看该作者
这个方式挺好的

使用特权

评论回复
17
mnynt121| | 2024-10-14 13:50 | 只看该作者
当一个时间片结束时,保存当前任务的状态(如寄存器、堆栈指针等),然后加载下一个任务的状态并开始执行。

使用特权

评论回复
18
alvpeg| | 2024-10-14 23:05 | 只看该作者
定义了一个Task结构体,它包含了任务函数的指针、任务执行的间隔以及一个计时器。任务列表tasks包含了多个这样的任务结构体。在主循环中,我们遍历任务列表,检查每个任务的计时器是否达到了其指定的间隔。如果是,我们就执行任务并将计时器重置为0;如果不是,我们只是简单地增加计时器的值。

请注意,这个例子是一个简化的模型,实际应用中可能需要考虑更多的因素,比如任务的优先级、任务的挂起和恢复、更复杂的调度策略等。

使用特权

评论回复
19
alvpeg| | 2024-10-15 12:14 | 只看该作者
时间片长度:时间片不宜太长,以免影响系统的响应时间;也不宜太短,以免频繁切换任务导致效率下降。
任务同步:如果任务之间存在数据共享或依赖关系,需要实现适当的同步机制,如互斥锁。
中断延迟:确保中断服务例程执行时间短,避免长时间阻塞。

使用特权

评论回复
20
qiufengsd| | 2024-10-15 13:51 | 只看该作者
为每个任务编写相应的代码。这些代码应该被设计为能够在给定的时间片内完成其工作,并准备好在下一个时间片内再次被调用。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

29

主题

1489

帖子

2

粉丝