3. STM32定时器编码器模式:TIM编码器模式配置

编码器模式,说白了就是让定时器自己读懂正交信号。你不用写一行中断代码去判断A相和B相的先后顺序,硬件自动帮你把位置和方向算出来。我刚开始用这个功能时,总觉得它很神秘,后来拆开一看,其实就是个状态机加一个计数器。

3.1 TI1与TI2:编码器的两只眼睛

编码器接口通常有两路信号:TI1和TI2。在STM32里,它们分别对应定时器的通道1和通道2。你想想看,电机转一圈,这两路信号会输出固定数量的脉冲,而且相位差90度。

我个人习惯把TI1接编码器的A相,TI2接B相。但反过来接也行,只是计数方向会反过来。我在项目中遇到过接反的情况,电机正转时计数器反而往下减,排查了半天才发现是线序问题。

关键点:TI1和TI2的极性可以在寄存器里取反,所以硬件接反了也不用重新焊线,软件改个位就行。

3.2 计数方向与极性设置

编码器模式下,计数方向由TI1和TI2的相位关系决定。简单说:

  • TI1领先TI2 90度 → 向上计数(正转)
  • TI2领先TI1 90度 → 向下计数(反转)

但实际项目中,电机正转的定义可能和你的预期相反。这时候不用慌,TIM里有极性控制位:

寄存器位 功能 我常用的值
TIMx_CCER.CC1P TI1输入极性(0:不取反,1:取反) 0(除非线序反了)
TIMx_CCER.CC2P TI2输入极性(0:不取反,1:取反) 0
TIMx_SMCR.SMS 编码器模式选择(3种) 0x3(TI1和TI2都计数)

嗯,这里要注意:极性取反相当于把信号反相,效果等同于交换A、B相。所以如果你发现电机正转时计数器在减少,把CC1P或CC2P置1就能纠正过来。

我的小技巧:调试时先用手慢慢转动电机,观察计数器变化方向。如果方向反了,先改极性,别急着动硬件。

3.3 三种编码器模式怎么选?

STM32的编码器模式有三种,区别在于对TI1和TI2边沿的利用方式:

SMS[2:0] 模式名称 计数方式 每圈脉冲数
001 仅TI1计数 只在TI1的边沿计数 编码器线数 × 1
010 仅TI2计数 只在TI2的边沿计数 编码器线数 × 1
011 TI1和TI2都计数 两个信号的上升沿和下降沿都计数 编码器线数 × 4

我几乎只用模式3(SMS=011)。为什么?因为分辨率直接翻4倍。举个例子,一个1000线的编码器,模式1只能得到1000个脉冲/圈,模式3能得到4000个。你想想看,同样的硬件,精度提升4倍,何乐而不为?

注意:模式3下计数器更新频率是模式1的4倍。如果你的电机转速很高,要确保定时器的时钟频率足够快,否则会丢步。我曾经在3000rpm的电机上遇到过这个问题,后来把定时器预分频调小才解决。

3.4 滤波器配置:别让噪声骗了定时器

编码器信号在工业现场很容易被干扰。电机启动时的电磁噪声、长线传输的反射,都会在TI1/TI2上产生毛刺。这些毛刺一旦被定时器当成有效边沿,计数器就会多跳几下。

STM32的输入滤波器可以解决这个问题。它本质上是一个数字低通滤波器:

  • 采样时钟:通常是定时器时钟(TIMxCLK)或分频后的时钟
  • 滤波原理:连续采样N次,如果N次结果一致,才认为信号有效
  • 配置位:TIMx_CCMR1.IC1F[3:0](TI1滤波器)和IC2F[3:0](TI2滤波器)

滤波器的配置参数如下:

ICxF[3:0] 采样频率 需要连续采样次数 适用场景
0000 无滤波 1 信号干净,或低速测试
0011 fCK_INT / 8 6 一般工业环境
0111 fCK_INT / 32 8 强干扰环境
1111 fDTS / 32 8 极恶劣环境(但延迟大)

我个人习惯从ICxF=0011开始试。如果计数器在电机静止时还在跳,再加大滤波强度。但要注意,滤波越强,信号延迟越大。高速场合下,过强的滤波会导致你丢失真实的边沿。

避坑指南:我曾经在一个伺服项目里,把滤波器设到了1111,结果电机高速运行时计数器读数明显偏小。后来用示波器一看,滤波器把正常的窄脉冲也滤掉了。所以滤波不是越强越好,够用就行。

3.5 预分频器:控制计数器的更新频率

编码器模式下,预分频器(PSC)的作用和普通定时器不太一样。它不改变输入信号的采样频率,而是控制计数器溢出(更新事件)的频率。

说白了,预分频器决定了你的计数器多久「满一次」。如果你把自动重装载值(ARR)设得很大,预分频器设得很小,计数器可以计很多个数才溢出。反之,计数器很快就溢出了。

配置时我一般遵循这个原则:

  • 先确定电机一圈对应的最大脉冲数(编码器线数 × 4)
  • 把ARR设成略大于这个值,避免溢出
  • 预分频器设成0,让计数器以最快速度响应

举个例子:

// 假设编码器1000线,使用模式3(4倍频)
// 一圈最大脉冲数 = 1000 × 4 = 4000
// 设置ARR为3999(0~3999共4000个值)

TIM_HandleTypeDef htim3;
htim3.Instance = TIM3;
htim3.Init.Prescaler = 0;         // 预分频器设为0
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 3999;         // 自动重装载值
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
HAL_TIM_Encoder_Init(&htim3, &sConfig);

注意:如果电机可能多圈旋转,你需要用软件记录溢出次数。每次定时器溢出中断时,用一个变量累加。这样就能得到超过一圈的位置信息。

3.6 知识结构总览

下面这张图把编码器模式的配置流程串起来了。你可以把它当成调试时的检查清单:

TIM编码器模式配置流程 硬件连接:TI1→A相,TI2→B相 选择编码器模式:SMS=011(TI1+TI2双沿计数) 极性配置:CC1P/CC2P(默认0,方向反时置1) 滤波器配置:ICxF(从0011开始试) 预分频PSC=0,ARR=编码器线数×4-1 验证:手动转动,观察计数器方向与数值 提示:每步配置后都可用示波器观察TI1/TI2波形,确认信号质量

3.7 调试时的常见问题

配置完编码器模式后,如果发现计数器不工作或数值不对,别急着怀疑硬件。先检查这几步:

  1. 时钟开了吗?——TIMx的时钟在RCC里使能了没?我犯过这种低级错误。
  2. GPIO配置对吗?——TI1和TI2对应的引脚要配成复用功能(AF),而且是开漏或推挽输出?不对,是输入。嗯,这里容易搞混。
  3. 编码器模式使能了吗?——SMS位写进去了吗?用调试器读一下SMCR寄存器确认。
  4. 计数器在动吗?——用手转动电机,观察CNT寄存器的值。如果纹丝不动,八成是硬件或GPIO的问题。

我的调试口诀:时钟先开,GPIO配好,模式选对,极性调正,滤波适中,ARR够大。按这个顺序查,90%的问题都能解决。