You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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
    }
}

问题分析与解决方案

核心问题点

  1. incrementer被中断频繁覆盖:主循环里把incrementer设为0,但SysTick中断(100ms触发一次)里的LED_PWM()会立刻把它改回1,导致主循环的设置几乎不会生效,看起来主循环像“卡住”。
  2. duty_cycle未初始化:全局变量duty_cycle没有初始值,启动后是随机值,可能导致PWM输出异常,间接影响主循环逻辑的观测。
  3. SysTick配置的潜在问题:若Interrupt_Init()里屏蔽了SysTick中断,或中断优先级设置过高,会导致主循环被频繁抢占,无法正常执行。

修复步骤

  1. 调整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;
            }
        }
    }
    
  2. 初始化duty_cycle:给全局变量设置初始值,避免随机值影响逻辑:

    volatile uint32_t duty_cycle = MIN_DUTY; // 初始化为最小占空比
    
  3. 调整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){
              // 这里可以保留其他主循环逻辑
          }
         }
    }
    
  4. 精简中断服务函数:中断内操作尽量简短,避免长时间占用CPU。比如可以把非紧急逻辑移到主循环执行,只在中断里更新关键寄存器。

内容的提问来源于stack exchange,提问作者Petar Ristic

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 03:07:06