正交编码器计数脉冲丢失,从哪下手?
用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
测试方法, 接入编码器不停的转动,有正转,也有反转。。。 记位一个位置记下当前的计数器值。
运行一个晚上后。 转回原来标志的位置。
发现计数值不对了! 偏差了很多。。。。
如果短时间运行, 偏差分辨不出来。。。 长时间后累积多了就看到了。
估计是正反变换时丢失了某些脉冲没有记数!
请大家帮分析一下从什么地方下手才可以提高可靠性? 帮顶,“同步cp,reset,z 三个信号”没看懂 怎么没有做过相关的处理 吗? 在正反向转动的时候会有误差,长时间有累计误差
你试试每计一个数,就送出显示,反复测试,你会发现在反向的时候就会有一个脉冲的误差 当有Z脉冲时必须多计数器强制赋值,转动难免会丢失脉冲。这样保证无限多次运转 丢失脉冲不累加! 你QQ多少加下你! QQ: 1291273
我是计数的时候立即显示出来的。 用手转动脉冲没有少。 如200一卷的编码器,4倍频后是800 我试过转过800就归0的。。 只是在连续运转几个小时或1天就开始感觉到偏了。。。
我在CPU用一中断脚接受 Z 的中断。 在中断中判断是否为 800 的整数, 正常来说每发生一次 Z 计数值应该是 800的整数倍。
用手短时转动都是正确的。 当放到设备上连续工作就慢慢发现在Z相到来时已经偏了这个 800 的倍数! 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); //赋值
}
}
编辑原因: 复制过来的代码缩进不见了! MARK 路过 always @(posedge clk)//上升沿处理
begin
state0 <= {lnA,lnB};
state1 <= state0;
state2 <= state1;
case( {state2,state1} )
......
页:
[1]