编码器介绍与应用

一.概述

1.编码器

编码器,是一种用来测量机械旋转或位移的传感器。这种传感器能够测量机械部件在旋转或直线运动时的位移位置或速度等信息,并将其转换成一系列电信号。其可和电机组装到一起用,反馈电机方向、转换角度的,然后电机根据反馈再动作纠偏,提升精度。

编码器是工业中常用的传感器之一,广泛应用于工业生产当中需要对机械系统进行监视或控制的场景,包括工业控制、机器人、照相机镜头、雷达平台以及部分计算机输入设备例如轨迹球和鼠标滚轮等等。

2.增量型编码器

增量型编码器是能够根据旋转运动产生信号的编码器,其刻度方式为每一个脉冲都进行增量计算,因此得名。

增量式旋转编码器是将设备运动时的位移信息变成连续的脉冲信号,脉冲个数表示位移量的大小。只有当设备运动的时候增量式编码器才会输出信号。编码器一般会把这些信号分为通道 A

和通道 B 两组输出,并且这两组信号间有 90° 的相位差。同时采集这两组信号就可以知道设备的运动和方向。除了通道 A、通道 B 以外,很多增量式编码器还会设置一个额外的通道 Z 输出信

号,用来表示编码器特定的参考位置,传感器转一圈 Z 轴信号才会输出一个脉冲。增量式编码器只输出设备的位置变化和运动方向,不会输出设备的绝对位置。

3.增量编码器结构

增量型编码器由一个中心有轴的光电码盘,其上有环形通、暗的刻线,有光电发射和接收器件读取,获得四组正弦波信号组合成A、B、C、D,每个正弦波相差90度相位差(相对于一个周波为360度),将C、D信号反向,叠加在A、B两相上,

可增强稳定信号;另每转输出一个Z相脉冲以代表零位参考位。由于A、B两相相差90度,可通过比较A相在前还是B相在前,以判别编码器的正转和反转,通过零位脉冲,可获得编码器的零位参考位。

分辨率―编码器以每旋转360度提供多少的通或暗刻线称为分辨率,也称解析分度、或直接称多少线,一般在每转分度5~10000线。

4.编码器基本参数

分辨率:

指编码器能够分辨的最小单位。对于增量式编码器,其分辨率表示为编码器转轴旋转一圈所产生的脉冲数,即脉冲数/转 (Pulse Per Revolution 或 PPR)。码盘上透光线槽的数

目其实就等于分辨率,也叫多少线,较为常见的有 5-6000 线。对于绝对式编码器,内部码盘所用的位数就是它的分辨率,单位是位 (bit),具体还分单圈分辨率和多圈分辨率。

精度:

首先明确一点,精度与分辨率是两个不同的概念。精度是指编码器每个读数与转轴实际位置间的最大误差,通常用角度、角分或角秒来表示。例如有些绝对式编码器参数表

里会写 ±20′′,这个就表示编码器输出的读数与转轴实际位置之间存在正负 20 角秒的误差,精度由码盘刻线加工精度、转轴同心度、材料的温度特性、电路的响应时间等各方面因素

共同决定。

最大响应频率:

指编码器每秒输出的脉冲数,单位是 Hz。计算公式:最大响应频率 = 分辨率 * 轴转速/60。

信号输出形式:

对于增量式编码器,每个通道的信号独立输出,输出电路形式通常有集电极开路输出、推挽输出、差分输出等。对于绝对式编码器,由于是直接输出几十位的二进

制数,为了确保传输速率和信号质量,一般采用串行输出或总线型输出,例如同步串行接口 (SSI)、RS485、CANopen 或 EtherCAT 等,也有一部分是并行输出,输出电路形式与增量

式编码器相同。

二.程序

1.硬件接口

STM32芯片内部有专门用来采集增量式编码器方波信号的接口,这些接口实际上是 STM32 定时器的其中一种功能。不过F407编码器接口功能只有高级定时器 TIM1、TIM8 和通用定时器 TIM2 到TIM5 才有。

2.增量式编码器程序设计,两个步骤:

①如何判断转动方向

②如何将脉冲数准确;  

第一个问题,如何根据编码器的脉冲判断电机的转动方向。

    目前比较常见的方法:使用DSP或者STM32,检测到A相信号的下降沿时触发中断,检测此时的B相信号的电平高低,如果电平为低,则为正转;如果为高,则为反转(正反转方向每个人的定义不同,不影响,只要根据自己的需要定义就行)。  

第二个问题的解决方案其实已经在上面说差不多了,如果为了提高精度,可以在A相信号的上升沿和下降沿都进行检测以及可以避免A相信号的下降沿和Z相信号上升沿重合

   (用A相信号的下降沿作为触发条件去检测Z相信号的高低,重合时检测不到,这也是我使用二倍频的原因),没有检测到从而不能及时清零的问题。

3.编码器定时器检测代码

/* 定时器溢出次数 */

__IO int16_t Encoder_Overflow_Count = 0;

TIM_HandleTypeDef TIM_EncoderHandle;

/**

  * @brief  编码器接口引脚初始化

  * @param  无

  * @retval 无

  */

static void Encoder_GPIO_Init(void)

{

  GPIO_InitTypeDef GPIO_InitStruct = {0};

  

  /* 定时器通道引脚端口时钟使能 */

  ENCODER_TIM_CH1_GPIO_CLK_ENABLE();

  ENCODER_TIM_CH2_GPIO_CLK_ENABLE();

  

  /* 设置输入类型 */

  GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;

  /* 设置上拉 */

  GPIO_InitStruct.Pull = GPIO_PULLUP;

  /* 设置引脚速率 */

  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;

  

  /* 选择要控制的GPIO引脚 */

  GPIO_InitStruct.Pin = ENCODER_TIM_CH1_PIN;

  /* 设置复用 */

  GPIO_InitStruct.Alternate = ENCODER_TIM_CH1_GPIO_AF;

  /* 调用库函数,使用上面配置的GPIO_InitStructure初始化GPIO */

  HAL_GPIO_Init(ENCODER_TIM_CH1_GPIO_PORT, &GPIO_InitStruct);

  

  /* 选择要控制的GPIO引脚 */

  GPIO_InitStruct.Pin = ENCODER_TIM_CH2_PIN;

  /* 设置复用 */

  GPIO_InitStruct.Alternate = ENCODER_TIM_CH2_GPIO_AF;

  /* 调用库函数,使用上面配置的GPIO_InitStructure初始化GPIO */

  HAL_GPIO_Init(ENCODER_TIM_CH2_GPIO_PORT, &GPIO_InitStruct);

}

/**

  * @brief  配置TIMx编码器模式

  * @param  无

  * @retval 无

  */

static void TIM_Encoder_Init(void)

{

  TIM_Encoder_InitTypeDef Encoder_ConfigStructure;

  

  /* 使能编码器接口时钟 */

  ENCODER_TIM_CLK_ENABLE();

  

  /* 定时器初始化设置 */

  TIM_EncoderHandle.Instance = ENCODER_TIM;

  TIM_EncoderHandle.Init.Prescaler = ENCODER_TIM_PRESCALER;

  TIM_EncoderHandle.Init.CounterMode = TIM_COUNTERMODE_UP;

  TIM_EncoderHandle.Init.Period = ENCODER_TIM_PERIOD;

  TIM_EncoderHandle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;

  TIM_EncoderHandle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;

  

  /* 设置编码器倍频数 */

  Encoder_ConfigStructure.EncoderMode = ENCODER_MODE;  //4倍频

  /* 编码器接口通道1设置 */

  Encoder_ConfigStructure.IC1Polarity = ENCODER_IC1_POLARITY;

  Encoder_ConfigStructure.IC1Selection = TIM_ICSELECTION_DIRECTTI;

  Encoder_ConfigStructure.IC1Prescaler = TIM_ICPSC_DIV1;

  Encoder_ConfigStructure.IC1Filter = 0;

  /* 编码器接口通道2设置 */

  Encoder_ConfigStructure.IC2Polarity = ENCODER_IC2_POLARITY;

  Encoder_ConfigStructure.IC2Selection = TIM_ICSELECTION_DIRECTTI;

  Encoder_ConfigStructure.IC2Prescaler = TIM_ICPSC_DIV1;

  Encoder_ConfigStructure.IC2Filter = 0;

  /* 初始化编码器接口 */

  HAL_TIM_Encoder_Init(&TIM_EncoderHandle, &Encoder_ConfigStructure);

  

  /* 清零计数器 */

  __HAL_TIM_SET_COUNTER(&TIM_EncoderHandle, 0);

  

  /* 清零中断标志位 */

  __HAL_TIM_CLEAR_IT(&TIM_EncoderHandle,TIM_IT_UPDATE);

  /* 使能定时器的更新事件中断 */

  __HAL_TIM_ENABLE_IT(&TIM_EncoderHandle,TIM_IT_UPDATE);

  /* 设置更新事件请求源为:计数器溢出 */

  __HAL_TIM_URS_ENABLE(&TIM_EncoderHandle);

  

  /* 设置中断优先级 */

  HAL_NVIC_SetPriority(ENCODER_TIM_IRQn, 5, 1);

  /* 使能定时器中断 */

  HAL_NVIC_EnableIRQ(ENCODER_TIM_IRQn);

  

  /* 使能编码器接口 */

  HAL_TIM_Encoder_Start(&TIM_EncoderHandle, TIM_CHANNEL_ALL);

}

/**

  * @brief  编码器接口初始化

  * @param  无

  * @retval 无

  */

void Encoder_Init(void)

{

  Encoder_GPIO_Init();    /* 引脚初始化 */

  TIM_Encoder_Init();     /* 配置编码器接口 */

}

/**

  * @brief  定时器更新事件回调函数

  * @param  无

  * @retval 无

  */

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)

{

  /* 判断当前计数器计数方向 */

  if(__HAL_TIM_IS_TIM_COUNTING_DOWN(htim))

    /* 下溢 */

    Encoder_Overflow_Count--;

  else

    /* 上溢 */

    Encoder_Overflow_Count++;

}

  • 24
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AI+程序员在路上

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值