搜索
bottom↓
回复: 49

增量式光电编码器计数器程序

[复制链接]

出0入0汤圆

发表于 2010-8-12 22:53:19 | 显示全部楼层 |阅读模式
似乎坛子里做光电编码器相关项目的兄弟还不少,发个FPGA实现的90度相位差A、B两相脉冲计数的程序上来(Z相被54了).
看了几个兄弟的写法,似乎都有点问题,乱说几点:
1、四倍频是必须的,这个跟编码器的结构有关
2、初始状态可能不是 A=0,B=0,(对于伺服电机尤其如此)
3、适当的隔离和滤波也是必须的
刚开始的时候接手摇编码器,计数器值老是有差。接伺服电机就更夸张,计数都计到天上去了.
纠结了两天才弄成,在伺服电机上和手摇编码器上测了一段时间没发现问题(阿弥陀佛).

FSM实现,个人觉得不是最优的方法,请高手指点.
FSM主状态转换图:

总共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 [DATA_WIDTH-1:0]load_data;
output reg[DATA_WIDTH-1:0]counter;
output reg err;
/*****************************************************************************
*      Internal wires and registers Declarations                           *
*****************************************************************************/
reg [3:0]state,n_state;
//wire reset_n = ~load;
wire [1:0]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)

阿莫论坛20周年了!感谢大家的支持与爱护!!

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出0入0汤圆

发表于 2010-8-12 23:57:08 | 显示全部楼层
楼主辛苦了,强烈支持

出0入0汤圆

发表于 2010-8-13 00:52:18 | 显示全部楼层
楼主搞的不错

出0入0汤圆

发表于 2010-8-13 07:24:56 | 显示全部楼层
学习了,希望多加点注释,谢谢

出0入0汤圆

发表于 2010-8-13 07:38:37 | 显示全部楼层
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[ABs];
return encoder_output;
//return ABs;
}

much simpler than  yours.

出0入0汤圆

发表于 2010-8-16 14:28:37 | 显示全部楼层
ERR:n_state <= ERR;

一旦出现错误,是不是就在ERR状态中打转了。要重新使能才能继续运行吗

出0入0汤圆

 楼主| 发表于 2010-8-17 20:22:42 | 显示全部楼层
回复【5楼】semonpic
err:n_state &lt;= err;  
一旦出现错误,是不是就在err状态中打转了。要重新使能才能继续运行吗
-----------------------------------------------------------------------

是的,根据编码器的结构分析,正常情况下是不会出现跳转到ERR的条件的,除非信号线上有大的干扰,所以才要对信号进行隔离和滤波的处理.目前实现的是:如果出现ERR状态,相应位会被置位,必须重新用load信号加载.

出0入0汤圆

发表于 2010-8-19 11:24:16 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-8-19 12:12:38 | 显示全部楼层
没有这么复杂的,请看附件

点击此处下载 ourdev_576113.rar(文件大小:59K) (原文件名:Quadarture Decoder.rar)

出0入0汤圆

发表于 2010-8-19 13:08:01 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-10-22 19:50:57 | 显示全部楼层
图画的很好啊
mark

出0入0汤圆

发表于 2010-10-27 10:49:24 | 显示全部楼层
回复【楼主位】yngufeng
----------------------------------------------------------------------
你好 楼主 我现在在做光电编码器,可以请教下,你的程序的意思吗。我学的是VHDL 可否注释写下啊。13个状态不懂,怎么就13个状态啊,是四个状态啊

出0入0汤圆

发表于 2010-10-27 12:04:37 | 显示全部楼层
呵呵,我卖ACTEL的FPGA或CPLD,我见别人做的这东西CPLD这一块还好吧

出0入0汤圆

 楼主| 发表于 2010-10-28 22:16:07 | 显示全部楼层
回复【11楼】fengzheng
-----------------------------------------------------------------------

- -||...那么老的贴都被你挖出来了.按你的要求加了中文注释.图上画的状态转换只是示意,还有一些用来加减运算的中间状态没有画出来.
带注释文件:
点击此处下载 ourdev_593594BEPWMO.rar(文件大小:1K) (原文件名:coder_counter.rar)

出0入0汤圆

发表于 2010-10-29 10:46:14 | 显示全部楼层
回复【13楼】yngufeng
-----------------------------------------------------------------------
非常感谢楼主,我还有个问题啊,因为我想重改你的这个程序用VHDL ,不知道你说的中间的状态是不是和你画出来的是一样的那,
还有就是你这个实现了 正转和反转的不同计数吗?再次感谢楼主

出0入0汤圆

发表于 2010-10-29 11:52:35 | 显示全部楼层
回复【13楼】yngufeng
-----------------------------------------------------------------------

楼主你把你的设计思想大致说下可以不,我看了程序大概明白了,但是signal 好像你在这里是用到了状态

出0入0汤圆

发表于 2010-11-8 15:07:30 | 显示全部楼层
回复【楼主位】yngufeng
-----------------------------------------------------------------------
谢谢你楼主啊 ,想问下为什么我仿真出来的值counter始终就记住了一次的光电编码器的个数那。你也出现这种情况吗。请指导:如果可以的话  加我QQ576394421万分感激附图

附图 (原文件名:截图.jpg)

出0入0汤圆

发表于 2010-11-8 15:14:14 | 显示全部楼层
回复【17楼】fengzheng
-----------------------------------------------------只能记录一个回复【17楼】fengzheng
-----------------------------------------------------------------------

楼主我搞出来了 谢谢啊

出0入0汤圆

发表于 2010-11-9 12:06:50 | 显示全部楼层
mark 增量式编码器

出0入0汤圆

发表于 2010-12-13 09:41:21 | 显示全部楼层
回复【楼主位】yngufeng
-----------------------------------------------------------------------
请问楼主,为什么我得出的用singaltap看的那个counter的值都是1那 不改变

出0入9汤圆

发表于 2010-12-13 09:58:37 | 显示全部楼层
mark 增量式编码器

出0入0汤圆

发表于 2010-12-13 16:10:02 | 显示全部楼层
感谢楼主分享

出0入0汤圆

发表于 2010-12-17 15:39:07 | 显示全部楼层
回复【楼主位】yngufeng
-----------------------------------------------------------------------
楼主你这个程序有问题计数不正确,状态机设计的有问题 ,不知道你发现没有,请赐教,为什么计数不对 啊

出0入0汤圆

 楼主| 发表于 2010-12-18 15:56:50 | 显示全部楼层
回复【23楼】fengzheng
回复【楼主位】yngufeng  
-----------------------------------------------------------------------
楼主你这个程序有问题计数不正确,状态机设计的有问题 ,不知道你发现没有,请赐教,为什么计数不对 啊
-----------------------------------------------------------------------

呃~~~没遇到过这种情况,你把状态添加进singaltap里观察下看看,为什么会跳到ERROR状态。

出0入0汤圆

发表于 2010-12-20 20:49:17 | 显示全部楼层
回复【24楼】yngufeng
-----------------------------------------------------------------------

不知道为什么计数不对,我用你的程序来计数但是不对,

出0入0汤圆

发表于 2010-12-20 20:59:33 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-12-20 22:13:03 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-7-14 08:13:11 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-7-15 16:30:53 | 显示全部楼层
学习中...

出0入0汤圆

发表于 2011-7-19 08:30:26 | 显示全部楼层
mark 一下,以后学习。

出0入0汤圆

发表于 2011-7-21 11:03:07 | 显示全部楼层
回复【14楼】fengzheng
-----------------------------------------------------------------------

回复【14楼】fengzheng
回复【13楼】yngufeng  
-----------------------------------------------------------------------
非常感谢楼主,我还有个问题啊,因为我想重改你的这个程序用vhdl ,不知道你说的中间的状态是不是和你画出来的是一样的那,
还有就是你这个实现了 正转和反转的不同计数吗?再次感谢楼主
-----------------------------------------------------------------------

你用VHDL弄出来了没,能否分享一下,我现在也在弄这个

出0入0汤圆

发表于 2011-11-25 21:38:57 | 显示全部楼层
好资料!正在学习中

出15入190汤圆

发表于 2011-11-25 21:44:00 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-11-25 22:00:02 | 显示全部楼层
经常见有人发码盘的,这个有什么诀窍吗?
我以前用C语言的思想写了一个,还是一样的用得好好的啊....

reg [31:0] cnt11;
reg [31:0] cnt12;
reg [31:0] cnt13;
reg [31:0] 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;

出0入4汤圆

发表于 2011-11-28 08:16:41 | 显示全部楼层
很好啊

出0入0汤圆

发表于 2011-12-2 15:22:52 | 显示全部楼层
有用

出0入0汤圆

发表于 2011-12-2 16:29:31 | 显示全部楼层
学习了,以后用得上。

出0入0汤圆

发表于 2011-12-7 13:55:56 | 显示全部楼层
增量式编码器

出0入0汤圆

发表于 2011-12-27 11:05:04 | 显示全部楼层
过来学习一下~

出0入0汤圆

发表于 2012-2-24 00:41:17 | 显示全部楼层
mark

出0入0汤圆

发表于 2012-2-24 02:07:38 | 显示全部楼层
回复【楼主位】yngufeng
-----------------------------------------------------------------------

状态怎么13个?看不出?不知道是用来干什么的

出0入0汤圆

发表于 2012-2-29 12:32:19 | 显示全部楼层
收藏!!

出0入0汤圆

发表于 2012-7-21 18:17:36 | 显示全部楼层
正在入门学习,收藏了

出0入0汤圆

发表于 2012-7-21 19:31:31 | 显示全部楼层
我也来MARK一下

出0入0汤圆

发表于 2013-1-17 21:38:24 | 显示全部楼层
mark  学习一下  ~~~

出0入0汤圆

发表于 2013-1-17 22:13:56 | 显示全部楼层
记一下! 谢谢

出0入0汤圆

发表于 2013-1-22 20:15:36 | 显示全部楼层
学习一下,编码器也是计数不对。。

出0入0汤圆

发表于 2013-12-11 12:50:58 | 显示全部楼层
学习,谢谢!!!

出0入0汤圆

发表于 2014-7-27 21:38:14 | 显示全部楼层
不错。。。。。。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-7-24 03:18

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表