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

STM8S003F3P的Timer1卡顿/停滞问题求助

STM8S003 Timer1计数停滞问题排查与解决

你的定时器出现随机停滞的核心原因是未启动计数器,同时还有变量声明错误、中断内串口阻塞等潜在问题,下面逐一解决:

1. 最关键:定时器未启动

你只配置了TIM1的分频、自动重载值和中断,但没开启计数器。STM8定时器必须通过CR1寄存器的CEN位启动计数,否则定时器根本不会运行,所谓的“停滞”其实是定时器没工作,偶尔的恢复可能是误触发导致的巧合。

修改TIM1_config函数,最后加上启动代码:

TIM1->CR1 |= 0x01;  // 开启TIM1计数器
// 或者用库函数更直观:TIM1_Cmd(ENABLE);

2. 变量声明/定义错误

stm8s_it.c里的extern volatile uint16_t remain_sec = 0;是错误的:

  • extern是用来声明外部变量,不能同时初始化(初始化属于定义操作)
  • 你的需求是从60开始递减,初始值应该设为60

正确写法:

  • 在main.c里定义变量:
volatile uint16_t remain_sec = 60;
  • 在stm8s_it.c里声明变量:
extern volatile uint16_t remain_sec;

3. 中断内串口打印的致命问题

中断服务函数(ISR)里调用Serial_print_xxx是大忌:

  • 串口发送基本都是阻塞式的,尤其是低波特率下,打印一次的时间可能远超1秒,直接导致定时器中断无法及时响应,表现为计数停滞。
  • 长时间占用中断会打乱整个系统的中断调度,引发各种异常。

解决办法:

  • 把串口打印移到主循环里,因为remain_sec是volatile修饰的,主循环可以安全读取。
  • 如果必须在中断里输出,改用非阻塞式串口(比如基于环形缓冲区+DMA)。

4. 时钟配置的小优化

你的时钟配置逻辑没问题,但用库函数设置系统分频更可靠,避免直接操作寄存器的潜在问题:

void Clock_config(){
    CLK_DeInit();
    CLK_HSICmd(ENABLE);
    while (CLK_GetFlagStatus(CLK_FLAG_HSIRDY) == RESET);
    CLK_SYSCLKConfig(CLK_PRESCALER_HSIDIV1); // 替换原来的HSIPrescalerConfig
}

修正后的核心代码片段

main.c

#include "stm8s.h"

volatile uint16_t remain_sec = 60;

void main(){
    _asm("sim\n");
    Clock_config();
    TIM1_config();
    ITC_SetSoftwarePriority(ITC_IRQ_TIM1_OVF, ITC_PRIORITYLEVEL_2);
    _asm("rim\n");

    while (1){
        // 主循环打印,避免中断阻塞
        Serial_print_string("sec=");
        Serial_print_int(remain_sec);
        Serial_print_string("\n");
        // 加个延时,别打印太频繁
        for(uint16_t i=0; i<0xFFFF; i++);
    } 
}

void Clock_config(){
    CLK_DeInit();
    CLK_HSICmd(ENABLE);
    while (CLK_GetFlagStatus(CLK_FLAG_HSIRDY) == RESET);
    CLK_SYSCLKConfig(CLK_PRESCALER_HSIDIV1);
}

void TIM1_config(){
    TIM1_DeInit();

    // 16MHz / (15999+1) = 1kHz
    TIM1->PSCRH = 0x3E;
    TIM1->PSCRL = 0x7F;

    // ARR=999,1秒溢出一次
    TIM1->ARRH = 0x03;
    TIM1->ARRL = 0xE7;

    TIM1->IER |= 0x01;  // 使能更新中断
    TIM1->CR1 |= 0x01;  // 启动计数器
}

stm8s_it.c

#include "stm8s.h"

extern volatile uint16_t remain_sec;

INTERRUPT_HANDLER(TIM1_UPD_OVF_TRG_BRK_IRQHandler, 11){
  TIM1->SR1 &= (uint8_t)(~0x01);  // 清除UIF标志

  if(remain_sec > 1){
    --remain_sec;
  }
}

内容的提问来源于stack exchange,提问作者thanh cong

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 13:53:12