一 增量式编码器原理介绍
增量式编码器是一种将位移信息转换成周期性电信号,再将电信号转换成脉冲计数的装置。
通常增量式编码器的接线输出为两根电源线,A,B,Z三个脉冲信号。其中可以通过A,B信号的相位关系来判断编码器的旋转方向,可以人为规定若A相在前,B相落后90o 则为正方向,反之为负方向。
旋转角度的计算也很简单,
顺时针:
θ = ( k + 1 ) ∗ 360 分 辨 率 heta=(k+1)*frac{360}{分辨率} θ=(k+1)∗分辨率360
逆时针:
θ = ( 分 辨 率 − ( k + 1 ) ) ∗ 360 分 辨 率 heta=(分辨率-(k+1))*frac{360}{分辨率} θ=(分辨率−(k+1))∗分辨率360
每旋转过一个单位刻度,A,B相都会产生一个脉冲,Z相信号是每转一圈产生一个周期的高电平。
倍频: 实际应用中往往会采用两倍频或者四倍频的方式来提高精度,一个周期内 A,B相的信号都会产生四次边沿跳变,两倍频可以在上升沿,下降沿各计数一次;四倍频则是每个边沿变化都计数。
两倍频计数规则: 在A或B的上升、下降沿都计数。
四倍频计数规则: 当A为高电平时,B在上升沿则加1,下降沿则减1;A为低电平时,B在下降沿则减1,上升沿则加1;B为高电平时,A在上升沿则减1,下降沿则加1;在B为低电平时,A在上升沿则加1,下降沿则减1。
PUL =(A1 ^ B2) ^ (A2 ^ B1)
二 硬件实现
在查阅资料论文后,发现大部分都是采用的是三个模块:顶层模块;倍频鉴相模块,以及计数模块。
其实完全可以综合为一个模块同时完成倍频鉴相计数工作。代码参考这位大佬
`timescale 1ns / 1ps module bianmaqi2(clk,rst_n ,quadA, quadB, position_out,A,B,DIR,index); input clk,rst_n, quadA, quadB,index; output [15:0] position_out; output A,B,DIR; reg [2:0] quadA_delayed, quadB_delayed; reg A,B,DIR; reg [15:0] position; 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]; //PUL =(A1^B2)^(A2^B1) wire count_direction = quadA_delayed[1] ^ quadB_delayed[2]; //DIR = C^D C是A1打一拍 D是B1打两拍 always @(posedge osc or negedge rst_n ) begin if(!rst_n)begin position<=16'd0; A<=0; B<=0; DIR<=0; //复位信号 必须有复位信号来赋初值 否则在testbench中输出为高阻态 end else if(count_enable) begin if(count_direction) position<=position+1'b1; else position<=position-1'b1; A <= quadA_delayed[2]; B <= quadB_delayed[2]; DIR <= count_direction; end else position<=position; end assign position_out = position; endmodule
三 测试平台
分别测试正转和反转;
正转即A比B超前90°;反转即B比A超前90°。
`timescale 1 ps/ 1 ps module bianmaqi2_tb(); // constants // general purpose registers reg eachvec; // test vector input registers reg index; reg rst_n; reg osc; reg quadA; reg quadB; // wires wire A; wire B; wire DIR; wire [15:0] position_out; // assign statements (if any) bianmaqi2 i1 ( // port map - connection between master ports and signals/registers .A(A), .B(B), .rst_n(rst_n), .DIR(DIR), .index(index), .osc(osc), .position_out(position_out), .quadA(quadA), .quadB(quadB) ); initial begin //initialize inputs rst_n=1'b0; osc=1'b0; quadA =1; quadB =0; index =0; #5 rst_n=1'b1; end initial begin repeat(50)begin #20 quadB=1; #20 quadA=0; #20 quadB=0; #20 quadA=1; end $stop; end always #10 osc =~osc; //产生50MHz时钟源 endmodule
`timescale 1 ps/ 1 ps module bianmaqi2_nishizhen_tb(); // constants // general purpose registers reg eachvec; // test vector input registers reg index; reg rst_n; reg osc; reg quadA; reg quadB; // wires wire A; wire B; wire DIR; wire [15:0] position_out; // assign statements (if any) bianmaqi2 i1 ( // port map - connection between master ports and signals/registers .A(A), .B(B), .rst_n(rst_n), .DIR(DIR), .index(index), .osc(osc), .position_out(position_out), .quadA(quadA), .quadB(quadB) ); initial begin //initialize inputs rst_n=1'b0; osc=1'b0; quadA =0; quadB =1; index =0; #5 rst_n=1'b1; end initial begin repeat(50)begin #20 quadA=1; #20 quadB=0; #20 quadA=0; #20 quadB=1; end $stop; end always #10 osc =~osc; //产生50MHz时钟源 endmodule
四 总结
fpga设计模块其实实现很简单,主要还是Quartus和Modelsim的联合仿真部分遇到了问题,主要还是testbench的编写需要强化学习。
全部0条评论
快来发表一下你的评论吧 !