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

发布于:2025-07-04 ⋅ 阅读:(21) ⋅ 点赞:(0)

一、编码器测速重要参数

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

        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);
		
	}

}