基于STM32的C语言时间调度器设计求助(定时器/状态机)
基于定时器+状态机实现时间调度器的解决方案
核心思路
利用你已完成的TIM2 1us计时基础(初始化代码将定时器分频为1MHz,每个tick对应1us),通过状态机跟踪当前调度阶段,配合动态修改定时器周期,实现4ms周期内的任务调度逻辑:
- 每4ms触发主请求
- 主请求后等待1ms周转延迟
- 在剩余3ms内,每500µs触发1次副请求,共6次
- 完成后回到主周期等待,循环执行
1. 定义状态机与全局跟踪变量
添加状态枚举和全局变量,用于记录当前调度阶段、副请求发送次数:
// 状态机枚举 typedef enum { STATE_MAIN_WAIT, // 等待4ms主周期触发 STATE_MAIN_DELAY, // 主请求后等待1ms延迟 STATE_SUB_REQUEST // 发送副请求阶段 } SchedulerState; SchedulerState current_state = STATE_MAIN_WAIT; uint8_t sub_request_count = 0; // 副请求计数器,最多6次
2. 修改定时器中断处理逻辑
重写TIM2_IRQHandler函数,根据当前状态执行任务并切换状态,动态调整定时器周期:
void TIM2_IRQHandler(void) { // 清除更新中断标志 __HAL_TIM_CLEAR_IT(&htim2, TIM_IT_UPDATE); switch(current_state) { case STATE_MAIN_WAIT: // 执行主请求任务 execute_main_request(); // 切换到1ms延迟状态,修改定时器周期为1000us current_state = STATE_MAIN_DELAY; changeTIM2Timeout(1000); break; case STATE_MAIN_DELAY: // 延迟结束,切换到副请求发送状态,设置周期为500us current_state = STATE_SUB_REQUEST; sub_request_count = 0; changeTIM2Timeout(500); break; case STATE_SUB_REQUEST: // 执行副请求任务 execute_sub_request(sub_request_count); sub_request_count++; if(sub_request_count >= 6) { // 6次副请求完成,回到主周期等待,设置周期为4000us current_state = STATE_MAIN_WAIT; changeTIM2Timeout(4000); } // 否则保持500us周期,继续下一次副请求 break; default: // 异常状态,重置为主等待 current_state = STATE_MAIN_WAIT; changeTIM2Timeout(4000); break; } }
3. 补充任务执行函数
根据实际需求实现主、副请求的具体逻辑:
void execute_main_request(void) { // 此处编写主请求的具体代码,比如发送指令、触发硬件动作等 } void execute_sub_request(uint8_t req_index) { // 此处编写副请求的具体代码,req_index可区分第几次副请求(0-5) }
4. 初始化与启动
调用初始化函数时,直接传入主周期的4000us(4ms):
// 启动调度器 TIM2_Init(4000);
关键说明
- 定时器周期修改:
changeTIM2Timeout直接操作ARR寄存器,因你已关闭AutoReloadPreload,修改后立即生效 - 状态流转:每个状态对应一个定时器周期,中断触发时完成任务并切换状态/周期,确保严格的时间间隔
- 副请求计数:通过
sub_request_count跟踪发送次数,达到6次后自动回到主周期
内容的提问来源于stack exchange,提问作者PierreP
相关产品推荐
相关产品推荐

