Nucleo-F4中能否用int变量存储TIM->CNT跟踪时间实现LED调光+闪烁?
问题分析与解决方案
你当前的代码逻辑存在核心问题,导致LED无法按预期闪烁,以下是具体问题和修正方案:
现有代码的问题
- 计时逻辑错误:主循环中直接累加
TIM->CNT会重复计入同一个定时器周期内的计数值——主循环执行速度远快于定时器计数速度,比如定时器CNT刚走到100,主循环可能已经跑了几十次,total_CNT会被重复加几十次100,完全无法准确累计时间。 - 未处理定时器溢出:当定时器CNT从
ARR值重置回0时,你没有累计这个完整的8ms周期,导致total_CNT的计时完全偏离实际流逝时间。
正确实现思路
因为你需要同时实现高频PWM调光(8ms周期,人眼无感知)和500ms周期闪烁,推荐两种可靠方案:
方案一:复用现有定时器,通过溢出中断累计时间
利用定时器的更新(溢出)中断来准确统计8ms周期的次数,再通过周期次数计算500ms时间窗口,切换LED亮度:
// 假设使用TIM2,先配置时钟与基础参数 RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; TIM2->PSC = 99; // 16MHz/(99+1)=160kHz,计数步长6.25us TIM2->ARR = 1279; // 周期=1280*6.25us=8ms TIM2->CCMR1 |= TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2; // 配置PWM模式1 TIM2->CCER |= TIM_CCER_CC1E; // 使能通道1输出 TIM2->DIER |= TIM_DIER_UIE; // 开启更新中断 NVIC_EnableIRQ(TIM2_IRQn); // 使能定时器中断 TIM2->CR1 |= TIM_CR1_CEN; // 启动定时器 uint32_t cycle_counter = 0; uint8_t blink_state = 0; // 定时器中断服务函数 void TIM2_IRQHandler(void) { if (TIM2->SR & TIM_SR_UIF) { TIM2->SR &= ~TIM_SR_UIF; // 清除中断标志位 cycle_counter++; // 500ms = 62.5个8ms周期,取整为62个周期(496ms)作为切换阈值 if (cycle_counter >= 62) { cycle_counter = 0; blink_state = !blink_state; // 根据闪烁状态调整PWM占空比(示例值,可按需修改) if (blink_state) { TIM2->CCR1 = 960; // 75%占空比,高亮 } else { TIM2->CCR1 = 320; // 25%占空比,低亮 } } } } // 主循环无需额外计时逻辑,可处理其他任务 while (1) { // 其他业务代码 }
方案二:新增独立定时器负责闪烁计时
保留现有定时器用于PWM调光,再用另一个定时器配置为500ms周期中断,直接在中断中切换PWM占空比:
// 现有PWM定时器配置(保持不变) RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; TIM2->PSC = 99; TIM2->ARR = 1279; TIM2->CCMR1 |= TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2; TIM2->CCER |= TIM_CCER_CC1E; TIM2->CR1 |= TIM_CR1_CEN; // 新增TIM3负责500ms闪烁计时 RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; TIM3->PSC = 99; // 160kHz计数频率 TIM3->ARR = 79999; // 80000*6.25us=500ms TIM3->DIER |= TIM_DIER_UIE; NVIC_EnableIRQ(TIM3_IRQn); TIM3->CR1 |= TIM_CR1_CEN; uint8_t blink_state = 0; void TIM3_IRQHandler(void) { if (TIM3->SR & TIM_SR_UIF) { TIM3->SR &= ~TIM_SR_UIF; blink_state = !blink_state; if (blink_state) { TIM2->CCR1 = 960; } else { TIM2->CCR1 = 320; } } } while (1) { // 其他业务代码 }
关键说明
- 高频PWM(8ms周期)确保调光时无肉眼可见的闪烁,仅通过占空比调整亮度;
- 中断驱动的计时逻辑能保证500ms周期的准确性,不受主循环执行速度影响;
- 若需要更精准的500ms计时,可调整定时器参数:比如将闪烁定时器的
PSC=159(16MHz/160=100kHz)、ARR=49999,这样周期为500ms(50000*10us=500ms)。
内容的提问来源于stack exchange,提问作者Minatozaki Sana
相关产品推荐
相关产品推荐

