3、编码器接口基础:增量式编码器原理、ABZ信号采集与解码
大家好,我是老李。做运动控制这些年,编码器接口这块我踩过的坑,比走过的路还多。今天咱们就聊聊增量式编码器,这东西看着简单,但真要在FPGA里把它玩明白,还是有不少门道的。
3.1 增量式编码器到底是个啥?
说白了,增量式编码器就是个“计数器”。它不告诉你绝对位置,只告诉你“动了多少”。你想想看,就像你跑步时用的计步器,它只记录你迈了多少步,至于你现在在跑道哪个位置,它不知道。
增量式编码器内部有个码盘,上面刻着密密麻麻的条纹。码盘转动时,光电传感器会检测这些条纹,产生脉冲信号。脉冲数越多,说明转过的角度越大。
核心参数:分辨率(PPR,Pulse Per Revolution)。比如一个1000 PPR的编码器,转一圈输出1000个脉冲。但注意,这通常是A相或B相的单端脉冲数。
我在项目中遇到过用2000 PPR的编码器做伺服电机反馈,结果发现分辨率不够,低速时抖动得厉害。后来换了5000 PPR的,问题就解决了。所以选型时,分辨率一定要留够余量。
3.2 ABZ信号,三兄弟各司其职
增量式编码器输出三路信号:A相、B相、Z相。这三兄弟各有分工:
- A相和B相:相位差90°的方波信号。通过判断谁先谁后,就能知道电机是正转还是反转。
- Z相:每转一圈输出一个脉冲,用于“归零”或“找参考点”。
我习惯把AB相想象成两个人走路。A先迈腿,B后迈腿,那就是正转。反过来B先迈腿,那就是反转。简单吧?
| 信号 | 功能 | 典型频率 |
|---|---|---|
| A相 | 主计数脉冲 | 最高可达几MHz |
| B相 | 方向判别脉冲 | 与A相同频 |
| Z相 | 零位参考脉冲 | 每圈1个 |
注意:Z相脉冲宽度通常很窄,只有几个微秒。如果FPGA采样频率不够,很容易漏掉。我曾经因为这个原因,导致设备每次上电找零位都不准,折腾了两天才发现是采样率的问题。
3.3 ABZ信号采集,FPGA的活儿
编码器信号进FPGA,第一件事就是“去毛刺”。工业现场干扰大,信号上经常有毛刺。我一般用三级寄存器打拍,再加一个边沿检测。
// 三级寄存器去抖
reg [2:0] a_sync;
always @(posedge clk) begin
a_sync <= {a_sync[1:0], A_raw};
end
// 边沿检测
wire a_rise = a_sync[2] & ~a_sync[1];
wire a_fall = ~a_sync[2] & a_sync[1];
嗯,这里要注意。三级打拍能滤掉大部分短毛刺,但如果干扰持续时间长,就得用更复杂的滤波算法了。我个人习惯在信号质量特别差的时候,加一个可编程的“窗口滤波器”,效果不错。
3.4 四倍频解码,榨干编码器性能
AB相有90°相位差,这意味着一个周期内可以检测到4个边沿(A上升、A下降、B上升、B下降)。每个边沿都计一次数,分辨率就提高了4倍。
比如一个1000 PPR的编码器,四倍频后就是4000个计数/圈。这就是所谓的“四倍频技术”。
小技巧:四倍频解码时,状态机是关键。我常用的方法是把AB相组合成4种状态(00, 01, 11, 10),然后根据状态跳转方向来判断正反转。这样代码简洁,还不容易出错。
// 四倍频状态机示例
reg [1:0] ab_state;
always @(posedge clk) begin
ab_state <= {B_sync, A_sync};
end
always @(posedge clk) begin
case (ab_state)
2'b00: if (A_sync) counter <= counter + 1; // 正转
2'b01: if (B_sync) counter <= counter - 1; // 反转
2'b11: if (!A_sync) counter <= counter + 1;
2'b10: if (!B_sync) counter <= counter - 1;
endcase
end
这段代码看着简单,但实际用的时候要注意。状态跳转必须完整覆盖所有可能路径,否则会丢步。我刚开始写的时候漏了一种情况,结果电机转一圈少计了十几个脉冲,查了好久才发现。
3.5 Z相信号处理,找零位的关键
Z相每圈一个脉冲,用来做位置清零或参考点定位。但Z相脉冲宽度窄,而且可能和AB相边沿同时出现,处理起来要小心。
我一般这样处理:
- 先用边沿检测抓到Z相的上升沿
- 在Z相有效时,把当前计数值锁存到寄存器
- 然后根据需求决定是否清零计数器
避坑指南:我曾经遇到过Z相脉冲和A相边沿刚好对齐的情况,导致计数器和Z相清零同时发生,位置数据出现了1个脉冲的误差。后来我加了一个“先锁存后清零”的机制,才彻底解决这个问题。
3.6 知识体系总览
说了这么多,咱们用一张图把编码器接口的核心逻辑串起来:
这张图把整个编码器接口的流程串起来了。从编码器输出ABZ信号,到FPGA采集去抖,再到四倍频解码和位置计数,每一步都有坑,每一步也都有技巧。
3.7 调试中的几个实用建议
最后,分享几个我调试编码器接口时的习惯:
- 先用示波器看波形:别急着写代码。先把A、B、Z三路信号用示波器抓出来,看看有没有毛刺、占空比是否正常、相位差是不是90°。这一步能省下后面80%的调试时间。
- 仿真时加随机抖动:我习惯在仿真时给AB信号加一些随机的抖动和毛刺,看看解码逻辑能不能扛得住。很多问题都是在仿真阶段发现的。
- 留一个调试接口:在FPGA里留一个寄存器,可以实时读出当前的计数值和方向状态。这样在调试时,通过上位机就能看到编码器的工作情况,不用每次都连示波器。
个人经验:编码器接口调试,最怕的就是“偶尔丢步”。这种问题往往不是逻辑错误,而是时序问题。我建议在FPGA里加一个“错误检测”逻辑,比如检测到AB相同时变化,就报一个错误标志。这样能帮你快速定位问题。
好了,编码器接口的基础就聊到这儿。这东西看着简单,但真要做得可靠,还是得花功夫的。下次咱们聊聊更高级的编码器——绝对值编码器,那个又是另一番天地了。