前言
在学习各种MCU的时候,都是用在main函数里写一个while(1){/* 执行代码 */},这种方式只能一个函数运行完以后再运行另一个函数。
假设需求控制多个模块,如显示屏幕信息的同时控制电机,还要一边接收按键输入。如果用上面的方式每个模块要排队等待CPU运行,就会显的很卡。
那有没有办法每个模块运行固定的时间,时间到了运行下一个模块,这样单个模块即使特别耗时,也不影响其他模块的运行,这个方法叫时间片轮转。
想到这个办法很容易,但要怎么编写代码呢?
A. 使用RTOS
根据不要重复造轮子的理论,能用现有的开源代码当然是最好的了。如类STM32常用的操作系统有uCOS, RT-thread(国产),FreeRTOS。
用现成的去官网等地方搜移植教程,本文不再详述。
用这些开源代码的问题是如果MCU RAM或ROM太小,删减起来就不太方便了,这时候手搓一个多任务并发系统的作用来了。
B.裸机多任务并发
时间片轮转的基本思路就是通过定时器(最好是硬件定时器)将CPU的运行时间切片成一个个时间片,代码里叫tick,然后一个任务每运行一个时间片,tick计数加1,当前任务运行的tick数已经达到分配给任务的tick数,就不再执行当前任务执行下一个任务。
先定义一个最任务结构体,至少包括任务主体函数,分配给任务的时间片tick数和当前运行已经消耗的时间片tick计数。用结构体就是为了方便扩展用的,还可以增加参数比如任务使能,任务偏移量等。这样就使任务执行更加灵活。
typedef void (*Func)(void);
typedef struct task_info_t
{
Func func; /* 任务主体函数 */
uint16_t task_tick; /* 分配给任务的时间片tick数 */
uint16_t tast_tick_cnt; /* 当前运行已经消耗的时间片tick计数 */
} TaskInfo_t;
初学者 typedef void (*Func)(void); 看不懂,这个是定义一种函数类型,这种函数类型是void (*)(void)型的,给他取个别名叫Func. 相当于下面这种写法:
不清楚的看这篇文章typedef void *(Func)(void)用法
typedef struct task_info_t
{
void (*func)(void); /* 任务主体函数 */
uint16_t task_tick; /* 分配给任务的时间片tick数 */
uint16_t tast_tick_cnt; /* 当前运行已经消耗的时间片tick计数 */
} TaskInfo_t;
定义好结构体后创建一个结构体数组,在数组里初始化任务的参数,结构体数组不清楚的看这里结构体数组
TaskInfo_t TaskInfoArray[] =

文章介绍了如何在不使用RTOS的情况下,利用STM32的硬件定时器实现裸机多任务并发,通过时间片轮转确保各个任务按预设时间间隔交替执行,以实现类似操作系统的效果。作者提供了任务结构体定义、任务数组初始化、定时器中断配置以及主循环中的任务切换逻辑。

3435

被折叠的 条评论
为什么被折叠?



