编码器
编码器工作原理
编码器是一种将角位移或者角速度转换成一串电数字脉冲的旋转式传感器。分为光电编码器和霍尔编码器。
通过在电机的传动轴上加装一个码盘,电机带动码盘转动, 而发射机与接收器成一对:
- 当光线穿过码盘孔的时候,接收器收到高电平
- 当光线被码盘阻断的时候,接收器收到低电平
定义从低电平变为高电平的那一瞬间(时刻)叫作上升沿;从高电平变为低电平的那一瞬间(时刻)叫作下降沿。由此,通过计算单位时间内的上升沿次数、下降沿次数并用其除以码盘的孔数就可以计算出电机转速。为提高精度,通常同时获得上升沿、下降沿次数并求取平均值后进行计算。
常用的霍尔编码器也称AB相编码器,它通过电路信号的变化来获取电机的转速,为了得到电机转动的方向,此类编码器通过两个相近的发射器、接收器(A相、B相)同时接收信号值:
引脚配置
博主所用的编码器电机型号为JGB37-520,其减速比为30F
1.引脚查询
博主所用开发版上封装了四个六线编码器电机接口,以电机接口MOTORA为例,学习如何使用编码器。
- AOUT1、AOUT2(1、6引脚)连接电机驱动TB6612FNG,用于控制电机正反转
- 2、5引脚分别接GND和VCC,用于编码器供电
- PB3、PA15(3、4引脚)为编码器AB相,用于获取编码器数据。
2.设置引脚
打开CubeMX,设置编码器引脚。点击PB3引脚可以发现存在TIM2_CH2定时器通道,而PB15存在TIM2_CH1定时器通道。由此,我们可以设置2号定时器为编码器模式进行编码器数据的读取。
点击上方Pinout&Configuration子页面并点击左侧Timers选项卡,选择TIM2并将Combined Channels设置为Encoder Mode,此时默认将设置引脚PA0和PA1为定时器模式,需要点击PB3设置为TIM2_CH2,同时PB15将自动设置为TIM2_CH1。
随后,点击界面下方Parameter Settings将Encoder Mode设置为Encoder Mode TI1 and TI2,即表示同时检测上升沿和下降沿。
随后开启编码器所在定时器的中断,旋转下方菜单NVIC Settings并勾选Enable。
3.开启定时器中断
为保证编码器能够不断的读取信息,需要额外开启一个定时器,采用设置频率进行中断执行。选中3号定时器,进行如下设置:
- Clock Source:Internal Clock
- 分频频率:7200 - 1
- 计数周期:100 - 1
- auto-reload preload:Enable
即设置一个周期为10ms的定时器中断,随后再NVIC Settings选项下勾选Enable,开启中断。
4.中断优先级
由于编码器中断必须在定时器10ms中断内发送,故而编码器中断优先级高于定时器中断。在上方选项卡中确保页面在Pinout&Configuration子页面,选择左侧System Core选项卡下NVIC选项并将TIM3定时器优先级设置为1。
设置完成后,点击右上角GENERATE CODE重新生成代码。
代码编写
1.读取编码器数值
首先需要启动定时器并读取编码器数据,
HAL_TIM_Encoder_Start(&htim2,TIM_CHANNEL_1|TIM_CHANNEL_2);
随后,获取编码器的数据值。数据为正表示正转,数据为反表示反转。
short i = __HAL_TIM_GET_COUNTER(&htim2);
在计算电机转速时,通常采用一小段时间内(瞬间)编码器的累加值来估算,故而需要在读取完成后,将定时器清零处理。
__HAL_TIM_SET_COUNTER(&htim2,0);
2.定时器中断设置
采用函数HAL_TIM_Base_Start_IT()开启定时器中断
/**
* @brief Starts the TIM Base generation in interrupt mode.
* @param htim TIM Base handle
* @retval HAL status
*/
HAL_StatusTypeDef HAL_TIM_Base_Start_IT(TIM_HandleTypeDef *htim)
- 参数 *htim:指针,定时器名
开启中断需要重写中断函数 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
3.电机转速获取
对所得编码器数据(信号数)做如下处理:
-
由于同时监听上升沿和下降沿,需要将信号数除以2
-
由于编码器存在AB相,即有两个收发器,需要将信号数除以2
-
所得平均信号数应除以编码器码盘上的孔数
-
电机存在减速比,需要除以电机减速比
-
上述数据处理后,所得为电机的旋转圈数
博主手上的电机减速比为30,编码器孔数为13,故而计算公式如下:
圈数 = 信号数 / 2 / 2 / 13 / 30
转速 = 圈数 * 测量频率
经过上述分析,最终代码如下:
/* USER CODE BEGIN 2 */
// 开启AB相编码器定时器
HAL_TIM_Encoder_Start(&htim2, TIM_CHANNEL_1|TIM_CHANNEL_2);
// 开启定时器3中断
HAL_TIM_Base_Start_IT(&htim3);
/* USER CODE END 2 */
/* USER CODE BEGIN 4 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
static unsigned char i = 0;
// 3号定时器中断
if(htim == (&htim3))
{
// 设置测量频率为100Hz(10ms)
int rate = 100;
// 获取编码器信号数
short encoder = __HAL_TIM_GET_COUNTER(&htim2);
// 计算圈数rpm
float count = ((float)encoder) / 2 / 2 / 13 / 30;
// 编码器数据清零
__HAL_TIM_SET_COUNTER(&htim2, 0);
// 计算转速
float speed = count * rate;
// 扩大100倍输出
log("speed:%d", (int)(speed) * 100);
}
}
/* USER CODE END 4 */