⚙️ 一、实现原理
-
重复计数器(RCR)的作用
- RCR 是高级定时器独有的寄存器,用于控制更新事件(Update Event, UEV) 的触发频率。
- 工作流程:
- 每次定时器溢出(上溢或下溢)时,RCR 值自动减 1。
- 当 RCR 递减至 0 后,下一次溢出时触发更新事件(UEV),并可能停止定时器。
-
脉冲数与 RCR 的关系
- 关键公式:输出脉冲数=N=TIM_RepetitionCounter+1
- 例如:设置
TIM_RepetitionCounter = 9→ 输出 10 个脉冲后停止。
- 例如:设置
- 原因:
- 定时器从初始值开始计数,每溢出一次产生一个完整脉冲。
- RCR 的递减从初始值 N−1 开始,需经过 N 次溢出才能归零并触发停止条件。
- 关键公式:输出脉冲数=N=TIM_RepetitionCounter+1
-
停止机制
- 若启用单脉冲模式(OPM),在 RCR 归零后的更新事件中,定时器自动停止计数并关闭输出。
🔧 二、配置步骤(标准库示例)
1. 基础定时器配置
TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;
TIM_TimeBaseStruct.TIM_Period = 999; // ARR值(决定PWM周期)
TIM_TimeBaseStruct.TIM_Prescaler = 71; // PSC值(72MHz→1MHz)
TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up; // 递增模式
TIM_TimeBaseStruct.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStruct.TIM_RepetitionCounter = N-1; // 输出N个脉冲
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStruct); // 初始化定时器
- 关键点:
TIM_Period和TIM_Prescaler决定单个脉冲的周期(频率)。
2. 启用单脉冲模式
TIM_SelectOnePulseMode(TIM1, TIM_OPMode_Single); // 单脉冲模式:输出完成后停止
- 作用:确保输出 N 个脉冲后定时器自动停止。
3. 配置PWM输出通道
TIM_OCInitTypeDef TIM_OCStruct;
TIM_OCStruct.TIM_OCMode = TIM_OCMode_PWM1; // PWM模式1
TIM_OCStruct.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCStruct.TIM_Pulse = 500; // 占空比50%(CCR=500)
TIM_OCStruct.TIM_OCPolarity = TIM_OCPolarity_Low;
TIM_OC2Init(TIM1, &TIM_OCStruct);
- 说明:占空比由
TIM_Pulse(CCR值)独立控制,与脉冲数无关。
4. 启动定时器
TIM_CtrlPWMOutputs(TIM1, ENABLE); // 高级定时器需使能主输出
TIM_Cmd(TIM1, ENABLE); // 启动定时器
5. 完整可用代码
// 引脚定义
#define PWM_PIN GPIO_Pin_9 // PA9(TIM1_CH21)
#define PWM_PORT GPIOA
// 定时器配置函数
void TIM1_OPM_Config(uint16_t pulse_count)
{
// 1. 使能时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
// 2. 配置PA8为复用推挽输出
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Pin = PWM_PIN;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(PWM_PORT, &GPIO_InitStruct);
// 3. 定时器时基配置
TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;
TIM_TimeBaseStruct.TIM_Period = 999; // ARR:PWM周期=1000个计数
TIM_TimeBaseStruct.TIM_Prescaler = 71; // PSC:72MHz/(71+1)=1MHz → 1us计数
TIM_TimeBaseStruct.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStruct.TIM_RepetitionCounter = pulse_count - 1; // 输出脉冲数=pulse_count
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStruct);
// 4. 配置单脉冲模式
TIM_SelectOnePulseMode(TIM1, TIM_OPMode_Single); // 单次脉冲后停止
// 5. PWM通道配置
TIM_OCInitTypeDef TIM_OCStruct;
TIM_OCStruct.TIM_OCMode = TIM_OCMode_PWM1; // PWM模式1
TIM_OCStruct.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCStruct.TIM_Pulse = 500; // 占空比50%(CCR=500)
TIM_OCStruct.TIM_OCPolarity = TIM_OCPolarity_Low;
TIM_OC2Init(TIM1, &TIM_OCStruct);
// 6. 使能主输出(高级定时器必需)
TIM_CtrlPWMOutputs(TIM1, ENABLE); //
// 7. 配置更新中断(可选)
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = TIM1_UP_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE);
// 8. 初始化时禁用定时器
TIM_Cmd(TIM1, DISABLE);
}
// 触发一次脉冲序列
void TIM1_TriggerPulse(void)
{
TIM_Cmd(TIM1, DISABLE); // 先停止定时器
TIM_SetCounter(TIM1, 0); // 计数器归零
TIM_GenerateEvent(TIM1, TIM_EventSource_Update); // 强制更新事件
TIM_Cmd(TIM1, ENABLE); // 启动定时器
}
// 中断服务函数
volatile uint8_t pulse_complete = 0;
void TIM1_UP_IRQHandler(void)
{
if (TIM_GetITStatus(TIM1, TIM_IT_Update))
{
TIM_ClearITPendingBit(TIM1, TIM_IT_Update);
pulse_complete = 1; // 标记脉冲完成
// 此处可添加脉冲结束后的处理代码
}
}
int main(void)
{
// 初始化系统时钟(根据实际晶振配置)
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_3);
Key_GPIO_Config();
// 配置输出10个脉冲
TIM1_OPM_Config(5);
while (1) {
// 示例:按键触发脉冲
if( Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN) == KEY_ON)
{
// pulse_complete = 0;
TIM1_TriggerPulse();
// 等待脉冲完成(可选)
// while(!pulse_complete);
}
}
}
⚡️ 三、工作流程
-
计数阶段
- 定时器从 0 开始递增,每达到
ARR值(周期结束)产生一个完整脉冲,同时 RCR 减 1。 - 示例(N=10):
- 第 1 个脉冲 → RCR 值从 9 减至 8
- 第 9 个脉冲 → RCR 值从 1 减至 0
- 第 10 个脉冲 → 溢出时触发更新事件(RCR=0)。
- 定时器从 0 开始递增,每达到
-
停止阶段
- 当 RCR 归零后的下一次溢出时:
- 触发更新事件(UEV)。
- 单脉冲模式生效,定时器停止计数,PWM 输出关闭。
- 当 RCR 归零后的下一次溢出时:
🔌 四、GPIO_Mode_AF_PP:复用推挽输出模式
作用与原理:
在用户代码中,引脚配置为GPIO_Mode_AF_PP(复用推挽输出)是为了将PA9(TIM1_CH2) 作为定时器的PWM输出引脚。以下是关键原因:
-
硬件自动控制
- 复用模式(Alternate Function)表示引脚由外设(如TIM1)直接控制电平,而非CPU软件控制。
- 推挽输出(Push-Pull)结构由P-MOS和N-MOS管组成,可主动输出高/低电平,驱动能力强(如驱动LED、电机驱动器)。
-
适用场景
- PWM输出:如定时器的PWM信号(TIM1_CH2),需硬件自动生成精确波形,无需CPU干预。
- 高速信号:推挽结构支持高电平切换速度(50MHz),适合PWM等时序敏感应用。
-
配置要点
- 复用功能映射:必须调用
GPIO_PinAFConfig()(用户代码未显式调用,但HAL库可能内部处理)。 - 速度配置:
GPIO_Speed_50MHz确保PWM边沿陡峭,减少信号失真。
- 复用功能映射:必须调用
✅ 为何不用普通推挽输出(GPIO_Mode_Out_PP)?
普通推挽需CPU写寄存器控制电平,而PWM要求硬件自动生成精确波形,CPU无法实时响应。
⚡ 五、TIM_GenerateEvent(TIM1, TIM_EventSource_Update):强制更新事件
作用与原理:
在TIM1_TriggerPulse()函数中,此操作通过软件触发更新事件(Update Event),实现寄存器值的立即生效:
-
更新事件的功能
- 将预装载寄存器(ARR、PSC、CCR)的值同步到影子寄存器(实际生效的寄存器)。
- 复位计数器(CNT)为0,并清除状态标志。
-
为何需要强制触发?
- 单脉冲模式要求:
- 用户配置了
TIM_SelectOnePulseMode(TIM1, TIM_OPMode_Single),表示定时器在输出指定脉冲数后自动停止。 - 每次启动新脉冲序列前,需复位计数器(CNT)并重载参数(如
TIM_RepetitionCounter = pulse_count - 1)。
- 用户配置了
- 避免首次脉冲异常:
若不强制更新,首次脉冲的周期可能使用旧参数(影子寄存器未更新)。
- 单脉冲模式要求:
⚠️ 六、注意事项
-
仅支持高级定时器
- RCR 功能仅限 TIM1/TIM8(STM32F1/F4系列),通用定时器需用中断或主从模式替代。
-
RCR 取值范围
- RCR 值通常为 0~255(具体取决于型号),超出范围可能导致行为异常。
-
与中断的配合
- 若需在脉冲结束后执行任务(如关闭外设),可启用更新中断:
TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE); // 使能更新中断- 中断中检测 RCR 状态并处理后续逻辑。
- 若需在脉冲结束后执行任务(如关闭外设),可启用更新中断:
-
频率与脉冲数的平衡
- 高频率 PWM 时,RCR 值不宜过大(避免计数器溢出)。
- 最大脉冲数 = (ARR+1)×(RCRmax+1),受限于定时器位数。
💎 总结
通过 TIM_RepetitionCounter = N-1 实现固定脉冲输出的核心是:
- 硬件自动递减:RCR 在每次溢出时减 1,零值触发更新事件。
- 单脉冲模式:更新事件中自动停止定时器,确保精确输出 N 个脉冲。
- 完全硬件控制:规避了软件中断的延迟误差,适用于步进电机驱动、精密脉冲发生器等高精度场景。
配置时需严格匹配单脉冲模式与 RCR 值,并验证目标定时器是否支持该功能。实测可通过示波器观察输出脉冲数量及占空比稳定性。
5911

被折叠的 条评论
为什么被折叠?



