## 一、为什么需要时间片轮询? 在资源受限的STM32应用中,直接引入RTOS可能带来额外RAM/ROM开销与移植复杂度。而传统的顺序执行(super-loop)无法应对“多事件并发”需求——例如同时处理按键扫描、LED刷新、传感器读取和串口发送。时间片轮询(Time-Slice Polling)是一种基于周期调度的裸机方案,它利用`SysTick`定时器产生稳定时基,将任务划分为多个时间片,在主循环中按序执行。 ## 二、时间片轮询的原理与架构 ### 2.1 核心机制 - **时基**:配置`SysTick`每1ms产生一次中断,作为系统心跳。 - **任务表**:定义结构体数组,包含任务函数指针、任务周期(ms)、当前计数值、运行标志。 - **调度流程**:每次SysTick中断中,遍历任务表,将计数值减1;当计数值归零时,重置为周期值并置位运行标志。主循环检测标志,执行相应任务,执行后清除标志。 ### 2.2 STM32架构优势 STM32的`SysTick`是内核级定时器,不占用通用外设定时器,且中断响应快(优先级可配置)。利用其嵌套向量中断控制器(NVIC),可确保时基的精准性,同时主循环保持最低优先级,避免打断任务执行中的关键操作。 ## 三、实现步骤 ### 3.1 配置SysTick时基 使用标准库或HAL库初始化: ```c void SysTick_Init(uint32_t freq) { SysTick_Config(SystemCoreClock / freq); // 例如1kHz -> 1ms } ``` ### 3.2 定义任务控制块 ```c #define TASK_MAX 4 typedef struct { void (*func)(void); // 任务函数指针 uint16_t period; // 任务周期(ms) uint16_t counter; // 递减计数器 uint8_t runFlag; // 运行标志 } TaskCtrl_t; TaskCtrl_t taskTable[TASK_MAX]; ``` ### 3.3 SysTick中断处理 ```c void SysTick_Handler(void) { for (int i = 0; i < TASK_MAX; i++) { if (taskTable[i].counter > 0) { taskTable[i].counter--; if (taskTable[i].counter == 0) { taskTable[i].counter = taskTable[i].period; taskTable[i].runFlag = 1; } } } } ``` ### 3.4 任务注册与主循环 ```c void Task_Init(void) { taskTable[0].func = Task_KeyScan; taskTable[0].period = 5; // 5ms taskTable[0].counter = 5; taskTable[1].func = Task_LedRefresh; taskTable[1].period = 20; // 20ms taskTable[1].counter = 20; taskTable[2].func = Task_SensorRead; taskTable[2].period = 100; // 100ms taskTable[2].counter = 100; } int main(void) { SysTick_Init(1000); // 1ms时基 Task_Init(); while (1) { for (int i = 0; i < TASK_MAX; i++) { if (taskTable[i].runFlag) { taskTable[i].runFlag = 0; taskTable[i].func(); } } } } ``` ### 3.5 任务函数定义 ```c void Task_LedRefresh(void) { static uint8_t toggle = 0; toggle = !toggle; HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, toggle); } void Task_KeyScan(void) { // 按键扫描逻辑 } ``` ## 四、注意事项 - **中断处理时间**:SysTick中断中的循环尽量简短,仅做计数与标志操作,避免实时性受损。 - **任务执行时长**:任务应保证在时间片内完成,尤其是高优先级任务。若任务耗时超过周期,会占用后续任务执行时机,导致调度偏移。 - **任务间数据共享**:当任务与中断函数(如串口接收)共享变量时,使用`volatile`修饰,并在必要时进入临界区(如关闭中断)保护。 - **优先级平衡**:周期短的任务排在任务表前面,以便更快获得CPU。但需注意,轮询模式下所有任务平等,没有抢占,所以长任务不应阻塞。 - **动态周期调整**:可根据运行模式修改`period`字段,但需在非中断状态下更新,避免竞态条件。 ## 五、总结 时间片轮询是一种优雅的裸机调度方案,它利用了STM32内核的SysTick硬件,以极少的资源占用实现多任务并发。尤其适用于设备控制、简单数据采集等场景。相比RTOS,它没有信号量、消息队列等同步机制,但通过合理的任务划分和周期设计,足以胜任大多数中低复杂度产品。理解其架构,也为后续迁移到RTOS打下基础。