多个定时器同时使用的问题
在STM32F4中完全可以同时配置和使用多个定时器(如TIM2和TIM3)。
多定时器同时运行的基本原理
STM32F4系列包含多达17个定时器(包括基本定时器、通用定时器和高级定时器),它们可以:
- 独立配置不同的时钟频率
- 设置不同的计数模式
- 产生独立的中断
- 执行不同的功能(PWM、输入捕获等)
同时使用TIM2和TIM3的示例代码
以下是TIM2和TIM3同时配置为不同频率的示例:
定时器初始化
#include "stm32f4xx.h"
void TIM2_Init(void) {
// 1. 使能TIM2时钟
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
// 2. 配置预分频器和自动重装载值
TIM2->PSC = 8399; // 84MHz/(8399+1) = 10kHz
TIM2->ARR = 9999; // (9999+1)/10kHz = 1秒
// 3. 使能更新中断
TIM2->DIER |= TIM_DIER_UIE;
// 4. 配置NVIC
NVIC_EnableIRQ(TIM2_IRQn);
NVIC_SetPriority(TIM2_IRQn, 1);
// 5. 启动定时器
TIM2->CR1 |= TIM_CR1_CEN;
}
void TIM3_Init(void) {
// 1. 使能TIM3时钟
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
// 2. 配置预分频器和自动重装载值
TIM3->PSC = 839; // 84MHz/(839+1) = 100kHz
TIM3->ARR = 4999; // (4999+1)/100kHz = 50ms
// 3. 使能更新中断
TIM3->DIER |= TIM_DIER_UIE;
// 4. 配置NVIC
NVIC_EnableIRQ(TIM3_IRQn);
NVIC_SetPriority(TIM3_IRQn, 2);
// 5. 启动定时器
TIM3->CR1 |= TIM_CR1_CEN;
}
volatile uint32_t tim2_count = 0;
volatile uint32_t tim3_count = 0;
void TIM2_IRQHandler(void) {
if(TIM2->SR & TIM_SR_UIF) {
TIM2->SR &= ~TIM_SR_UIF; // 清除中断标志
tim2_count++; // 每秒增加1
// 执行TIM2相关任务...
}
}
void TIM3_IRQHandler(void) {
if(TIM3->SR & TIM_SR_UIF) {
TIM3->SR &= ~TIM_SR_UIF; // 清除中断标志
tim3_count++; // 每50ms增加1
// 执行TIM3相关任务...
}
}
- 多定时器使用的关键点
时钟配置
确保APB1/APB2总线时钟已正确配置
TIM2/TIM3位于APB1总线(最大频率84MHz)
中断优先级管理
// 设置TIM2优先级高于TIM3
NVIC_SetPriority(TIM2_IRQn, 1); // 更高优先级
NVIC_SetPriority(TIM3_IRQn, 2); // 较低优先级
资源分配
资源 TIM2 TIM3
中断向量 TIM2_IRQn TIM3_IRQn
时钟使能位 RCC_APB1ENR_TIM2EN RCC_APB1ENR_TIM3EN
DMA通道 可配置 可配置
- 高级应用示例:TIM2和TIM3协同工作
PWM输出 + 输入捕获组合
// TIM2配置为PWM输出
void TIM2_PWM_Init(void) {
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
TIM2->PSC = 0;
TIM2->ARR = 999; // 84MHz/1000 = 84kHz PWM频率
TIM2->CCR1 = 500; // 50%占空比
TIM2->CCMR1 |= TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2; // PWM模式1
TIM2->CCER |= TIM_CCER_CC1E; // 使能输出
TIM2->CR1 |= TIM_CR1_CEN;
}
// TIM3配置为输入捕获
void TIM3_IC_Init(void) {
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
TIM3->PSC = 83; // 84MHz/84 = 1MHz
TIM3->CCMR1 |= TIM_CCMR1_CC1S_0; // CC1通道输入
TIM3->CCER |= TIM_CCER_CC1E; // 捕获使能
TIM3->DIER |= TIM_DIER_CC1IE; // 捕获中断使能
NVIC_EnableIRQ(TIM3_IRQn);
TIM3->CR1 |= TIM_CR1_CEN;
}
- 实际应用注意事项
功耗考虑:
每个启用的定时器都会增加功耗
不使用时应当关闭定时器时钟
调试技巧:
// 检查定时器是否运行
if(TIM2->CR1 & TIM_CR1_CEN) {
// TIM2正在运行
}
性能优化:
对于高频定时器,考虑使用DMA减少中断频率
使用定时器级联功能处理超长定时
冲突避免:
确保不同定时器不使用相同的GPIO引脚复用功能
检查DMA通道是否冲突
结论:
STM32F4完全可以同时运行多个定时器(如TIM2和TIM3),只需注意:
- 正确配置各自的时钟和中断
- 合理设置中断优先级
- 确保资源(引脚、DMA等)不冲突
- 根据应用需求选择合适的定时器组合
如果只是配置和使用定时器(TIM)的基本计时功能,而不使用PWM
输出、输入捕获、输出比较等外设功能,确实不需要配置或使用任何GPIO口。
为什么不需要GPIO?
- 内部计数器:定时器的核心是一个自增/自减计数器,完全在内部运行
- 时钟源:使用内部时钟(APB总线提供),不依赖外部引脚
- 中断机制:通过NVIC(嵌套向量中断控制器)处理,不涉及物理引脚
- 寄存器访问:全部通过内部总线完成
//同时配置定时器2、定时器3,可同时使用的。
void TIM2_Int_Init(u16 arr,u16 psc)
{
RCC->APB1ENR|=1<<0; //TIM2时钟使能 00000001
TIM2->ARR=arr; //设定重装载值,刚好1ms 00C7
TIM2->PSC=psc; //设定预分频系数,溢出时间计算公式为:Tout=((arr+1)*(psc+1))/Tclk,单位us
TIM2->DIER|=1<<0; //允许更新中断 0001
TIM2->CR1|=0x01; //使能定时器3 0001
MY_NVIC_Init(1,3,TIM2_IRQn,2);//抢占优先级1,响应优先级3,组2
}
void TIM3_Int_Init(u16 arr,u16 psc)
{
RCC->APB1ENR|=1<<0; //TIM2时钟使能 00000001
TIM3->ARR=arr; //设定重装载值,刚好1ms 00C7
TIM3->PSC=psc; //设定预分频系数,溢出时间计算公式为:Tout=((arr+1)*(psc+1))/Tclk,单位us
TIM3->DIER|=1<<0; //允许更新中断 0001
TIM3->CR1|=0x01; //使能定时器3 0001
MY_NVIC_Init(1,3,TIM3_IRQn,2);//抢占优先级1,响应优先级3,组2
}
//在主函数中同时使用没问题的
TIM2_Int_Init(99,8399);
TIM3_Int_Init(99,8399);
同时使用定时器的定时与PWM输出等的问题
像PWM输出+定时中断,经尝试,没问题
//既配置了PWM输出也配置了定时器
void TIM3_PWM_Init(u16 arr,u16 psc)
{
RCC->APB1ENR|=1<<1; //TIM3时钟使能
RCC->AHB1ENR|=1<<1; //使能PORTB时钟
GPIOB->MODER&=0XFFFFFFFC; //PB0复用推挽输出,PB0口作PWM输出口
GPIOB->MODER|=0X00000002;
// GPIOB->OTYPER&=0xFFFFFC3F;
GPIOB->AFR[0]&=0xFFFFFFF0;//AF2复用
GPIOB->AFR[0]|=0x00000002;
TIM3->ARR=arr; //设定计数器自动重装值
TIM3->PSC=psc; //预分频器不分频
TIM3->CCMR2|=6<<4; //CH3 PWM1模式 PWM1模式下当TIMx_CNT<TIMx_CCRx时PWM信号参考OCxREF为高,否则为低。
// TIM3->CCMR1|=7<<4; //CH3 PWM2模式
TIM3->CCMR2|=1<<3; //CH3预装载使能
TIM3->CCER|=1<<8; //OC3 输出使能
TIM3->CR1=0x0080; //ARPE(自动重装载)使能
TIM3->DIER|=1<<0; //允许更新中断 0001
TIM3->CR1|=0x01; //使能定时器3
MY_NVIC_Init(1,3,TIM3_IRQn,2);//抢占优先级1,响应优先级3,组2
TIM3->CCR3= 0;
}
不推荐做法:
- 同一通道配置多个功能
- 高频PWM与精确定时混用同一定时器
- 在PWM应用中频繁修改ARR值影响定时精度