cicnx 发表于 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 state1;
reg state0;
reg 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 DI;
output reg DO;

reg cp_buf;
wire cp_flag;

reg reset_buf;
wire reset_flag;

reg Z_buf;
wire Z_flag;

//同步cp,reset,z 三个信号
always @(posedge Clk)
begin
         cp_buf <= {cp_buf,cp};
         reset_buf <= {reset_buf,reset};
         Z_buf <= {Z_buf,Z};
end
assign cp_flag = cp_buf & cp_buf & !cp_buf;//0->1
assign reset_flag = !reset_buf & reset_buf;        //1->0
assign Z_flag = !Z_buf & Z_buf;        //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
       
测试方法, 接入编码器不停的转动,有正转,也有反转。。。 记位一个位置记下当前的计数器值。
运行一个晚上后。 转回原来标志的位置。
发现计数值不对了! 偏差了很多。。。。

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

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

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

semonpic 发表于 2010-4-26 21:48:41

帮顶,“同步cp,reset,z 三个信号”没看懂

cicnx 发表于 2010-4-28 09:41:39

怎么没有做过相关的处理 吗?

281229961 发表于 2010-4-28 12:33:43

在正反向转动的时候会有误差,长时间有累计误差
你试试每计一个数,就送出显示,反复测试,你会发现在反向的时候就会有一个脉冲的误差

yonghaokeji 发表于 2010-4-28 13:38:32

当有Z脉冲时必须多计数器强制赋值,转动难免会丢失脉冲。这样保证无限多次运转 丢失脉冲不累加!

yonghaokeji 发表于 2010-4-28 13:39:14

你QQ多少加下你!

cicnx 发表于 2010-4-28 14:10:41

QQ: 1291273

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

cicnx 发表于 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); //赋值
          }
}

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

hong_hong789 发表于 2011-10-8 10:47:24

MARK

guozs1984 发表于 2012-1-26 20:46:56

路过

ibmx311 发表于 2012-1-27 05:22:17

always @(posedge clk)//上升沿处理
begin                  
          state0 <= {lnA,lnB};
          state1 <= state0;
          state2 <= state1;
   
          case( {state2,state1} )
         ......
页: [1]
查看完整版本: 正交编码器计数脉冲丢失,从哪下手?