差别
这里会显示出您选择的修订版和当前版本之间的差别。
后一修订版 | 前一修订版 | ||
fpga_quad_decoder [2022/04/26 13:10] gongyusu 创建 |
fpga_quad_decoder [2022/04/26 16:17] (当前版本) gongyusu [什么是正交信号?] |
||
---|---|---|---|
行 1: | 行 1: | ||
## 用FPGA做正交解码 | ## 用FPGA做正交解码 | ||
+ | 转自文章 - [[https://www.fpga4fun.com/QuadratureDecoder.html|Quadrature Decoder]] | ||
+ | |||
FPGA非常适合用逻辑来实现正交解码的功能。 | FPGA非常适合用逻辑来实现正交解码的功能。 | ||
- | ### 什么是正交信号? | + | ###什么是正交信号? |
- | 正交信号是两个产生90度相位差的信号。它们在机械系统中用于确定轴的运动(或转动)。比如下面这是一个向前移动几步的轴。 | + | 正交信号是两个相位差为90度的信号。它们在机械系统中用于确定轴的运动(或旋转)。 |
+ | |||
+ | 这是一个向前移动几步的轴。 | ||
+ | {{ ::quadraturedecoder_waveforma.gif |}} | ||
+ | |||
+ | 如果对脉冲计数,则可以说轴移动了3步。\\ | ||
+ | 如果计算边缘,则可以说轴移动了12步。这就是我们在此页面上所做的。\\ | ||
+ | \\ | ||
+ | |||
+ | 现在,轴向后移动了相同的量。 | ||
+ | {{ ::quadraturedecoder_waveformb.gif |}} | ||
+ | |||
+ | 因此,想法是通过查看边缘和水平,我们可以确定运动的方向和距离。\\ | ||
+ | 这是一个示例,其中轴向前移动10步,然后向后移动7步。 | ||
+ | {{ ::quadraturedecoder_waveformc.gif |}} | ||
+ | \\ | ||
+ | |||
+ | ####它们在哪里使用? | ||
+ | * 在机械手轴中,用于反馈控制。 | ||
+ | * 用旋钮确定用户输入。 | ||
+ | * 在电脑鼠标中,确定运动方向。 | ||
+ | |||
+ | 如果您打开机械鼠标,则会看到以下内容。 | ||
+ | {{ ::mouseinternal.jpg |}} | ||
+ | |||
+ | 有两个光学正交编码器,每个编码器由开槽轮,光发射器和一对光电探测器制成。\\ | ||
+ | \\ | ||
+ | 鼠标包括负责正交解码和串行/ PS2接口的IC。由于创建正交解码器(在FPGA中)比串行或PS2接口要容易得多,因此我们修改了鼠标,并用四缓冲器施密特触发器输入IC替换了原始IC。 | ||
+ | {{ ::mouseinternal2.jpg |}} | ||
+ | |||
+ | 我们使用[[http://www.national.com/ds/CD/CD4093BC.pdf|CD4093]],每个NAND门的输入连接在一起形成反相器。\\ | ||
+ | 现在,鼠标输出正交编码信号!\\ | ||
+ | \\ | ||
+ | |||
+ | ####正交解码器 | ||
+ | 我们要实现一个根据正交信号递增或递减的计数器。我们假设有一个比正交信号快的“过采样时钟”(在此页面中称为“ clk”)。\\ | ||
+ | \\ | ||
+ | 控制计数器的硬件电路非常简单。 | ||
+ | {{ ::quadraturedecoder1.gif |}} | ||
+ | |||
+ | 这是轴向前移动的波形,计数器会递增。 | ||
+ | {{ ::quadraturedecoder_waveform.gif |}} | ||
+ | |||
+ | 该电路有时称为“ 4x解码器”,因为它会计算正交输入的所有跃迁。\\ | ||
+ | \\ | ||
+ | 在verilog HDL中,这为我们提供了:\\ | ||
+ | |||
+ | <code verilog> | ||
+ | module quad(clk, quadA, quadB, count); | ||
+ | input clk, quadA, quadB; | ||
+ | output [7:0] count; | ||
+ | |||
+ | reg quadA_delayed, quadB_delayed; | ||
+ | always @(posedge clk) quadA_delayed <= quadA; | ||
+ | always @(posedge clk) quadB_delayed <= quadB; | ||
+ | |||
+ | wire count_enable = quadA ^ quadA_delayed ^ quadB ^ quadB_delayed; | ||
+ | wire count_direction = quadA ^ quadB_delayed; | ||
+ | |||
+ | reg [7:0] count; | ||
+ | always @(posedge clk) | ||
+ | begin | ||
+ | if(count_enable) | ||
+ | begin | ||
+ | if(count_direction) count<=count+1; else count<=count-1; | ||
+ | end | ||
+ | end | ||
+ | |||
+ | endmodule | ||
+ | </code> | ||
+ | \\ | ||
+ | |||
+ | ####实际生活中的电路 | ||
+ | 先前的电路假定“ quadX”输入与“ clk”时钟同步。在大多数情况下,“ quadX”信号与FPGA时钟不同步。经典解决方案是每个输入使用2个额外的D触发器,以避免将亚稳性引入计数器。 | ||
+ | {{ ::quadraturedecoder2.gif |}} | ||
+ | \\ | ||
+ | |||
+ | <code verilog> | ||
+ | module quad(clk, quadA, quadB, count); | ||
+ | input clk, quadA, quadB; | ||
+ | output [7:0] count; | ||
+ | |||
+ | reg [2:0] quadA_delayed, quadB_delayed; | ||
+ | always @(posedge clk) quadA_delayed <= {quadA_delayed[1:0], quadA}; | ||
+ | always @(posedge clk) quadB_delayed <= {quadB_delayed[1:0], quadB}; | ||
+ | |||
+ | wire count_enable = quadA_delayed[1] ^ quadA_delayed[2] ^ quadB_delayed[1] ^ quadB_delayed[2]; | ||
+ | wire count_direction = quadA_delayed[1] ^ quadB_delayed[2]; | ||
+ | |||
+ | reg [7:0] count; | ||
+ | always @(posedge clk) | ||
+ | begin | ||
+ | if(count_enable) | ||
+ | begin | ||
+ | if(count_direction) count<=count+1; else count<=count-1; | ||
+ | end | ||
+ | end | ||
+ | |||
+ | endmodule | ||
+ | </code> | ||
+ | \\ | ||
+ | |||
+ | 总之,创建正交解码器/计数器所需的硬件很少。FPGA可以容纳多个轴,因此可以同时跟踪多个轴。\\ | ||