打印
[活动专区]

【杰发科技AC7802x测评】4.基于AC7802正交编码实现电机测速

[复制链接]
201|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 GrootBrain 于 2023-6-3 20:55 编辑

#有奖活动# #申请原创#
基于AC7802正交编码实现电机测速


正交编码器测速原理
正交编码器是一种通过旋转或移动测量运动位置和速度的传感器。它通常由两个光学传感器(A相和B相)组成,每个传感器的输出波形完全相同,但相位相位差90度(即正交)。当物体被旋转或移动时,两个波形将发生同步变化,使得编码器可以确定方向和速度。
具体而言,在实际应用中,编码器的A和B两条输出线和中心的接地线连接到计数器或控制器电路中。计数器对A和B两种输信进行脉冲计数,并根据两条线之间的相对时间差确定运动速度和方向。如果传感器被旋转,每旋转一次会产生一定数量的脉冲,可以通过这些脉冲来计算旋转角度。




从上来看,以通道A的下降沿作为起始位置:
顺时针是01->00->10->11,也就是10进制的1-0-2-3
逆时针是00->01->11->10,也就是10进制的0-1-3-2
因此,只要知道计数规律,就知道是往哪个方向在转,计算脉冲的频率,就是旋转速度。

AC7802的正交解码功能
AC7802的PWM带正交解码功能,模块的通道0接phase A, 模块的通道1接phase B。7802正对正交编码进行正确记数。


AC7802的正交编码测速方案
硬件接口:
PB0,使用PWM1_CH1功能,用作编码器的phase A输入;
PB1,使用PWM1_CH2功能,用作编码器的phase B输入;
PWM1模块用于正交编码计数。phase A或phase B边沿跳变时计时器加1。正转时计数器增加,反转时计数器减少。


速度计算:
本实验中使用编码器是11线编码器,也就是电机转一圈,A/B两相分别输出11个脉冲,每个脉冲都使解码数值增加的话,电机转一圈是44个脉冲。
本实验电机的输出轴减速比是4.4,也就是电机转4.4圈,电机输出轴才会转一圈。也就是说。输出轴转一圈,脉冲计数器变化11*4*4.4=193.6个脉冲。
本实验每20ms计算一次转速,计算前200ms内转速,假如脉冲数变化为N,则转速rpm(转/分钟)
rpm=[ (N/193.6)  /  (  200 / 1000 ) ] * 60

AC7802的正交编码测速编程
测速模块提供初始化接口,速度计算接口以及获取速度接口。
void speed_check_init( void );
void speed_check_task( void );
float speed_check_get_Revolutions_Per_Minute( void );

速度初始化接口speed_check_init(), 用于调用下层正交编码器初始化
void speed_check_init( void )
{
    PWM_quadrature_decode_init();
}

速度计算接口speed_check_task(),用于计算转速,必须周期性调用,这里的调用周期是20ms
static void SpeedMeter(int currentPulse)
{
    int deltaPulse = 0;
    uint8_t i;

    for ( i=0; i < (SPEED_METER_BUF_LEN-1) ; ++i ) {
        g_pulseRecordTbl[i] = g_pulseRecordTbl[i+1];
    }
    g_pulseRecordTbl[SPEED_METER_BUF_LEN-1] = currentPulse;

    deltaPulse = g_pulseRecordTbl[SPEED_METER_BUF_LEN-1] - g_pulseRecordTbl[0];

    if ( -QUAD_CHANGE_NUMBER_MAX_IN_CALC_CYCLE > deltaPulse ) {
        // inc pass 0
        deltaPulse += (QUAD_ENCODER_NUM_MAX + 1);
    } else if ( deltaPulse > QUAD_CHANGE_NUMBER_MAX_IN_CALC_CYCLE ) {
        // dec pass 0
        deltaPulse -= (QUAD_ENCODER_NUM_MAX + 1);
    }

    SPEED_TASK_ENTER_CRITICAL();
    g_MoterSpeedRPM = deltaPulse / QUAD_ENCODER_NUMBER_IN_A_CYCLE / (SPEED_METER_CYCLE * (SPEED_METER_BUF_LEN-1)/1000.0f) * 60;
    SPEED_TASK_EXIT_CRITICAL();
}


void speed_check_task(void)
{
    SpeedMeter( PWM_quadrature_decode_get_val() );
}

获取速度接口speed_check_get_Revolutions_Per_Minute(),给外部提供计算后的转速获取接口,正负值表示方向
float speed_check_get_Revolutions_Per_Minute( void )
{
    float speed = 0.0f;

    SPEED_TASK_ENTER_CRITICAL();
    speed = g_MoterSpeedRPM;
    SPEED_TASK_EXIT_CRITICAL();

    return speed;
}



测速模块会调用下层模块,下层模块提供编码器的初始化和获取编码器数值接口
void PWM_quadrature_decode_init( void );
uint32_t PWM_quadrature_decode_get_val( void );

正交编码器初始化接口PWM_quadrature_decode_init(), 完成PWM底层寄存器配置,端口配置
void PWM_quadrature_decode_init( void )
{
    PWM_ConfigType config;
    PWM_QuadDecodeConfigType quadDecodeConfig;
    PWM_QuadPhaseConfigType quadPhaseAConfig, quadPhaseBConfig;

    memset(&config, 0U, sizeof(config));
    memset(&quadDecodeConfig, 0U, sizeof(quadDecodeConfig));
    memset(&quadPhaseAConfig, 0U, sizeof(quadPhaseAConfig));
    memset(&quadPhaseBConfig, 0U, sizeof(quadPhaseBConfig));

    GPIO_SetFunc(GPIOB, GPIO_PIN0, GPIO_FUN2);  /* PB0--PWM1_CH1.该引脚只在32pin封装上有 */
    GPIO_SetFunc(GPIOB, GPIO_PIN1, GPIO_FUN2);  /* PB1--PWM1_CH0,该引脚只在32pin封装上有.*/

    GPIO_SetPullup(GPIOB, GPIO_PIN0, ENABLE); /*使能上拉*/
    GPIO_SetPullup(GPIOB, GPIO_PIN1, ENABLE); /*使能上拉*/


    /*通道配置*/
    quadPhaseAConfig.polarity = PWM_QUAD_PHASE_NORMAL;  /*A相输入极性为正常极性。*/
    quadPhaseAConfig.filterEn = DISABLE;                /*A相滤波器去能*/
    quadPhaseAConfig.filterVal = 0;                     /*滤波值*/
    quadPhaseBConfig.polarity = PWM_QUAD_PHASE_NORMAL;  /*B相输入极性为正常极性。*/
    quadPhaseBConfig.filterEn = DISABLE;                /*B相滤波器去能*/
    quadPhaseBConfig.filterVal = 0;                     /*滤波值*/
    quadDecodeConfig.mode = PWM_QUAD_PHASE_ENCODE;      /*A相和B相编码模式*/
    quadDecodeConfig.phaseAConfig = quadPhaseAConfig;   /*A相配置赋值*/
    quadDecodeConfig.phaseBConfig = quadPhaseBConfig;   /*B相配置赋值*/
    quadDecodeConfig.quadEn = ENABLE;                   /*正交解码使能*/

    /*PWM模块配置*/
    config.mode = PWM_MODE_QUADRATURE_DECODER;          /*PWM模块配置为正交解码模式*/
    config.initModeStruct = &quadDecodeConfig;          /*正交解码配置赋值*/
    config.clkSource = PWM_CLK_SOURCE_APB;              /*PWM时钟源配置*/
    config.clkPsc = 0;                                  /*PWM时钟源分频*/
    config.initValue = 0;                               /*计数器初始寄存器值*/
    config.maxValue = PULSE_PER_REVOLUTION - 1;         /*PWM计数器最大值*/
    config.overflowInterrupEn = DISABLE;                /*计数器溢出中断使能*/
    config.cntOverflowFreq = 0;                         /*CNTOF中断产生的频率与计数器频率的关系(0-127), 0表示每次计数器溢出都产生溢出中断,1表示间隔1次,2表示间隔2次,以此类推。*/
    config.interruptEn = DISABLE;                       /*PWM中断使能*/
    config.callBack = NULL;                             /*PWM中断回调*/
    PWM_Init(QUAD_PWM_MODULE, &config);                 /*配置初始化生效*/
}


正交编码器数值获取接口PWM_quadrature_decode_get_val(),给上层接口提供获取数值的方法
uint32_t PWM_quadrature_decode_get_val( void )
{
    uint32_t counter = QUAD_PWM_MODULE->CNT & 0xFFFF;

    return counter;
}


将速度计算功能嵌入到电机任务中
void motor_Task( void *pvParameters )
{
    pvParameters = pvParameters;

    adc_motor_ctrl_input_init();
    PWM_motor_ctrl_output_init();
    speed_check_init();

    while (1) {
        PWM_motor_ctrl_ouput_duty_val( adc_motor_ctrl_get_adc_Val() );
        
        speed_check_task();

        vTaskDelay( pdMS_TO_TICKS(20) );
    }
}


在printTask输出电机转速数值
void printf_Task( void *pvParameters )
{
    pvParameters = pvParameters;

    InitDebug();

    while (1) {
        //printf( "Hi,I'm a small chip, AC7802.\r\n");
        printf("speed(rpm) = %d\r\n", (int)speed_check_get_Revolutions_Per_Minute() );
        vTaskDelay( pdMS_TO_TICKS(1000) );
    }
}


测试
正转

反转:

结论:电机测速与电机标定值相符,且能计算出电机转动方向。

测试工程
测试工程在linux环境下编译,基于freeRTOS开发。
AC7802_FreeRTOS_motor_speed_meter.zip (1.56 MB)




使用特权

评论回复

相关帖子

发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

17

主题

87

帖子

2

粉丝