本节将和大家一起使用FPGA驱动底板上的EC11的旋转编码器的原理及驱动方法。


硬件说明

旋转编码器是用来测量转速的装置,因其人性化的操作被用于越来越多的电子设备中,旋转编码器有多种分类:

  • 以编码器工作原理可分为:光电式、磁电式和触点电刷式。
  • 以码盘刻孔方式不同分为:增量式和绝对式两类。

关于以上各类编码器的区别,大家自行查阅资料,这里就不多做介绍了。
我们STEP-BaseBoard底板上集成的EC11的旋转编码器就属于增量式触电电刷编码器,其工作原理如下:

如上图所示,当顺时针旋转时A信号提前B信号90度相位,当逆时针旋转时B信号提前A信号90度相位,FPGA接收到旋转编码器的A、B信号时,可以根据A、B的状态组合判定编码器的旋转方向。
程序设计中我们可以对A、B信号检测,检测A信号的边沿及B信号的状态,

  • 当A信号上升沿时B信号为低电平,或当A信号下降沿时B信号为高电平,证明当前编码器为顺时针转动
  • 当A信号上升沿时B信号为高电平,或当A信号下降沿时B信号为低电平,证明当前编码器为逆时针转动

本设计实际电路连接如下:


Verilog代码

// --------------------------------------------------------------------
// >>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<
// --------------------------------------------------------------------
// Module: Encoder
// 
// Author: Step
// 
// Description: Driver for rotary encoder
// 
// Web: www.stepfapga.com
// 
// --------------------------------------------------------------------
// Code Revision History :
// --------------------------------------------------------------------
// Version: |Mod. Date:   |Changes Made:
// V1.0     |2016/04/20   |Initial ver
// --------------------------------------------------------------------
module Encoder
(
input					clk_in,			//系统时钟
input					rst_n_in,		//系统复位,低有效
input					key_a,			//旋转编码器A管脚
input					key_b,			//旋转编码器B管脚
input					key_ok,			//旋转编码器D管脚
output	reg				Left_pulse,		//左旋转脉冲输出
output	reg				Right_pulse,	//右旋转脉冲输出
output					OK_pulse		//按动脉冲输出
);
 
localparam				NUM_500US	=	6_000;	
 
reg				[12:0]	cnt;
//计数器周期为500us,控制键值采样频率
always@(posedge clk_in or negedge rst_n_in) begin
	if(!rst_n_in) cnt <= 0;
	else if(cnt >= NUM_500US-1) cnt <= 1'b0;
	else cnt <= cnt + 1'b1;
end
 
reg				[5:0]	cnt_20ms;
reg						key_a_r,key_a_r1;
reg						key_b_r,key_b_r1;
reg						key_ok_r;
 
//针对A、B、D管脚分别做简单去抖操作,
//如果对旋转编码器的要求比较高,建议现对旋转编码器的输出做严格的消抖处理后再来做旋转编码器的驱动
//对旋转编码器的输入缓存,消除亚稳态同时延时锁存
always@(posedge clk_in or negedge rst_n_in) begin
	if(!rst_n_in) begin
		key_a_r		<=	1'b1;
		key_a_r1	<=	1'b1;
		key_b_r		<=	1'b1;
		key_b_r1	<=	1'b1;
		cnt_20ms	<=	1'b1;
		key_ok_r	<=	1'b1;
	end else if(cnt == NUM_500US-1) begin
		key_a_r		<=	key_a;
		key_a_r1	<=	key_a_r;
		key_b_r		<=	key_b;
		key_b_r1	<=	key_b_r;
		if(cnt_20ms >= 6'd40) begin	//对于按键D信号还是采用20ms周期采样的方法,40*500us = 20ms
			cnt_20ms <= 6'd0;
			key_ok_r <= key_ok;
		end else begin 
			cnt_20ms <= cnt_20ms + 1'b1;
			key_ok_r <=	key_ok_r;
		end
	end
end
 
reg						key_ok_r1;
//对按键D信号进行延时锁存
always@(posedge clk_in or negedge rst_n_in) begin
	if(!rst_n_in) key_ok_r1 <= 1'b1;
	else key_ok_r1 <= key_ok_r;
end
 
wire	A_state		= key_a_r1 && key_a_r && key_a;	//旋转编码器A信号高电平状态检测
wire	B_state		= key_b_r1 && key_b_r && key_b;	//旋转编码器B信号高电平状态检测
assign	OK_pulse	= key_ok_r1 && (!key_ok_r);		//旋转编码器D信号下降沿检测
 
reg						A_state_reg;
//延时锁存
always@(posedge clk_in or negedge rst_n_in) begin
	if(!rst_n_in) A_state_reg <= 1'b1;
	else A_state_reg <= A_state;
end
 
//旋转编码器A信号的上升沿和下降沿检测
wire	A_pos	= (!A_state_reg) && A_state;
wire	A_neg	= A_state_reg && (!A_state);
 
//通过旋转编码器A信号的边沿和B信号的电平状态的组合判断旋转编码器的操作,并输出对应的脉冲信号
always@(posedge clk_in or negedge rst_n_in)begin
	if(!rst_n_in)begin
		Right_pulse <= 1'b0;
		Left_pulse <= 1'b0;
	end else begin
		if(A_pos && B_state) Left_pulse <= 1'b1;	
		else if(A_neg && B_state) Right_pulse <= 1'b1;
		else begin
			Right_pulse <= 1'b0;
			Left_pulse <= 1'b0;
		end
	end
end
 
endmodule

小结

本节主要为大家讲解了旋转编码器的工作原理及软件设计,需要大家掌握的同时自己创建工程,通过整个设计流程,生成FPGA配置文件加载测试。
如果你对Diamond软件的使用不了解,请参考这里:Diamond的使用


相关资料


使用STEP-MXO2第二代的旋转编码器应用程序: 后续会有下载连接 待更新
使用STEP-MAX10的旋转编码器应用程序: 后续会有下载连接 待更新