封装版多任务调度
仍然是一种不使用 FreeRTOS 来实现简单的多任务调度的方式,使用 MSPM0G3507 作为示例。
首先请确保 SysTick 内的 Calculated Period 为 1ms,这样才能确保调度精确。当然也可以选择使用一个 1ms 定时器中断来代替 SysTick 中断。
嵌入式开发内的命名较乱,我目前除了 OLED_Init 这种操作外设的函数和 delay_ms 这种特殊的函数之外,主要还是用驼峰法 (camelCase) 进行命名。
SysTick 中断
在 delay.c 内编写延时函数,并通过 SysTick 中断来处理延时。
c
volatile uint32_t utick = 0;
// 1ms 执行一次
void SysTick_Handler(void) {
SysTick->CTRL &= ~(1 << 16); // 清除中断标志位
utick++;
}1
2
3
4
5
6
7
2
3
4
5
6
7
以上中断会使得 utick 每 1ms 自增一次,因此可用 utick 来表示系统时间。
经典 delay_ms 函数
TI 似乎没有内置的阻塞型延时,需要利用 SysTick 中断实现阻塞型延时,相当于 STM32 HAL 库中的 HAL_Delay。
c
void delay_ms(uint32_t ms) {
uint32_t now = utick;
while (utick < (now + ms)) {
}
}1
2
3
4
5
6
2
3
4
5
6
getTick 函数
定义一个 getTick 函数使得 utick 可被外部访问
c
void getTick(void) {
return utick;
}1
2
3
2
3
封装多任务调度
在 tasks.c 内封装多任务调度。首先在头文件中声明任务结构体:
c
typedef struct {
uint32_t interval; // 任务持续时间
uint32_t lastCall; // 上次执行时间
void (*task)(void); // 任务函数指针
} Task;1
2
3
4
5
2
3
4
5
定义任务数组,用于存放所有的定时任务
c
void task1(void) {
// do something
}
void task2(void) {
// do something
}
Task tasks[2] = {
{20, 0, task1},
{100, 0, task2}
};
int tasksLen = 2;1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
实现一个 iter 函数,该函数需在 main 函数中主动调用,以实现任务调度
c
void iter(void) {
for (int i = 0; i < tasksLen; i++) {
uint32_t now = getTick();
if (now - tasks[i].lastCall >= tasks[i].interval) {
tasks[i].task();
tasks[i].lastCall = now;
}
}
}1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
在 main 函数主循环中调用 iter 来实现任务调度
c
#include "ti_msp_dl_config.h"
int main(void) {
SYSCFG_DL_init();
while (1) {
iter();
// 其他主逻辑
}
}1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11