【嵌入式电机控制#8】编码器测速实战

【嵌入式电机控制#8】编码器测速实战

一、编码器测速重要参数

有刷电机编码器参数(其他的后面会慢慢提及,也可以在某宝看)

1. 编码器分辨率(PPR)

2. 编码器工作电压

3. 电机减速比 例如 30:1 指的就是电机减速轴转1圈,编码器转30圈。

注意明确一个关系,大部分直流减速电机的机械结构,是编码器套在主轴,而电机轴是经过机械传动减速后转动的,所以我们把这类电机叫做减速电机。

参数1和3到底有什么用呢?

举个栗子,我们的编码器在VOFA上的测速结果为300RPM,而编码器接口配置为100方式计数,即四倍频,那么:

电机减速转速 = 主轴转速 / 减速比

= 编码器转速 / 减速比

= (计数器接收脉冲个数 / 四倍频 / PPR / 减速比)* 测速中断频率

实际代码中,还需要考虑时间单位s->min的换算

二、Encoder的HAL库函数

(1)HAL_TIM_Encoder_Init()

初始化定时器基础参数,以及编码器接口,如果用的是Cube则不需要编写。

(2)HAL_TIM_Base_Start_IT()

定时器外设若需要使用中断功能(比如编码本身和编码过程中断回调处理),则必须提前使能定时器base中断。

(3)HAL_TIM_Encoder_Start()

开启编码器接口通道,与PWM_start有异曲同工之妙。

(4)定时器更新中断回调函数

有两种处理方式,一种是单定时器中断,通过使用encoder本身的更新中断,当计数值达到ARR时候,自动进入中断处理测量的脉冲数。

第二种是Encoder中断+其他定时器中断,通过其他定时器预设定的中断频率,来对速度采样频率进行自由的改动,不受编码器采样频率的限制,但如果中断频率设置过高会造成严重误差。

(5)__HAL_TIM_IS_COUNTING_DOWN()

在无CubeMX时,用于读取DIR位,进而判断计数方向。

有Cube时,直接判断编码器反馈数值的正负。

三、Encoder的定时器配置

(1)配置编码器模式

TI1与TI2都检测,也就是四倍频

(2)配置Encoder双输入通道参数

理论上两个通道参数应该一致。

因为是100法计数,根据功能表规则,我们的计算规则应该是上升沿有效,所以边沿极性选择为上升沿。

IC采用直接选择

分频因子不分频,如果分频了,那我们何必用四倍频呢?

接下来,输入滤波器可以暂时先设置为10。它起到一个什么作用呢?

通俗的讲,它把一个电平信号扫描十次,然后判断是否有高低反转的不稳定情况,如果信号不稳定,则丢弃这一帧。

实际上,它是一个低通滤波器,对高频干扰信号做衰减。你的参数设置的越大,它扫描次数越多,过滤高频尖刺的能力也就更强,但芯片工作量也会随之增加。(滤波过程可以近似参考模拟线路的0.1uF的RC滤波器。图画的可能不标准,具体内容请见隔壁DSP)

(3)中断方法1:Encoder更新中断

我的这款主控找不到Encoder更新中断开启,可能是因为Cube封装了Encoder的更新中断的总计数值更新过程,如果要找得去ISR文件看看,下面介绍另外一种方法。

(4)中断方法2:另开定时器进行中断

为了节省资源,我选了基本定时器做定时器中断。

这里设置中断频率为10Hz,也就是0.1s中断一次,对于我自己的外设来说效果比较理想,实际工程中需要不断调试 中断频率 和 PWM的ARR 去测试它的开环测量准确度。

四、实战例程

(1)使能中断功能并开启编码器

虽然我们没手写编码器的ISR,但是我们还是需要它的中断测量总计数值,它没有被禁用只是在后台默默的为我们计数。

HAL_TIM_Base_Start_IT(&htim6);

HAL_TIM_Base_Start_IT(&htim2);

HAL_TIM_Encoder_Start(&htim2, TIM_CHANNEL_ALL);

我们使用GetCounter函数来一段时间内的获取编码值,获取完立刻清零,不能放在其他位置,否则会因为其他轮询代码的运行造成结果偏小的误差(我们下一次中断还要用!)

至于转速查看的方法,我不建议用串口打印,因为它背后调用了stdio库,运行速度肯定没有VOFA+的float协议来的快。

VOFA+的标准用法,我会在补充章节分享。

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){

if(htim==&htim6){

printf("entered");

int16_t val = (int16_t)__HAL_TIM_GetCounter(&htim2);

__HAL_TIM_SET_COUNTER(&htim2, 0);

float RPM =(float)((val/7.0/50.0/4.0)*600);

Vofa_data(RPM);

// printf("RPM: %.3f \r \n",RPM);

// __HAL_TIM_SetCompare(&htim1, TIM_CHANNEL_1,BINMotor_SpeedtoPulse(BACK,L_AddPID.pwm_add));

dc_motor_pwmset(RPM,&spdPID);

}

}

相关推荐