1. 差分编码器与4倍频技术解析
增量式编码器在电机控制、位置检测等领域应用广泛,但很多初学者对差分信号和4倍频技术的理解存在误区。今天我就结合自己多年的实战经验,用最直白的方式给大家讲明白这个技术。
编码器输出的信号通常有两种形式:一种是占空比50%的方波(A、B两相相位差90度),另一种是正弦波模拟信号。我们今天重点讨论方波信号,因为STM32的编码器接口就是为这种信号设计的。
所谓4倍频,就是把编码器的原始分辨率提高4倍。举个例子,如果你的编码器标称600PPR(每转600个脉冲),经过4倍频后实际可以获得2400个计数脉冲。这意味着最小分辨角度从原来的0.6度提升到了0.15度,精度大大提升。
实现原理其实很简单:普通计数只采集单个通道的上升沿,2倍频会同时采集上升沿和下降沿,而4倍频则同时采集两个通道的上升沿和下降沿。在实际项目中,我发现4倍频不仅能提高分辨率,还能有效抑制信号抖动,这点在高速电机控制中特别重要。
2. 硬件电路设计与连接
差分信号传输是工业现场的常见需求,但STM32的GPIO只能识别单端信号。这就需要用到差分接收芯片,我最常用的是TI的AM26C32,这款芯片稳定性很好,抗干扰能力强。
具体连接方式如下:将编码器的A+、A-接到AM26C32的1A和1B引脚,B+、B-接到2A和2B,Z相(零点信号)接到3A和3B。芯片的输出端1Y、2Y分别接到STM32定时器的CH1和CH2,3Y接到任意GPIO用作零点中断。
在实际布线时要注意几点:第一,差分信号线最好使用双绞线,长度不要超过1米;第二,在AM26C32的电源引脚附近记得加0.1uF的去耦电容;第三,如果环境干扰较强,可以在信号线上加RC滤波电路。我曾经在一个伺服项目中没有加滤波,结果电机高速运行时计数会出现跳变,后来加了22欧姆电阻和100pF电容就稳定了。
如果大家不想自己画板,可以直接用现成的差分转单端模块,比如RMLS-701模块就很不错,即插即用特别方便。
3. STM32编码器接口深度剖析
STM32的编码器功能其实是定时器的一个特殊工作模式,并不是所有定时器都支持。通常高级定时器TIM1、TIM8和通用定时器TIM2-TIM5才有这个功能。
理解编码器接口的关键在于看懂那个让人头疼的计数逻辑表。其实说白了就是根据两个通道的电平变化关系来判断方向和计数。TI1和TI2分别对应编码器的A相和B相,TI1FP1和TI2FP2是经过反相后的信号。
当配置为"仅在TI1计数"模式时,只在TI1的边沿计数,但同时会参考TI2的电平状态。如果TI1上升沿时TI2为低电平,则向上计数;TI1下降沿时TI2为高电平,也向上计数。这样就实现了2倍频。反过来如果旋转方向改变,就会向下计数。
4倍频模式(在TI1和TI2处均计数)则是同时检测两个通道的所有边沿。假设编码器正转:A相上升沿时B相为低电平(计数+1),B相上升沿时A相为高电平(计数+1),A相下降沿时B相为高电平(计数+1),B相下降沿时A相为低电平(计数+1)。这样一转就有4个计数脉冲。
我在多个项目实测中发现,STM32的编码器接口非常稳定,最高支持几十MHz的计数频率,完全满足大多数工业应用的需求。
4. CubeMX配置详解
使用STM32CubeMX配置编码器接口可以省去大量底层寄存器操作的时间。打开CubeMX后,选择对应的定时器(比如TIM3),在Mode中选择Encoder Mode。
关键参数配置如下:Encoder Mode选择"Encoder Mode TI1 and TI2",这就是4倍频模式。Polarity保持默认的"Rising Edge"即可。Counter Period(ARR寄存器)设置为65535(16位定时器的最大值),或者根据实际需要设置。
Prescaler(分频系数)设置为0,这样输入脉冲直接进入计数器。Filter值根据信号质量设置,如果信号干净就设为0,有抖动可以适当增加滤波值。我一般从3开始尝试,如果计数还有跳变就逐步增加。
记得开启定时器的中断(如果需要在计数溢出时处理),在NVIC Settings中使能定时器中断。生成代码时,建议选择"Generate peripheral initialization as a pair of '.c/.h' files per peripheral",这样代码结构更清晰。
配置完成后生成代码,CubeMX会自动帮我们生成定时器的初始化代码,包括GPIO配置、定时器模式设置等基础工作。
5. 编码器数据读取与处理
在生成的代码基础上,我们需要添加编码器的启动和数据读取逻辑。在main函数中,先启动编码器接口:
HAL_TIM_Encoder_Start(&htim3, TIM_CHANNEL_ALL);
读取计数值很简单,使用库函数即可:
int16_t count = __HAL_TIM_GET_COUNTER(&htim3);
但要注意的是,16位定时器的计数值范围是0-65535,超过这个范围就会溢出。处理溢出有两种方法:一种是开启溢出中断,在中断中记录溢出次数;另一种是使用32位变量组合成32位计数器。
我推荐第一种方法,因为更可靠。先开启溢出中断:
HAL_TIM_Base_Start_IT(&htim3);
然后在中断回调函数中处理溢出:
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM3)
{
if(__HAL_TIM_IS_TIM_COUNTING_DOWN(&htim3))
overflow_count--;
else
overflow_count++;
}
}
获取完整32位计数值:
int32_t full_count = (overflow_count * 65536) + __HAL_TIM_GET_COUNTER(&htim3);
方向判断也很重要,可以通过这个函数获取当前旋转方向:
uint8_t direction = __HAL_TIM_IS_TIM_COUNTING_DOWN(&htim3);
// 返回0表示正向,1表示反向
在实际应用中,我建议每10-100ms读取一次计数值,并通过差分计算得到速度值。不要读取太频繁,否则会增加CPU负担。
6. 实战应用与优化技巧
在电机控制项目中,编码器数据主要用于位置环和速度环的控制。位置控制直接使用计数值即可,而速度计算则需要通过差分和滤波处理。
速度计算的基本公式是:速度 = (本次计数 - 上次计数) / 时间间隔。但这样计算出来的速度会有较大噪声,需要加入滤波处理。我通常使用一阶低通滤波:
current_speed = (current_count - last_count) / delta_time;
filtered_speed = 0.9 * filtered_speed + 0.1 * current_speed;
滤波系数需要根据实际应用调整,响应速度要求高的场合用0.5-0.7,要求平滑的场合用0.1-0.3。
另一个常见问题是计数溢出处理。当电机长时间单向旋转时,计数值会不断溢出。我上面提到的32位计数器方法可以解决这个问题,但要注意溢出次数的符号处理。
对于零点信号(Z相),建议使用外部中断来处理。当检测到Z相上升沿时,可以将计数器重置为0,这样可以实现绝对位置校准。但要注意的是,重置计数器时要同时重置溢出计数,保持数据一致性。
在高速应用场合,我发现输入滤波器的设置很关键。滤波值太大会丢失脉冲,太小又无法有效抑制噪声。最好的办法是用示波器观察编码器波形,根据实际噪声情况设置滤波值。
最后提醒大家,编码器接线要使用屏蔽线,并且屏蔽层要单端接地,这样可以有效减少电磁干扰。电源质量也很重要,最好使用LDO为AM26C32供电,而不是简单的DCDC转换器。
7. 常见问题与解决方案
在实际项目中,我遇到过各种编码器相关的问题,这里分享几个典型的案例和解决方法。
第一个问题是计数不准,偶尔会跳变。这通常是信号质量问题,可以用示波器观察波形是否有毛刺。解决方法包括:增加硬件滤波(在AM26C32输入脚加RC滤波)、调整STM32输入滤波参数、检查接地是否良好。
第二个问题是高速时丢失脉冲。可能的原因有:输入滤波设置过大、代码读取过于频繁、中断处理时间过长。建议优化代码结构,将速度计算等耗时操作放在低速循环中,避免在中断中做复杂运算。
第三个问题是零点信号不准。Z相信号通常每转只有一个脉冲,如果位置对不齐会影响绝对位置精度。解决方法是在系统初始化时让电机转动寻找Z相,找到后将计数器重置为中间值(比如32768),这样正反转都有足够的计数空间。
第四个问题是电源噪声影响。电机驱动器的开关噪声会耦合到编码器信号中,导致计数错误。解决方法包括:使用隔离电源为编码器供电、信号线远离功率线、增加共模扼流圈等。
最后一个常见问题是机械安装误差。编码器与轴不同心会导致信号抖动,特别是在低速时影响更明显。安装时要确保同心度在允许范围内,联轴器要有足够的柔性补偿能力。
调试时我习惯先用逻辑分析仪捕获编码器波形,确认硬件没问题后再调试软件。STM32的调试模式也很好用,可以实时监控计数器值的变化情况。
377



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



