FPGA实现电机霍尔编码器模块

一. 简介

想要知道直流电机的转速,就需要用到编码器,常用的编码器有霍尔和光电两种,但是光电编码器比较贵(性能好于霍尔),所以平常的时候使用最多的是霍尔编码器了。

霍尔编码器一般有AB两相信号输出,默认的时候为低电平,当电机转动的时候,AB两相会输出具有一定相位差的脉冲,根据相位差可以确定电机旋转的方向,另外根据单位时间内,脉冲的数量可以确定电机的转速(线数X(编码器参数):电机旋转一圈产生的脉冲数,减速电机有一个减速比Y(Y越大,扭矩越大,负载转速越小),也就是说负载(一般为轮胎)旋转一圈所产生的脉冲数为: X * Y)。AB输出的脉冲波形如下

请添加图片描述

编码器的使用方法如上,非常简单,下面就用FPGA来写一个编码器模块吧!

二. 编码器模块架构

首先,需要明确一下,编码器模块需要实现那些功能,经过简单的思考,可以确定要实现的功能如下,其中加速度不是必须的。
请添加图片描述

功能确定了之后,就可以简单设计一下框图如下,根据框图可以很清晰来编写各个模块了。

请添加图片描述

三.定时器模块

定时器模块的功能非常简单。就是每隔一段时间产生一个触发信号,用来清除脉冲计数 和 计算一次速度与加速度。我这里是设置的5ms触发一次,具体多少时间触发一次合适,可以根据实际的测试效果而定。

四. 编码器脉冲检测模块

该模块的主要功能是用来检测AB两相的脉冲并且判断脉冲的方向。一共有两种方法来检测:

  1. 单边沿检测 : 检测AB某一相的A沿,然后判断另外一相的电平。例如检测A相的上升沿为有效脉冲,然后判断B相的电平为电机旋转方向。该方法非常简单,但是抗干扰能力并没有那么强,容易误判。
  2. 四边沿检测 : 依次检测每一个边沿,如果四个边沿均满足要求,则该脉冲为有效脉冲,否则为无效脉冲。该方法抗干扰能力比较强,但逻辑上稍微有点点复杂相较于第一种方法来说。

两种方法的实现,对于FPGA来说,不是什么难事,第一种就不提了;第二种方法的话,一个状态机就可以了,在对应的状态里面检测一相的边沿信号和另外一相的电平,两相都满足的话,就跳到下一个状态,四个状态均满足的话,则输出一个有效电平,否则的话,均回到初始状态。本次使用的是一段式状态机,代码片段如下(两个状态)。

always@(posedge sys_clk_i or negedge sys_rst_n_i) begin
    if( sys_rst_n_i == 1'b0 ) begin
        step <= 6'b00_0000;
        encoder_AB_detect_dir_reg <= 1'b0;
    end
    else begin
        case (step)
        6'b00_0000: begin                 //处理第一个边沿
            if( (encoder_A_posedge  | encoder_B_posedge) && encoder_AB_detect_en_i == 1'b1)  
                step <= 6'b00_0001;
            else
                step <= step;
        end
        6'b00_0001: begin  //处理第二个边沿
            if( encoder_A_posedge == 1'b1)
                if( encoder_B_d0 == 1'b1) begin
                    step <= 6'b00_0100;
                    encoder_AB_detect_dir_reg <= 1'b0; //在第二个边沿的时候,确定旋转方向
                end
                else
                    step <= 6'b00_0000;
            else if( encoder_B_posedge == 1'b1)
                if( encoder_A_d0 == 1'b1) begin
                    step <= 6'b00_0010;
                    encoder_AB_detect_dir_reg <= 1'b1; //在第二个边沿的时候,确定旋转方向
                end
                else
                    step <= 6'b00_0000;
            else if( encoder_A_negedge | encoder_B_negedge)   //检测到下降沿 表示错误 
                step <= 6'b00_0000;
            else  
                step <= step;  //需进行超时处理
        end

然后模块的信号如下,

module encoder_AB_detect(
    input              sys_clk_i                ,
    input              sys_rst_n_i              ,
    
    input              encoder_AB_detect_en_i   ,       //编码器检测使能
    output             encoder_AB_detect_valid_o,       //编码器检测有效输出
    output             encoder_AB_detect_dir_o  ,       //编码器检测方向输出
    //硬件编码器输入
    input              motor_encoder_A_i        ,      //编码器A相输入
    input              motor_encoder_B_i               //编码器B相输入
);

五. 脉冲计数模块

计算脉冲数,由于电机在朝一个方向转动的时候,可能会由于不确定因数的影响,产生另外一个方向的脉冲,所以在计算的时候需要对其进行处理。

分别计数两个方向的脉冲数,以脉冲数多的方向为当前方向,多的脉冲数 减去 少的脉冲数 为当前方向的脉冲数。

assign encoder_Phase_count_dir_o = ( encoder_Phase_Cnt_dir0 > encoder_Phase_Cnt_dir1 ) ? 1'b0 : 1'b1;
assign encoder_Phase_count_o     = ( encoder_Phase_Cnt_dir0 > encoder_Phase_Cnt_dir1 ) ? (encoder_Phase_Cnt_dir0 - encoder_Phase_Cnt_dir1): 
                                                                                         (encoder_Phase_Cnt_dir1 - encoder_Phase_Cnt_dir0);

//编码器脉冲计数
always@(posedge sys_clk_i or negedge sys_rst_n_i) begin
    if( sys_rst_n_i == 1'b0) begin
        encoder_Phase_Cnt_dir0 <= 16'd0;
        encoder_Phase_Cnt_dir1 <= 16'd0;
    end
    else if( encoder_Phase_count_clear_i == 1'b1 ) begin  //定时器输入,重新开始计数
        encoder_Phase_Cnt_dir0 <= 16'd0;
        encoder_Phase_Cnt_dir1 <= 16'd0;
    end
    else if( encoder_AB_detect_valid_i == 1'b1 )  //对两个方向的脉冲分别计数
        if( encoder_AB_detect_dir_i == 1'b0 ) begin
            encoder_Phase_Cnt_dir0 <= encoder_Phase_Cnt_dir0 + 1'b1;
            encoder_Phase_Cnt_dir1 <= encoder_Phase_Cnt_dir1;
        end
        else begin
            encoder_Phase_Cnt_dir0 <= encoder_Phase_Cnt_dir0;
            encoder_Phase_Cnt_dir1 <= encoder_Phase_Cnt_dir1 + 1'b1;   
        end
    else begin
        encoder_Phase_Cnt_dir0 <= encoder_Phase_Cnt_dir0;
        encoder_Phase_Cnt_dir1 <= encoder_Phase_Cnt_dir1;
    end
end

六. 速度与加速度检测模块

当定时器信号输入时,根据脉冲计数模块输入的脉冲数来计算。速度的单位为 圈数/分钟,而检测周期为5ms,所以RPM = 圈数 *( 1分钟 / 5ms ),然后这里使用的编码器为500线,电机的减速比为20,所以一圈对应的编码器脉冲数为500 * 20 = 10000 ,所以最终RPM = ( 脉冲数 / 10000) * ( 1分钟 / 5ms) = 1.2 * 脉冲数。 为了便于计算将RMP扩大10倍, 即 RPM = 12 * 脉冲数 = ( 8 + 4) * 脉冲数。将脉冲数左移3位 加速 脉冲数左移2位 即可。

加速度就更加简单了,只需要将当前速度 减去 上一时刻的速度 即可,加速度有方向,还需要判断一下加速度方向。

assign encoder_speed = ( encoder_Phase_count_i << 3 ) + ( encoder_Phase_count_i << 2 );
always@( posedge sys_clk_i or negedge sys_rst_n_i ) begin
    if( sys_rst_n_i == 1'b0 ) begin
        encoder_speed_d0 <= 16'd0;
        encoder_speed_o  <= 16'd0;
        encoder_acc_o    <= 16'd0;
        encoder_acc_dir_o<= 1'b0;
    end
    else if( cal_en_i == 1'b1 ) begin
        encoder_speed_d0 <= encoder_speed_o;
        encoder_speed_o  <= encoder_speed;
        encoder_acc_o    <= (encoder_speed > encoder_speed_d0) ? encoder_speed - encoder_speed_d0 : encoder_speed_d0 - encoder_speed;
        encoder_acc_dir_o<= (encoder_speed > encoder_speed_d0) ? 1'b1 : 1'b0;
    end
    else begin
        encoder_speed_d0 <= encoder_speed_d0;
        encoder_speed_o  <= encoder_speed_o;
        encoder_acc_o    <= encoder_acc_o;
        encoder_acc_dir_o<= encoder_acc_dir_o;
    end
end

七. 角度检测模块

当需要旋转对应角度的时候,就需要对其旋转角度进行检测。旋转一圈,对应的脉冲数为10000,所以每个脉冲数对应的角度为0.036°,为了便于计算,这里将角度扩大10倍,每个脉冲数对应的角度就变成了0.36°,每5个脉冲数对应的角度就变成了1.8°,这样以5个脉冲数为一个脉冲单位,所以每一个脉冲单位角度就变化了1°,先不管0.8°,而0.8 * 5 = 4°,所以每5个脉冲单位角度就变化了4°,这样就非常方便计算了,当是会有一定的误差,最大误差角度约为: 3.2° + 1° = 4.2°,即实际误差角度为0.42°,还是可以接受的。

always@(posedge sys_clk_i or negedge sys_rst_n_i ) begin
    if( sys_rst_n_i == 1'b0 )
        encoder_num_angle_o <= 20'd0;
    else if( encoder_accumulate_clr_i == 1'b1)
        encoder_num_angle_o <= 20'd0;
    else if( encoder_accumulate_en_i == 1'b1 && encoder_AB_detect_valid_i == 1'b1 )
        if( encoder_AB_Angle_Cnt1 == 'd4 )
            encoder_num_angle_o <= encoder_num_angle_o + 'd4 + 'd1;
        else if( encoder_AB_Angle_Cnt == 'd4)
            encoder_num_angle_o <= encoder_num_angle_o + 1'b1;
        else    
            encoder_num_angle_o <= encoder_num_angle_o;
    else
        encoder_num_angle_o <= encoder_num_angle_o;
end

八. 小结

现在一个简单的编码器模块,就写完啦,算是一个基础版本吧,后面会根据需求进行完善。

需要完整模块文件的话关注gzh FPGA之旅 可以回复 编码器1.0 获取

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
基于FPGA的增量式编码器是一种使用可编程逻辑器件FPGA实现编码器。增量式编码器主要用于测量转动物体的运动状态,其中包括转速和转角。传统的增量式编码器由光电传感器和计数器组成,但该方案存在灵敏度低、接线复杂等问题。 基于FPGA的增量式编码器通过将传感器信号与FPGA芯片相连接,利用FPGA的灵活性和高度可编程性,实现了更高的灵敏度和更简化的接线。具体来说,FPGA通过配置其内部的逻辑门和寄存器等元件,将传感器信号转化为数字信号,并进行信号处理和计算。 在编码器的设计中,FPGA可以根据需要实现多种不同的编码方式,如A相正交编码、2位相位编码等。同时,FPGA还能够处理编码器的输出信号,对其进行计数和解码等操作。通过FPGA的功用,增量式编码器的性能和功能得到了极大的增强,能够满足更高精度、更复杂的应用需求。 此外,基于FPGA的增量式编码器具有较高的可扩展性和灵活性。由于FPGA的可编程性,编码器的功能可以随时根据需要进行升级和修改。同时,FPGA具有较强的实时性和并行计算能力,能够实时响应传感器的输入信号,并进行即时计算和反馈。 总之,基于FPGA的增量式编码器利用FPGA的可编程特性和高性能计算能力,实现了更高灵敏度和更灵活的设计。它在各种转动物体测量领域都具备广泛的应用前景,并能够满足不同应用场景对编码器性能和功能的需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FPGA之旅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值