FPGA接口实现----增量式编码器

前言

实验室的Zynq项目中要求在PL端实现一个增量式编码器实时的数据检测。本次项目中其实有着两套编码器,其中电机后有一套编码器负责测量各个电机的速度;另外,每条腿上还外接了一组编码器负责位置信息的测量。电机内置的编码器通过伺服驱动器可以直接通过CAN总线得到数据;而外接的编码器则是A,B,Z三相输出需要在PL端构建合适的信号处理模块。

一 增量式编码器原理介绍

增量式编码器是一种将位移信息转换成周期性电信号,再将电信号转换成脉冲计数的装置。
通常增量式编码器的接线输出为两根电源线,A,B,Z三个脉冲信号。其中可以通过A,B信号的相位关系来判断编码器的旋转方向,可以人为规定若A相在前,B相落后90o 则为正方向,反之为负方向。
旋转角度的计算也很简单,
顺时针:
θ = ( k + 1 ) ∗ 360 分 辨 率 \theta=(k+1)*\frac{360}{分辨率} θ=(k+1)360
逆时针:
θ = ( 分 辨 率 − ( k + 1 ) ) ∗ 360 分 辨 率 \theta=(分辨率-(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的编写需要强化学习。

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值