打印
[技术问答]

单片机开发之裸机也能 “多任务”?

[复制链接]
5574|51
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
wengh2016|  楼主 | 2023-8-27 19:23 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
单片机开发之裸机也能 “多任务”?
1. 背景
​ 对于一些简单的单片机项目,没必要非得跑RTOS,因此,很多项目都是在“裸奔”(指纯循环加上中断的机制)。所以,开发出一套好用的裸机框架是非常有必要的,本文章带你手把手实现裸机中的“多任务”调度。

2. 基本知识
​ 需要掌握的基本知识并不多,也都是最基本的知识,总结如下

定时器
函数指针
结构体数组
3. 代码实现
​ 整个系统的代码由 定时器中断发动,定时器就像是一个发动机,每隔一定的周期发动一次中断,利用这一个中断的时间去对指定任务的时间片减1,在主循环中一直遍历系统中所有任务的时间片,如果时间片耗尽了,则执行该任务。

​ 首先创建一个任务对象,经过上述分析,首先该任务对象至少有个时间片来决定该任务到底多久执行一次,其次该任务对象得有个任务,这个任务就是一个函数,比如创建一个LED灯的任务,每隔1秒钟执行一次。相关代码如下,该机制完全可以通过一个链表给链起来,可以有,但没必要,裸机代码简单易懂是关键。

typedef struct _task
{
        void          (*task)(void);
        uint32_t      tasktick;
}task_t;

​ 通过task_t这个结构体去实例化一个对象,如下:

task_t led_task;//实例化出led_task对象
led_task.tasktick = 1000;
led_task.task = xxxx_func();

​ 这样就将一个led任务的对象给创建出来了,但是系统中不可能仅存在一个任务,因此使用一个结构体数组将全部任务集中到一起,如下:

task_t  task[] = {
        {led_task,500},
        {tim_capture_task,20},
        {muliti_button_task,5},
        {mpu6050_task,10},
        {mpu6050_display_task,100},
        {srf_05_task,30}
};

​ 这个Task 数组中集合了该系统中的所有任务,就只剩下每个时钟周期减去每个任务的tick即可。这里涉及到一个定时器的中断周期问题,但一般都是1ms一次中断

​ 直接将配置systick相关代码加到系统时钟初始化函数中即可,需要注意的是将定时器中断优先级调至系统最高,这样其他中断来临时,不会打断正在执行的定时器中断。

​ 接下来就就需要在SysTick_Handler(void)服务函数中递减每个任务的时间片了,代码如下:

void SysTick_Handler(void)
{
        uint8_t i;
        for(i = 0 ; i < MAX_TASK ; i ++) //MAX_TASK 系统中最大任务个数,可指定
        {
                if(task_timer[i]) //任务定时器
                        task_timer[i]--;
        }
}

​ 上述代码中的 task_timer需要经过 Task[] 这个结构体数组初始化,如下:

void task_init(void) // 系统任务初始化
{
        uint8_t i = 0;
        for(i = 0; i < sizeof(task)/sizeof(task[0]); i++)
            task_timer[i] = task[i].tasktick;
}

​ 经过以上简单的几步整个系统这时候就能够跑起来了,不过还需最后一步,也就是在 while(1) 中添加任务运行相关的代码,如下:

void  task_run(void)
{
        uint8_t i = 0;
        for(i = 0; i < sizeof(task)/sizeof(task[0]); i++)
    {
                if(task_timer[i] == 0)
                {
                    task_timer[i] = task[i].tasktick; //重新给当前任务定时器付上初值,这里还可以再给对象添加一个周期任务与单次任务,需要的自行添加即可。
                        (task[i].task)();//调用任务函数
                }
    }
}

整个框架的核心步骤就如上所述。整个 main函数中也是非常精简,可谓是看似精简,实则内部波涛汹涌。

int main(void)
{
    board_init();//硬件相关初始化与 task_init
    while (1)
    {
        task_run(); // 上述 task_run函数
    }
}

原文链接:https://blog.csdn.net/m0_56548489/article/details/124333366

使用特权

评论回复
沙发
七毛钱| | 2023-9-6 10:07 | 只看该作者
该机制完全可以通过一个链表给链起来

使用特权

评论回复
板凳
nomomy| | 2023-9-7 13:33 | 只看该作者
单片机开发中,即使不使用实时操作系统(RTOS),也可以实现多任务处理。通常这种多任务处理被称为“裸机多任务”。

使用特权

评论回复
地板
chenci2013| | 2023-9-7 13:51 | 只看该作者
当一个任务的时间片用完时,切换到下一个任务。这可以通过在定时器中断服务函数中判断任务状态和切换任务来实现。

使用特权

评论回复
5
timfordlare| | 2023-9-7 14:15 | 只看该作者
裸机系统通常使用多核处理器或多处理器系统,这些处理器可以同时执行多个任务。

使用特权

评论回复
6
51xlf| | 2023-9-7 14:34 | 只看该作者
裸机系统还可以使用硬件定时器来实现任务调度和时间片轮转。

使用特权

评论回复
7
timfordlare| | 2023-9-7 14:58 | 只看该作者
想要实现多任务处理,需要为单片机安装操作系统和应用程序。

使用特权

评论回复
8
mickit| | 2023-9-7 15:22 | 只看该作者
为每个任务分配一个时间片,即任务执行的时间段。可以使用定时器中断(如Systick)来控制时间片的分配。

使用特权

评论回复
9
jonas222| | 2023-9-7 15:52 | 只看该作者
虽然裸机多任务处理相对复杂,但对于一些简单的单片机项目来说,没有必要引入RTOS的复杂性。开发一个良好的裸机多任务框架可以帮助有效地管理多个任务,提高系统的效率。

使用特权

评论回复
10
pentruman| | 2023-9-7 16:09 | 只看该作者
裸机状态下单片机是不能实现多任务处理的。如果想实现多任务处理,需要为单片机安装操作系统和应用程序。

使用特权

评论回复
11
houjiakai| | 2023-9-7 16:18 | 只看该作者
操作系统可以提供多个任务的调度和资源管理功能,使得多个任务能够同时运行,而应用程序则可以利用操作系统提供的资源,实现更加复杂和高级别的功能。

使用特权

评论回复
12
10299823| | 2023-9-7 16:27 | 只看该作者
多任务调度一般采用轮询或基于中断的方式。轮询是指在主循环中轮流检查各个任务的状态并执行相应的任务代码,而基于中断则是通过中断事件触发不同的任务执行。

使用特权

评论回复
13
minzisc| | 2023-9-7 16:33 | 只看该作者
合理的任务设计和权衡,以及充分利用单片机的硬件资源,可以实现有效的多任务系统。

使用特权

评论回复
14
ingramward| | 2023-9-7 16:42 | 只看该作者
如果需要更复杂的多任务处理,涉及到任务优先级、线程同步、资源管理等问题,那么一般会选择使用操作系统来进行任务调度和管理。

使用特权

评论回复
15
sdlls| | 2023-9-17 23:04 | 只看该作者
在裸机系统中,多任务处理是通过硬件和软件的结合来实现的。

使用特权

评论回复
16
bestwell| | 2023-9-19 10:03 | 只看该作者
使用单片机的中断机制来处理多个任务。每个任务都有一个对应的中断服务函数,当某个事件发生时,中断服务函数会被触发执行。

使用特权

评论回复
17
mollylawrence| | 2023-9-19 10:11 | 只看该作者
可以利用这个中断,每次中断都对指定任务的时间片减1,然后在主循环中遍历所有任务,检查时间片是否耗尽。如果某个任务的时间片耗尽,就执行该任务。

使用特权

评论回复
18
51xlf| | 2023-9-19 10:27 | 只看该作者
虽然单片机资源有限,但通过合理的设计和编程技巧,可以实现简单的多任务调度。

使用特权

评论回复
19
jackcat| | 2023-9-19 10:48 | 只看该作者
在裸机开发中,多任务调度可以通过Systick定时器来实现。Systick定时器就像一个发动机,每隔一定的周期就会发动一次中断。

使用特权

评论回复
20
kkzz| | 2023-9-19 11:01 | 只看该作者
选择合适的调度算法来确定哪个任务应该执行。

使用特权

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

本版积分规则

17

主题

2652

帖子

1

粉丝