搜索
bottom↓
回复: 10

正交编码器计数脉冲丢失,从哪下手?

[复制链接]

出0入0汤圆

发表于 2010-4-26 15:12:57 | 显示全部楼层 |阅读模式
用Verilog 处理正交编码器的计数。 长时间计数后发现计数器不准确了。。。

4倍频鉴相处理 :
module Phase(
        clk,        //时钟。8MHZ
        lnA,      //A相
        lnB,      //B相
        clk_o,    //输出的时钟
        ph        //输出相位 (正向或反向)
);
input clk;                        //8MHZ
input lnA,lnB;                //
output reg clk_o,ph;//


reg [1:0] state1;
reg [1:0] state0;
reg [3:0] wide_counter;         //输出脉宽控制.

always @(posedge clk)         //上升沿处理
begin                 
          state0 <= {lnA,lnB};
          state1 <= state0;
       
          case( {state1,state0} )
          4'b0010,//B=0,A 0->1
          4'b1011,//A=1,B 0->1
          4'b1101,//B=1,A 1->0
          4'b0100://A=0,B 1->0
          begin
                     clk_o <= 1;
                     ph <= 0;
                     wide_counter <= 0;
          end
          4'b0001,//A=0,B 0->1
          4'b0111,//B=1,A 0->1
          4'b1110,//A=1,B 1->0
          4'b1000://B=0,A 1->0
          begin
                     clk_o <= 1;
                     ph <= 1;
                     wide_counter <= 0;
          end
          endcase
           /////////////////////////////////////////////////////
           if( clk_o )
           begin
                     wide_counter <= wide_counter + 1;
                     if( wide_counter == 7) //让高电平保持N个时钟周期
                     begin
                               clk_o <= 0;
                               wide_counter <= 0;
                     end
            end
end
endmodule


计数器:
module ECounter(
   Clk, //时钟 8MHZ
   cp,  //鉴相输出的脉冲输入
   ph,  //鉴相输出的相位输入
   Z,   //编码器零点(Z相)
   en,  //使能
   reset,//复位
   write,//写初始标志
   DI,  //输入数据
   DO   //计数器输出
);
input Clk;
input cp,ph,Z,en,reset;
input write;
input [15:0] DI;
output reg [15:0] DO;

reg [2:0] cp_buf;
wire cp_flag;

reg [1:0] reset_buf;
wire reset_flag;

reg [1:0] Z_buf;
wire Z_flag;

//同步cp,reset,z 三个信号
always @(posedge Clk)
begin
           cp_buf <= {cp_buf[1:0],cp};
           reset_buf <= {reset_buf[0],reset};
           Z_buf <= {Z_buf[0],Z};
end
assign cp_flag = cp_buf[0] & cp_buf[1] & !cp_buf[2];//0->1
assign reset_flag = !reset_buf[0] & reset_buf[1];        //1->0
assign Z_flag = !Z_buf[0] & Z_buf[1];        //1->0

always @(posedge Clk)
begin
          if( reset_flag )
                    DO <= 0;
          else if( Z_flag)        //Encode Z pos
          begin
                //这里是编码器机械零位! 可以点做什么处理 呢?
          end
          else if( write )
                     DO <= DI;//写入初值
          else if(cp_flag && en)
          begin
                     if( ph ) //正向
                               DO <= DO + 1;
                     else     //反向
                               DO <= DO - 1;
          end
end
endmodule
       
测试方法, 接入编码器不停的转动,有正转,也有反转。。。 记位一个位置记下当前的计数器值。
运行一个晚上后。 转回原来标志的位置。
发现计数值不对了! 偏差了很多。。。。

如果短时间运行, 偏差分辨不出来。。。 长时间后累积多了就看到了。

估计是正反变换时丢失了某些脉冲没有记数!

请大家帮分析一下从什么地方下手才可以提高可靠性?

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

曾经有一段真挚的爱情摆在我的面前,我没有珍惜,现在想起来,还好我没有珍惜……

出0入0汤圆

发表于 2010-4-26 21:48:41 | 显示全部楼层
帮顶,“同步cp,reset,z 三个信号”没看懂

出0入0汤圆

 楼主| 发表于 2010-4-28 09:41:39 | 显示全部楼层
怎么没有做过相关的处理 吗?

出0入0汤圆

发表于 2010-4-28 12:33:43 | 显示全部楼层
在正反向转动的时候会有误差,长时间有累计误差
你试试每计一个数,就送出显示,反复测试,你会发现在反向的时候就会有一个脉冲的误差

出0入0汤圆

发表于 2010-4-28 13:38:32 | 显示全部楼层
当有Z脉冲时必须多计数器强制赋值,转动难免会丢失脉冲。这样保证无限多次运转 丢失脉冲不累加!

出0入0汤圆

发表于 2010-4-28 13:39:14 | 显示全部楼层
你QQ多少加下你!

出0入0汤圆

 楼主| 发表于 2010-4-28 14:10:41 | 显示全部楼层
QQ: 1291273

我是计数的时候立即显示出来的。 用手转动脉冲没有少。 如200一卷的编码器,4倍频后是800 我试过转过800就归0的。。 只是在连续运转几个小时或1天就开始感觉到偏了。。。
我在CPU用一中断脚接受 Z 的中断。 在中断中判断是否为 800 的整数, 正常来说每发生一次 Z 计数值应该是 800的整数倍。
用手短时转动都是正确的。 当放到设备上连续工作就慢慢发现在Z相到来时已经偏了这个 800 的倍数!

出0入0汤圆

 楼主| 发表于 2010-4-28 14:15:03 | 显示全部楼层
TO :  yonghaokeji

这是我的Z 相处理 。。。。 只是在CPU的中断中处理 。
你看这样的算法合理不? 是否可以在 CPLD中处理?

void Z_Handler(void)
{
          s16 Counter = ENC_Get_Counter();        //读计数器。

          s16 ENCPulse = PARAM_GetENCPulse() * 4;//已经4倍频了!
       
        //过编码器零位,计数器应该是刚才被编码器脉冲数整除!
          int page = Counter % ENCPulse;        //
          int temp = page - ENCPulse;        //这个一定是负值。

          if( page > abs(temp))        //取最小值!
                     min_value = temp;
          else
                     min_value = page;

          if( abs(min_value) > ENCPulse/4)        //出现偏差了!正常应该是
                     APP_OnENCError(); //报错用的。。。
          else
          {
                     //强制赋值。。。。
                    page = Counter / ENCPulse;
                    Counter = page * ENCPulse;

                    if( min_value < 0)        //向上对齐
                            Counter += ENCPulse;

                    ENC_Set_Counter(Counter); //赋值
          }
}

编辑原因: 复制过来的代码缩进不见了!

出0入0汤圆

发表于 2011-10-8 10:47:24 | 显示全部楼层
MARK

出0入0汤圆

发表于 2012-1-26 20:46:56 | 显示全部楼层
路过

出0入300汤圆

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

本版积分规则

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

GMT+8, 2024-8-27 14:15

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

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