增量式光电编码器计数器程序
似乎坛子里做光电编码器相关项目的兄弟还不少,发个FPGA实现的90度相位差A、B两相脉冲计数的程序上来(Z相被54了).看了几个兄弟的写法,似乎都有点问题,乱说几点:
1、四倍频是必须的,这个跟编码器的结构有关
2、初始状态可能不是 A=0,B=0,(对于伺服电机尤其如此)
3、适当的隔离和滤波也是必须的
刚开始的时候接手摇编码器,计数器值老是有差。接伺服电机就更夸张,计数都计到天上去了.
纠结了两天才弄成,在伺服电机上和手摇编码器上测了一段时间没发现问题(阿弥陀佛).
FSM实现,个人觉得不是最优的方法,请高手指点.
FSM主状态转换图:
http://cache.amobbs.com/bbs_upload782111/files_32/ourdev_574663.JPG
总共13个状态,全画出来烦死,知道意思就好:) (原文件名:coderFSM.JPG)
源程序:
/*******************************************************************
** Company :
** Project Name :
** Author :
** Creation Date :2010.07
** Version Number :1.0
**
** Description :
**
**
**
** Revision History :
**
** Date Initials Modification
**
**
**********************************************************************/
module coder_counter(
clk, //system clock
en, //enable(low active)
load, //asynchronous load signal(high active)
diff_a, //A phasic pulse input
diff_b, //B phasic pulse input
load_data, //asynchronous load data
counter, //counter data
err //counter error signal(high active)
);
/*****************************************************************************
* Parameter Declarations *
*****************************************************************************/
parameter DATA_WIDTH = 32;
parameter IDLE='d0,ALBL_ADD='d1,ALBL_SUB='d2,ALBL='d3,AHBL_ADD='d4,AHBL_SUB='d5,AHBL='d6,
AHBH_ADD='d7,AHBH_SUB='d8,AHBH='d9,ALBH_ADD='d10,ALBH_SUB='d11,ALBH='d12,ERR='d13;
/*****************************************************************************
* Port Declarations *
*****************************************************************************/
input clk,en,load,diff_a,diff_b;
input load_data;
output regcounter;
output reg err;
/*****************************************************************************
* Internal wires and registers Declarations *
*****************************************************************************/
reg state,n_state;
//wire reset_n = ~load;
wire signal = {diff_b,diff_a};
/*****************************************************************************
* Finite State Machine *
*****************************************************************************/
always@(posedge clk or posedge load)
begin
if(load)
state <= IDLE;
else
state <= n_state;
end
always@(en or signal or state)
begin
case(state)
IDLE:
begin
if(en == 1)
n_state <= IDLE;
else
begin
case(signal)
'b00:n_state <= ALBL;
'b01:n_state <= AHBL;
'b10:n_state <= ALBH;
'b11:n_state <= AHBH;
endcase
end
end
ALBL_ADD:n_state <= ALBL;
ALBL_SUB:n_state <= ALBL;
ALBL://00
begin
case(signal)
'b00:n_state <= ALBL;
'b01:n_state <= AHBL_ADD;
'b10:n_state <= ALBH_SUB;
'b11:n_state <= ERR;
endcase
end
AHBL_ADD:n_state <= AHBL;
AHBL_SUB:n_state <= AHBL;
AHBL://01
begin
case(signal)
'b00:n_state <= ALBL_SUB;
'b01:n_state <= AHBL;
'b10:n_state <= ERR;
'b11:n_state <= AHBH_ADD;
endcase
end
AHBH_ADD:n_state <= AHBH;
AHBH_SUB:n_state <= AHBH;
AHBH://11
begin
case(signal)
'b00:n_state <= ERR;
'b01:n_state <= AHBL_SUB;
'b10:n_state <= ALBH_ADD;
'b11:n_state <= AHBH;
endcase
end
ALBH_ADD:n_state <= ALBH;
ALBH_SUB:n_state <= ALBH;
ALBH://10
begin
case(signal)
'b00:n_state <= ALBL_ADD;
'b01:n_state <= ERR;
'b10:n_state <= ALBH;
'b11:n_state <= AHBH_SUB;
endcase
end
ERR:n_state <= ERR;
default:n_state <= IDLE;
endcase
end
always@(posedge clk)
begin
case(state)
IDLE:
begin
counter <= load_data;
err <= 0;
end
ALBL_ADD:
begin
counter <= counter + 1'b1;
err <= 1'b0;
end
ALBL_SUB:
begin
counter <= counter - 1'b1;
err <= 1'b0;
end
ALBL:
begin
counter <= counter;
err <= 1'b0;
end
AHBL_ADD:
begin
counter <= counter + 1'b1;
err <= 1'b0;
end
AHBL_SUB:
begin
counter <= counter - 1'b1;
err <= 1'b0;
end
AHBL:
begin
counter <= counter;
err <= 1'b0;
end
AHBH_ADD:
begin
counter <= counter + 1'b1;
err <= 1'b0;
end
AHBH_SUB:
begin
counter <= counter - 1'b1;
err <= 1'b0;
end
AHBH:
begin
counter <= counter;
err <= 1'b0;
end
ALBH_ADD:
begin
counter <= counter + 1'b1;
err <= 1'b0;
end
ALBH_SUB:
begin
counter <= counter - 1'b1;
err <= 1'b0;
end
ALBH:
begin
counter <= counter;
err <= 1'b0;
end
ERR:
begin
counter <= counter;
err <= 1'b1;
end
default:
begin
counter <= counter;
err <= err;
end
endcase
end
endmodule
程序文件:
增量式光电编码器计数器verilog程序ourdev_574664.rar(文件大小:1K) (原文件名:coder_counter.rar) 楼主辛苦了,强烈支持 楼主搞的不错 学习了,希望多加点注释,谢谢 here is my code, using the same thought process, in C.
//determine increment / decrement of the encoder
unsigned char encoder_read(PORT_TYPE port, PORT_TYPE pins) {
const signed char ABs_states[]={0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0};
static unsigned char encoder_output=0x00;
static unsigned char ABs=0x00; //AB key read out, Previous in the high 2 bits and current in the low two bits;
unsigned char tmp;
ABs <<=2; //left 2 bits now contain the previous AB key read-out;
tmp=IO_GET(port, pins); //read ab pins
if (tmp & KEY_A) ABs |= 0x02; //set the 1st bit if A is high now;
if (tmp & KEY_B) ABs |= 0x01; //set the 0th bit if B is high;
ABs &= 0x0f; //only retain ABs' last 4 bits (A_previous, B_previous, A_current, B_current)
encoder_output += ABs_states;
return encoder_output;
//return ABs;
}
much simpler thanyours. ERR:n_state <= ERR;
一旦出现错误,是不是就在ERR状态中打转了。要重新使能才能继续运行吗 回复【5楼】semonpic
err:n_state <= err;
一旦出现错误,是不是就在err状态中打转了。要重新使能才能继续运行吗
-----------------------------------------------------------------------
是的,根据编码器的结构分析,正常情况下是不会出现跳转到ERR的条件的,除非信号线上有大的干扰,所以才要对信号进行隔离和滤波的处理.目前实现的是:如果出现ERR状态,相应位会被置位,必须重新用load信号加载. mark 没有这么复杂的,请看附件
点击此处下载 ourdev_576113.rar(文件大小:59K) (原文件名:Quadarture Decoder.rar) mark 图画的很好啊
mark 回复【楼主位】yngufeng
----------------------------------------------------------------------
你好 楼主 我现在在做光电编码器,可以请教下,你的程序的意思吗。我学的是VHDL 可否注释写下啊。13个状态不懂,怎么就13个状态啊,是四个状态啊 呵呵,我卖ACTEL的FPGA或CPLD,我见别人做的这东西CPLD这一块还好吧 回复【11楼】fengzheng
-----------------------------------------------------------------------
- -||...那么老的贴都被你挖出来了.按你的要求加了中文注释.图上画的状态转换只是示意,还有一些用来加减运算的中间状态没有画出来.
带注释文件:
点击此处下载 ourdev_593594BEPWMO.rar(文件大小:1K) (原文件名:coder_counter.rar) 回复【13楼】yngufeng
-----------------------------------------------------------------------
非常感谢楼主,我还有个问题啊,因为我想重改你的这个程序用VHDL ,不知道你说的中间的状态是不是和你画出来的是一样的那,
还有就是你这个实现了 正转和反转的不同计数吗?再次感谢楼主 回复【13楼】yngufeng
-----------------------------------------------------------------------
楼主你把你的设计思想大致说下可以不,我看了程序大概明白了,但是signal 好像你在这里是用到了状态 回复【楼主位】yngufeng
-----------------------------------------------------------------------
谢谢你楼主啊 ,想问下为什么我仿真出来的值counter始终就记住了一次的光电编码器的个数那。你也出现这种情况吗。请指导:如果可以的话加我QQ576394421万分感激附图
http://cache.amobbs.com/bbs_upload782111/files_34/ourdev_596150OLC8PM.jpg
附图 (原文件名:截图.jpg) 回复【17楼】fengzheng
-----------------------------------------------------只能记录一个回复【17楼】fengzheng
-----------------------------------------------------------------------
楼主我搞出来了 谢谢啊 mark 增量式编码器 回复【楼主位】yngufeng
-----------------------------------------------------------------------
请问楼主,为什么我得出的用singaltap看的那个counter的值都是1那 不改变 mark 增量式编码器 感谢楼主分享 回复【楼主位】yngufeng
-----------------------------------------------------------------------
楼主你这个程序有问题计数不正确,状态机设计的有问题 ,不知道你发现没有,请赐教,为什么计数不对 啊 回复【23楼】fengzheng
回复【楼主位】yngufeng
-----------------------------------------------------------------------
楼主你这个程序有问题计数不正确,状态机设计的有问题 ,不知道你发现没有,请赐教,为什么计数不对 啊
-----------------------------------------------------------------------
./emotion/em031.gif 呃~~~没遇到过这种情况,你把状态添加进singaltap里观察下看看,为什么会跳到ERROR状态。 回复【24楼】yngufeng
-----------------------------------------------------------------------
不知道为什么计数不对,我用你的程序来计数但是不对, mark mark mark 学习中... mark 一下,以后学习。 回复【14楼】fengzheng
-----------------------------------------------------------------------
回复【14楼】fengzheng
回复【13楼】yngufeng
-----------------------------------------------------------------------
非常感谢楼主,我还有个问题啊,因为我想重改你的这个程序用vhdl ,不知道你说的中间的状态是不是和你画出来的是一样的那,
还有就是你这个实现了 正转和反转的不同计数吗?再次感谢楼主
-----------------------------------------------------------------------
你用VHDL弄出来了没,能否分享一下,我现在也在弄这个 好资料!正在学习中 mark 经常见有人发码盘的,这个有什么诀窍吗?
我以前用C语言的思想写了一个,还是一样的用得好好的啊....
reg cnt11;
reg cnt12;
reg cnt13;
reg cnt14;
/**************************CODER1************************/
always@(posedge coder1a or negedge clear1)//Line a input rising edge
begin
if(clear1==1'b0)cnt11<=0;
else
begin
if(coder1b==1'b1)cnt11<=cnt11+1;
else cnt11<=cnt11-1;
end
end
//---------------------------------------------
always@(negedge coder1a or negedge clear1)//Line a input rising edge
begin
if(clear1==1'b0)cnt12<=0;
else
begin
if(coder1b==1'b0)cnt12<=cnt12+1;
else cnt12<=cnt12-1;
end
end
//---------------------------------------------
always@(posedge coder1b or negedge clear1)//Line b input rising edge
begin
if(clear1==1'b0)cnt13<=0;
else
begin
if(coder1a==1'b0)cnt13<=cnt13+1;
else cnt13<=cnt13-1;
end
end
//---------------------------------------------
always@(negedge coder1b or negedge clear1)//Line b input rising edge
begin
if(clear1==1'b0)cnt14<=0;
else
begin
if(coder1a==1'b1)cnt14<=cnt14+1;
else cnt14<=cnt14-1;
end
end
assign cnt10= cnt11+cnt12+cnt13+cnt14; 很好啊 有用 学习了,以后用得上。 增量式编码器 过来学习一下~ mark 回复【楼主位】yngufeng
-----------------------------------------------------------------------
状态怎么13个?看不出?不知道是用来干什么的 收藏!! 正在入门学习,收藏了 我也来MARK一下 mark学习一下~~~ 记一下! 谢谢
学习一下,编码器也是计数不对。。 学习,谢谢!!! 不错。。。。。。
页:
[1]