一、编码器测速重要参数
有刷电机编码器参数(其他的后面会慢慢提及,也可以在某宝看)
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);
}
}