STM32F401RE SysTick配置问题:主循环无法运行如何解决?
问题:SysTick中断导致主循环无法正常工作,如何配置实现两者同时运行?
问题描述
无法理解为何SysTick会导致主循环无法正常工作?应如何重新配置,以实现SysTick中断触发与主循环的同时运行?
相关代码
配置代码
#include "main.h" #include "functions.h" #include <stdbool.h> #include <stdlib.h> union InterruptFlag flag = { .bits_access.flag= 0, .bits_access.direction=0, .bits_access.debounce= 0, .bits_access.press = 0}; // Initialize to 0 void EXTI15_10_IRQHandler(void){ flag.bits_access.flag = !flag.bits_access.flag; // Set the flag to indicate button press event EXTI->PR |= (1<<13); // Clear PR to re-enable EXTI interrupt }; #define MAX_DUTY 500 #define MIN_DUTY 0 #define DEBOUNCE_DELAY 500 volatile uint32_t duty_cycle; volatile uint16_t incrementer = 1;
主函数及实现代码
int main(void){ TIM2_INIT(); TIM3_INIT(); Interrupt_Init(); SysTick->CTRL = SysTick->CTRL | (1 << 0) | (1 << 1) | (1 << 2); SysTick->LOAD = (84000 - 1); // 100 millisecond while (1) { //LED_PWM(); if(flag_check()==true){ incrementer=0; } } } void SysTick_Handler(void) { LED_PWM(); } bool flag_check(){ return flag.bits_access.flag; } void LED_PWM() { TIM2->CCR1 = duty_cycle; incrementer=1; if (duty_cycle >= MAX_DUTY) { flag.bits_access.direction = false; // Change direction to decrement } else if (duty_cycle <= MIN_DUTY) { flag.bits_access.direction = true; // Change direction to increment } if (flag.bits_access.direction) { duty_cycle += incrementer; // Increment } else { duty_cycle -= incrementer; // Decrement } }
问题分析与解决方案
核心问题点
incrementer被中断频繁覆盖:主循环里把incrementer设为0,但SysTick中断(100ms触发一次)里的LED_PWM()会立刻把它改回1,导致主循环的设置几乎不会生效,看起来主循环像“卡住”。duty_cycle未初始化:全局变量duty_cycle没有初始值,启动后是随机值,可能导致PWM输出异常,间接影响主循环逻辑的观测。- SysTick配置的潜在问题:若
Interrupt_Init()里屏蔽了SysTick中断,或中断优先级设置过高,会导致主循环被频繁抢占,无法正常执行。
修复步骤
调整
incrementer控制逻辑:取消中断里强制设置incrementer=1的操作,改用按键标志位直接控制增减逻辑,避免主循环操作被中断覆盖:// 修改EXTI中断函数 void EXTI15_10_IRQHandler(void){ flag.bits_access.flag = !flag.bits_access.flag; EXTI->PR |= (1<<13); // 新增消抖,避免短时间内重复触发 for(uint32_t i=0; i<10000; i++); }; // 修改LED_PWM函数 void LED_PWM() { TIM2->CCR1 = duty_cycle; // 仅在按键未触发时执行增减 if(!flag.bits_access.flag){ if (duty_cycle >= MAX_DUTY) { flag.bits_access.direction = false; } else if (duty_cycle <= MIN_DUTY) { flag.bits_access.direction = true; } if (flag.bits_access.direction) { duty_cycle += incrementer; } else { duty_cycle -= incrementer; } } }初始化
duty_cycle:给全局变量设置初始值,避免随机值影响逻辑:volatile uint32_t duty_cycle = MIN_DUTY; // 初始化为最小占空比调整SysTick中断优先级:降低SysTick中断优先级,确保主循环有足够执行时间:
int main(void){ TIM2_INIT(); TIM3_INIT(); Interrupt_Init(); // 设置SysTick优先级(数值越大优先级越低) NVIC_SetPriority(SysTick_IRQn, 3); // 规范SysTick配置顺序 SysTick->LOAD = (84000 - 1); SysTick->VAL = 0; // 清空当前计数值,避免触发异常中断 SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk; while (1) { if(flag_check()==true){ // 这里可以保留其他主循环逻辑 } } }精简中断服务函数:中断内操作尽量简短,避免长时间占用CPU。比如可以把非紧急逻辑移到主循环执行,只在中断里更新关键寄存器。
内容的提问来源于stack exchange,提问作者Petar Ristic
相关产品推荐
相关产品推荐

