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
相关产品推荐
相关产品推荐

