基于FPGA的增量式编码器程序设计

1. 简介

增量式编码器(正交编码器),广泛应用于工业自动化和伺服控制系统的位置检测,主要功能是检测转机的旋转位置和速度,实现精确控制。
一般在检测过程中可能会受到工作环境影响,导致编码器输出的脉冲信号产生毛刺,影响计数,进而影响加工、定位精度。
A、B、Z脉冲的关系:正向旋转A和B存在90°的相位差,反向旋转A和B存在-90°的相位差,Z脉冲为0位置。
在这里插入图片描述

2. FPGA实现步骤

通过Verilog语言实现信号的滤波,再对信号进行计数,可以提升信号精度。
步骤如下:

  1. 先对输入信号,两级打拍消除抖动;
always@(posedge clk_200m or negedge rst_n)begin
    if(!rst_n)begin
        positiona_r <= 'd0;
        positionb_r <= 'd0;
        positionz_r <= 'd0;
    end
    else begin
        positiona_r <= {positiona_r[0], positiona};
        positionb_r <= {positionb_r[0], positionb};
        positionz_r <= {positionz_r[0], positionz};
    end
end

在这里插入图片描述2. 然后通过高频采样,滤除毛刺信号;

always@(posedge clk_200m or negedge rst_n)begin
   if(!rst_n)begin
       a_pos <= 'd0;
   end
   else if(~positiona_r[1] && positiona_r[0])begin  // pos
       a_pos <= 1'b1;
   end
   else if(positiona_r[1] && ~positiona_r[0])begin  // neg
       a_pos <= 1'b0;
   end
   else begin
       a_pos <= a_pos;
   end
end

always@(posedge clk_200m or negedge rst_n)begin
   if(!rst_n)begin
       cnt_a <= 'd0;
   end
   else if(~positiona_r[1] && positiona_r[0])begin  // pos
       cnt_a <= 'b0;
   end
   else if(cnt_a >= CNT_DELAY)begin
       cnt_a <= cnt_a ;
   end
   else if(positiona_r[1])begin
       cnt_a <= cnt_a + 1'b1;
   end
end

always@(posedge clk_200m or negedge rst_n)begin
   if(!rst_n)begin
       a_flag <= 'd0;
   end
   else if((cnt_a >= CNT_DELAY) && (~positiona_r[1]))begin  // neg
       a_flag <= 'b1;
   end
   else begin
       a_flag <= 'b0;
   end
end

在这里插入图片描述
3. 通过比较滤波后A、B的高电平位置,确定转动方向;

//对a b的HIGH计数,在同时为高时比较 cnt_a > cnt_b 则顺时钟,反之
always@(posedge clk_200m or negedge rst_n)begin
    if(!rst_n)begin
        frount <= 'd1;
    end
    else if(positiona_r[1] && positionb_r[1] && cnt_a > cnt_b)begin  // 顺时针
        frount <= 'b1;
    end
    else if(positiona_r[1] && positionb_r[1] && cnt_a < cnt_b)begin  // 逆时针
        frount <= 'b0;
    end
    else begin
        frount <= frount;
    end
end
  1. 通过Z信号脉冲确定0位置,对信号计数,确定一周的总脉冲数量;
always@(posedge clk_200m or negedge rst_n)begin
   if(!rst_n)begin
        sys_all <= 'd0;
   end
   else if(z_flag && ~z_flag_r )begin  // 复位
       sys_all <= 'd0;
   end
   else if((a_flag && ~a_flag_r) | (b_flag && ~b_flag_r))begin  // 复位
       sys_all <= sys_all + 1'b1;
   end
   else begin
       sys_all <= sys_all;
   end
end
always@(posedge clk_200m or negedge rst_n)begin
   if(!rst_n)begin
        sys_all_r <= 'd1;
   end
   else if(z_flag && ~z_flag_r )begin  // 寄存
       sys_all_r <= (sys_all >> 1);
   end
   else begin
       sys_all_r <= sys_all_r;
   end
end

在这里插入图片描述

  1. 根据滤波后A、B、Z的脉冲来进行位置计算和速度计算。

3. 位置计算

[当前角度]° = [相对0位置转过的脉冲数量]° x 360.00° / [转一周的总脉冲数量]° 

对360.00° 放大100倍,来提高转动角度的精确计算,即

 degree_r = (sys_cnt<<'d5) + (sys_cnt<<'d7) + (sys_cnt<<'d10) + (sys_cnt<<'d11) +  (sys_cnt<<'d15);
always@(posedge clk_200m or negedge rst_n)begin
    if(!rst_n)begin
        degree_r0 <= 'd0;
    end
    else if(z_flag && ~z_flag_r)begin  // clr
        degree_r0 <= 'd0;
    end
    else if(frount_r)begin  
        degree_r0 <= (sys_cnta<<'d5) + (sys_cnta<<'d15);
    end
    else if(~frount_r)begin  
        degree_r0 <= (sys_cntb<<'d5) + (sys_cntb<<'d15);
    end
end
always@(posedge clk_200m or negedge rst_n)begin
    if(!rst_n)begin
        degree_r1 <= 'd0;
    end
    else if(z_flag && ~z_flag_r)begin  // clr
        degree_r1 <= 'd0;
    end
    else if(frount_r)begin  
        degree_r1 <= (sys_cnta<<'d7) + (sys_cnta<<'d10) + (sys_cnta<<'d11);
    end
    else if(~frount_r)begin  
        degree_r1 <= (sys_cntb<<'d7) + (sys_cntb<<'d10) + (sys_cntb<<'d11);
    end
end
always@(posedge clk_200m or negedge rst_n)begin
    if(!rst_n)begin
        degree_r <= 'd0;
    end
    else if(z_flag && ~z_flag_r)begin  // clr
        degree_r <= 'd0;
    end
    else begin  
        degree_r <= degree_r0 + degree_r1;
    end
end

由于除数是定值,可以通过移位求和,也可以使用IP来除法运算;这里转动一周的总脉冲数量是由转动一周统计出来的,目前不确定总脉冲数量,所以我使用整数除法IP直接得到计算结果。由于,除法一般是DSP处理,所以,可以对除数和被除数先寄存,确保其周期满足除法IP的时序要求。

4. 速度计算

由于速度可能存在加速度,其算法处理过于复杂,且实际场景使用不到,所以博主的速度是单位时间的平均速度,如果转机速度不是匀速,可能计算不准确。

4.1 高速模式

通过计算转动一周用的时间,根据滤波后Z的脉冲上升沿到下一次上升沿,计数转动所用的时间,转速公式:

[当前转速] (r/s)  =  [一秒的拍数] (拍/s)  /  [转一周的拍数] (拍/r)

注: 一秒的拍数,即晶振的频率通过FPGA采样后使用的实际频率;

// 速度     (转)r/s    换方向速度清零  奇数圈和偶数圈分开计数,确保实时性
always@(posedge clk_200m or negedge rst_n)begin
    if(!rst_n)begin
         frount_r <= 'd0;
    end
    else begin
        frount_r <= frount;
    end
end
always@(posedge clk_200m or negedge rst_n)begin
    if(!rst_n)begin
         clr_speed <= 'd0;
    end
    else if((~frount_r && frount) || (~frount && frount_r))begin
        clr_speed <= 'd1;
    end
    else begin
        clr_speed <= 'd0;
    end
end
// 方式一(高速): 转1周,用的时间 sf_cmd[3:0] == 5(HIGH_SPEED) : 6(LOW_SPEED)
always@(posedge clk_200m or negedge rst_n)begin
    if(!rst_n)begin
         one_cycle <= 'd0;
    end
    else if(clr_speed)begin  // clr
        one_cycle <= 'd0;
    end
    else if(z_flag && ~z_flag_r)begin  // z pos
        one_cycle <= one_cycle + 1'b1;
    end
    else begin
        one_cycle <= one_cycle;
    end
end
//one_cycle 拉低计数
always@(posedge clk_200m or negedge rst_n)begin
    if(!rst_n)begin
         one_time_n <= 'd1;
    end
    else if(clr_speed)begin 
        one_time_n <= 'd1;
    end
    else if(one_cycle)begin 
        one_time_n <= 'd1;
    end
    else begin
        one_time_n <= one_time_n + 1'b1;
    end
end
//one_cycle 拉高计数
always@(posedge clk_200m or negedge rst_n)begin
    if(!rst_n)begin
         one_time_p <= 'd1;
    end
    else if(clr_speed)begin 
        one_time_p <= 'd1;
    end
    else if(~one_cycle)begin 
        one_time_p <= 'd1;
    end
    else begin
        one_time_p <= one_time_p + 1'b1;
    end
end

4.2 低速模式

单位时间转动的周数,这里参考时间为50ms,可根据实际需求调整,转速公式:

[当前转速] (r/s)  =  ([50msA、B转动的总脉冲数量 ](个/50ms) x 20) (个/s)  / [总脉冲数量] (个/r)
//cnt_50ms
always@(posedge clk_200m or negedge rst_n)begin
    if(!rst_n)begin
        cnt_50ms <= 'd0;
    end
    else if(clr_speed)begin  // clr
        cnt_50ms <= 'd0;
    end
    else if(cnt_50ms == 'd10_000_000)begin  // clr
        cnt_50ms <= 'd0;
    end
    else begin
        cnt_50ms <= cnt_50ms + 1'b1;
    end
end
//circle
always@(posedge clk_200m or negedge rst_n)begin
    if(!rst_n)begin
        circle <= 'd0;
    end
    else if(clr_speed)begin  // clr
        circle <= 'd0;
    end
    else if(cnt_50ms == 'd9_999_999 )begin  // 复位
        circle <= 'd0;
    end
    else if((a_flag && ~a_flag_r) | (b_flag && ~b_flag_r))begin  // 
        circle <= circle + 1'b1;
    end
    else begin
        circle <= circle;
    end
end

由于转速太低时,转动一周时间太长,使用方式一,速度计算的反馈延时太长;在速度过高时,单位时间采样数量较大,通过计算一周的转动时间稳定性更高,所以转速>=5r/s使用方式一,转速<5r/s使用方式二。

//速度选择,   >=5.00r/s:高速 speed_rh,   <5.00r/s:低速 speed_rl   
always@(posedge clk_200m or negedge rst_n)begin
    if(!rst_n)begin
        speed_tmp <= 'd0;
    end
    else if(speed_tmp < 'd500)begin  
        speed_tmp <= speed_rl ;
    end
    else begin  
        speed_tmp <= speed_rh ;
    end
end

黄色为速度放大了100倍,即实际为49.99(r/s),紫色为位置角度也放大了100倍,即当前位置为356.40°。
在这里插入图片描述

5. Modelsim仿真

在这里插入图片描述

最后,测试时可通过将数据每隔500ms寄存一次位置和速度信息,通过串口发送到上位机,观察其准确度。

:完整工程和仿真程序放资源里面了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值