STM32 TIM1四通道同步脉冲输出

AI助手已提取文章相关产品:

基于STM32F103 TIM1的四通道同步单脉冲输出实现:从ETR触发到多路精确控制

在工业自动化、精密测量和实时控制系统中,常常需要在某个外部事件发生后,立即驱动多个执行器以严格同步的方式动作——比如激光打标机在接收到位置信号后同时触发光路与振镜,或超声探头在启动瞬间激励多阵元发射。这类场景对 响应延迟、时序一致性与硬件可靠性 提出了极高要求。

而普通的软件延时或中断调度方式,受限于CPU任务调度不确定性,往往难以满足微秒级甚至纳秒级的时间对齐需求。这时候,利用STM32高级定时器(如TIM1)的 外部触发+单脉冲模式+多通道同步输出 机制,就成了一种极具工程价值的技术路径。

本文聚焦于 STM32F103 系列芯片中的 TIM1 定时器 ,深入探讨如何通过其 ETR 引脚接收外部硬触发信号,并在此基础上配置四路 PWM 输出通道,在一次触发下生成宽度各异但时间完全对齐的单次脉冲。整个过程无需 CPU 干预,由硬件自动完成,极大提升了系统的实时性与稳定性。


我们先来看一个典型问题:假设你正在设计一台多通道电磁阀控制系统,要求当传感器检测到目标到达时,四个气缸必须在 同一时刻启动 ,各自保持不同开启时间(例如 5ms、8ms、3ms、6ms),且不能有任何相位偏移。如果用传统方法:

  • 使用 GPIO + HAL_Delay()?显然不行——函数调用开销、中断抢占都会引入不可控抖动。
  • 用普通定时器中断逐个翻转 IO?依然存在中断延迟和服务顺序的影响。
  • 改用 DMA 或者 RTOS 任务?复杂度陡增,且仍无法保证绝对同步。

真正理想的方案是: 所有输出基于同一个计数器,在相同的起点开始变化,仅靠各自的比较寄存器决定翻转时机 。这正是 STM32 高级定时器 TIM1 所擅长的领域。


TIM1 作为 STM32F103 上唯一的“高级控制定时器”,不仅具备标准定时功能,还集成了丰富的输入/输出控制逻辑,支持互补输出、死区插入、刹车保护以及多种从模式(Slave Mode)。其中, ETR(External Trigger Input)引脚 就是一个关键入口,它允许我们将外部物理事件直接接入定时器内部状态机,从而实现真正的“硬件触发”。

以 LQFP48 封装为例,TIM1 的 ETR 通常映射到 PA12 引脚(可通过重定义更改),该引脚输入的信号可以经过预分频器和数字滤波器处理后,用于启动、复位或同步定时器操作。这意味着你可以将一个按钮按下、编码器到位信号或者来自 FPGA 的同步脉冲,直接作为 TIM1 的“启动开关”。

更进一步地,当你把 TIM1 设置为 One Pulse Mode(单脉冲模式) 时,整个定时器的行为就会变成这样:

“我等待一个触发信号。一旦收到,我就开始计数;当我数到 CCRx 时,对应的通道翻转;当我数到 ARR 时,停止计数并关闭自己。全程不打扰 CPU。”

这个行为非常适合只需要执行一次的动作序列控制。更重要的是,由于 CH1~CH4 共享同一个计数器 CNT,它们之间的相对时序完全由各自的 CCR 值决定,不存在任何软件调度偏差。

举个例子:
- 设系统主频 72MHz,TIM1 时钟经 PSC 分频后为 1MHz(即每 tick = 1μs)
- ARR = 10000 → 总周期 10ms
- 各通道设置如下:
- CH1: CCR1 = 2000 → 在 2ms 处上升沿触发(若初始为低,则输出高电平持续 8ms)
- CH2: CCR2 = 5000 → 输出高电平持续 5ms
- CH3: CCR3 = 1000 → 持续 9ms
- CH4: CCR4 = 7000 → 持续 3ms

于是,在外部触发到来后的第 2ms、5ms、1ms 和 7ms,四个通道依次翻转,形成一组具有独立宽度但共享起始基准的脉冲群。这种精度,只有硬件定时才能做到。


要实现这一机制,核心在于正确配置三个部分: ETR 输入参数、单脉冲工作模式、多通道输出极性与空闲状态

首先是 ETR 的初始化。虽然 HAL 库没有专门针对 ETR 的独立 API,但我们可以通过 TIM_MasterConfigTypeDef 结构体进行设置。关键是要启用滤波功能以防止噪声误触发。例如:

TIM_MasterConfigTypeDef sMasterConfig = {0};

// 配置ETR:不分频,使用内部时钟作为采样源,滤波深度为15个周期
sMasterConfig.MasterEtrPrescaler = TIM_ETRPRESCALER_DIV1;
sMasterConfig.MasterEtrFilter = 0x0F;  // f_DTS/32, N=8 连续相同才认定有效
sMasterConfig.MasterTriggerSource = TIM_TS_ETRF;  // 选择ETR为触发源
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;

if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK) {
    Error_Handler();
}

这里的 MasterEtrFilter 是关键。设为 0x0F 表示使用定时器内部时钟(CK_INT)进行采样,连续 8 次检测到相同电平才认为信号有效,能有效抑制按键抖动或长线传输带来的毛刺。

接下来是单脉冲模式的主体配置。我们需要明确几点:

  • 计数方向:一般选择向上计数(TIM_COUNTERMODE_UP)
  • 自动重载值(ARR):决定最大脉冲周期
  • 预分频器(PSC):调节计数分辨率
  • 是否启用预加载(ARPE):强烈建议开启,避免运行中修改 ARR 导致异常

代码如下:

htim1.Instance = TIM1;
htim1.Init.Prescaler = 71;                    // 72MHz / (71+1) = 1MHz → 1μs/tick
htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
htim1.Init.Period = 9999;                     // 10ms 周期
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim1.Init.RepetitionCounter = 0;
htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;

if (HAL_TIM_OnePulse_Init(&htim1, TIM_OPMODE_SINGLE) != HAL_OK) {
    Error_Handler();
}

注意这里调用的是 HAL_TIM_OnePulse_Init() ,而不是普通的 HAL_TIM_Base_Init() 。虽然底层仍是通用定时器模块,但这个函数会自动配置从模式控制器为“触发启动并单次运行”的逻辑。

然后是对各个输出通道的配置。尽管名为“单脉冲模式”,但它本质上还是基于输出比较(OC)机制工作的。因此我们可以像配置 PWM 一样设置每个通道的极性、空闲状态和比较值。

TIM_OC_InitTypeDef sConfigOC = {0};

sConfigOC.OCMode = TIM_OCMODE_ACTIVE;         // 计数到CCR时置位输出
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH; // 互补通道也高有效
sConfigOC.OCIdleState = TIM_OUTPUTCOMPARE_IDLESTATE_RESET;
sConfigOC.OCNIdleState = TIM_OUTPUTCOMPARE_IDLESTATE_RESET;

// 配置CH1:2ms后翻转
sConfigOC.Pulse = 1999;
HAL_TIM_OnePulse_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1);

// 配置CH2:5ms后翻转
sConfigOC.Pulse = 4999;
HAL_TIM_OnePulse_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_2);

// 配置CH3:1ms后翻转
sConfigOC.Pulse = 999;
HAL_TIM_OnePulse_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_3);

// 配置CH4:7ms后翻转
sConfigOC.Pulse = 6999;
HAL_TIM_OnePulse_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_4);

需要注意的是, HAL_TIM_OnePulse_ConfigChannel() 实际上只是封装了输出通道的基本 OC 配置,并不会自动激活所有通道。你必须显式地为每个需要参与输出的通道调用一次该函数。

此外,关于输出极性的设定也很重要。如果你希望在触发后某通道立即输出高电平并在 CCR 到达时变为低电平,可以选择 TIM_OCMODE_INACTIVE ;反之则选 TIM_OCMODE_ACTIVE 。也可以结合 OCIDLESTATE 控制未触发前的默认电平,确保设备处于安全状态。


实际应用中,有几个细节容易被忽视,却直接影响系统稳定性和可重复性。

首先是 触发边沿的选择 。默认情况下,ETR 使用上升沿触发。如果你的外部信号是下降沿有效,可以通过以下方式反转:

__HAL_TIM_ENABLE(&htim1);  // 必须先使能定时器
__HAL_TIM_SET_TRIGGERPOLARITY(&htim1, TIM_TRIGGERPOLARITY_INVERTED);

注意:此宏操作的是 SMCR 寄存器中的 ETP 位,必须在定时器使能前设置,否则可能无效。

其次是 多次触发防护 。单脉冲模式执行完毕后,定时器并不会自动回到待机状态。如果你想让它再次响应后续触发,必须手动重启:

// 在主循环中检查是否已完成
if (__HAL_TIM_GET_FLAG(&htim1, TIM_FLAG_UPDATE) && __HAL_TIM_GET_IT_SOURCE(&htim1, TIM_IT_UPDATE)) {
    __HAL_TIM_CLEAR_IT(&htim1, TIM_IT_UPDATE);

    // 可选择重新启动
    HAL_TIM_OnePulse_Start(&htim1, TIM_CHANNEL_1);
}

或者使用回调机制(需开启中断):

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
    if (htim == &htim1) {
        // 脉冲结束,可执行清理或重启逻辑
        HAL_TIM_OnePulse_Stop(&htim1, TIM_CHANNEL_ALL);
        // 或重新配置并启动
    }
}

最后是 PCB 设计层面的建议:
- ETR 输入走线应尽可能短,远离高频干扰源(如开关电源、晶振)
- 若信号来自远端,建议增加施密特触发缓冲器(如 74HC14)进行整形
- 添加 10kΩ 上拉或下拉电阻,防止悬空导致误触发
- 对于高速或噪声环境,可考虑使用光耦隔离


这套方案的价值不仅仅体现在“能干活”,更在于它的 确定性与低负载特性 。一旦配置完成,无论主程序在忙什么——处理通信、跑算法、刷屏幕——只要外部触发到来,四路脉冲就能准时启动,不受任何影响。这对于医疗设备、测试仪器、机器人关节控制等高可靠性场景尤为重要。

而且,这种架构具备良好的扩展性。比如你可以将 TIM1 的更新事件(UEV)输出为 TRGO 信号,去级联其他定时器(如 TIM2~TIM8),实现跨定时器的多级同步动作;或者结合 DMA,在脉冲生成的同时自动采集 ADC 数据,构建完整的“激励-响应”闭环系统。


归根结底,STM32 的强大之处并不只是主频有多高、RAM 有多大,而是它提供了一套完整的 外设协同机制 。TIM1 的 ETR + 单脉冲 + 多通道输出组合,正是这种设计理念的缩影:把复杂的时序逻辑交给硬件,让 CPU 回归到更高层次的任务管理上去。

当你下次面对“多路同步输出 + 外部事件驱动”的需求时,不妨放下 delay 和 interrupt 的惯性思维,试试这条更高效、更可靠的硬件路径。

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

您可能感兴趣的与本文相关内容

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值