EC11编码器编码使用

前要

关于EC11编码器的了解可以参考两篇文章,比较详细,在此就不多介绍了:

原理

脉冲与定位

  • 15脉冲/30定位:每拨动一格,两个电平都相继翻转,是半个脉冲;再拨动一格,电平再相继翻转,也是半个脉冲;两个半脉冲形成一个完整脉冲。静止状态下,两个电平相同,都为高或低
  • 20脉冲/20定位:每拨动一格,形成一个完整脉冲
    对应下图如下:
    在这里插入图片描述
    示波器抓取部分波形:
    在这里插入图片描述
      (note: 两个脉冲跳变的间隔约为几十ms)

功能

通过2个pin负责编码器的波形检测,顺时针与逆时针波形不同

硬件设计

IO外部上拉与无上拉
在这里插入图片描述

编程

硬件条件:

  • MCU:    stm32f407
  • 编码器类型: EC11-15脉冲/30定位
  • 连接:    IO外部无上拉,设置MCU GPIO的内部上拉

下面使用两种方法来对编码器进行计数和使用。

轮询模式

直接就上代码了,随意两个GPIO

//GPIO初始化
void MX_GPIO_Init(void)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOH_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();

  /*Configure GPIO pin : PB6 */
  GPIO_InitStruct.Pin = GPIO_PIN_6;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /*Configure GPIO pin : PB7 */
  GPIO_InitStruct.Pin = GPIO_PIN_7;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

}

//判断检测
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
  // exit_init();
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  uint32_t count = 0;
  uint32_t wait_t = 0;
  bool encoder_switch = 0;
  uint8_t encoder_a_pre = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_6);
  // uint8_t encoder_b_pre = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_7);
  int32_t steps = 0;
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    uint32_t t = HAL_GetTick();

    uint8_t encoder_a = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_6);
    uint8_t encoder_b = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_7);

    if (encoder_a_pre != encoder_a && !encoder_switch) {
      wait_t = HAL_GetTick();
      encoder_switch = true;
    }
    if (encoder_switch && ((t - wait_t) >= 2 )) {
      //a 0->1, b 0 Clockwise; b 1 AntiClockwise
      if (encoder_a == 1) {
        if (encoder_b == 0) {
          steps++;
        } else {
          steps--;
        }
      }
      //a 1->0, b 1 Clockwise; b 0 AntiClockwise 
      else {
        if (encoder_b == 1) {
          steps++;
        } else {
          steps--;
        }
      }
      encoder_switch = false;
      encoder_a_pre = encoder_a;
      printf("%d\r\n", steps);
    }
 
  }
  /* USER CODE END 3 */
}

注意点:编码器电平发生变化时可能存在噪声,类似按键一样需要增加延时防抖,并且考虑到在系统中少加入延时死等这些不友善的代码,所以代码中有如上处理。

定时器Encoder模式

stm32中定时器有自带Encoder的功能,所以可以借助定时器的这个特性来实现我们的需求。
直接撸代码,GPIO必须使用复用功能有定时器的pin。

//定时器及IO初始化
TIM_HandleTypeDef htim4;

/* TIM4 init function */
void MX_TIM4_Init(void)
{

  /* USER CODE BEGIN TIM4_Init 0 */

  /* USER CODE END TIM4_Init 0 */

  TIM_Encoder_InitTypeDef sConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};

  /* USER CODE BEGIN TIM4_Init 1 */

  /* USER CODE END TIM4_Init 1 */
  htim4.Instance = TIM4;
  htim4.Init.Prescaler = 0;
  htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim4.Init.Period = 65535;
  htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
  sConfig.EncoderMode = TIM_ENCODERMODE_TI1;
  sConfig.IC1Polarity = TIM_ICPOLARITY_FALLING;
  sConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI;
  sConfig.IC1Prescaler = TIM_ICPSC_DIV1;
  sConfig.IC1Filter = 3;
  sConfig.IC2Polarity = TIM_ICPOLARITY_FALLING;
  sConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI;
  sConfig.IC2Prescaler = TIM_ICPSC_DIV1;
  sConfig.IC2Filter = 3;
  if (HAL_TIM_Encoder_Init(&htim4, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM4_Init 2 */
  HAL_TIM_Encoder_Start(&htim4, TIM_CHANNEL_ALL);
  /* USER CODE END TIM4_Init 2 */

}

void HAL_TIM_Encoder_MspInit(TIM_HandleTypeDef* tim_encoderHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(tim_encoderHandle->Instance==TIM4)
  {
  /* USER CODE BEGIN TIM4_MspInit 0 */

  /* USER CODE END TIM4_MspInit 0 */
    /* TIM4 clock enable */
    __HAL_RCC_TIM4_CLK_ENABLE();

    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**TIM4 GPIO Configuration
    PB6     ------> TIM4_CH1
    PB7     ------> TIM4_CH2
    */
    GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF2_TIM4;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /* USER CODE BEGIN TIM4_MspInit 1 */

  /* USER CODE END TIM4_MspInit 1 */
  }
}

//获取编码器变化
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
  // exit_init();
  MX_TIM4_Init();
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  int32_t Enc_Count_pre =  __HAL_TIM_GET_COUNTER(&htim4);
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    int32_t Enc_Count =  __HAL_TIM_GET_COUNTER(&htim4);
    if (Enc_Count != Enc_Count_pre) {
      printf("%d\r\n", Enc_Count);
      Enc_Count_pre = Enc_Count;
    }
    
  }
  /* USER CODE END 3 */
}

结束语

此两种方式已做测试,稳得一批,如果细节问题可沟通。


— 2021.10.22-21:45于广东深圳

### STM32F407 旋转编码器配置与使用 #### 基础概念介绍 旋转编码器是一种能够将机械位移转换成电信号输出的传感器,广泛应用于各种精密控制领域。对于STM32系列单片机而言,通过特定的GPIO引脚以及TIM定时器可以实现对这类器件的有效读取和处理[^3]。 #### 硬件连接说明 针对STM32F407微控制器,在实际操作过程中通常会利用其内部集成的通用定时器来完成增量型旋转编码器信号捕捉的任务。具体来说,需要将编码器的A/B两路脉冲分别接入MCU的不同IO口上,并设置这些管脚为输入模式;与此同时还要注意电源电压匹配问题——即确保外部设备的工作电平同处理器I/O兼容[^2]。 #### 软件编程要点 为了简化开发流程并提升程序稳定性,建议采用官方提供的HAL库来进行底层驱动编写工作。下面给出了一段简单的初始化函数示例代码: ```c // 初始化 TIMx 定时器用于编码器接口 void MX_TIMx_Init(void) { __HAL_RCC_TIMx_CLK_ENABLE(); // 开启时钟使能 TIM_Encoder_InitTypeDef sConfig = {0}; htimx.Instance = TIMx; htimx.Init.Prescaler = 0; htimx.Init.CounterMode = TIM_COUNTERMODE_UP; htimx.Init.Period = 65535; htimx.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htimx.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; if (HAL_TIM_Encoder_Init(&htimx, &sConfig) != HAL_OK) { Error_Handler(); } } ``` 上述片段展示了如何创建一个适用于四倍频解码方式下的定时器实例对象`htimx`,并通过调用`HAL_TIM_Encoder_Init()`完成了必要的参数设定过程[^1]。 #### 实际应用场景中的注意事项 当涉及到具体的工程项目实施环节时,则需进一步考虑诸如抗干扰措施、异常状态监测机制等方面的内容。比如可以通过软件算法过滤掉因抖动而产生的误触发事件,从而保障最终测量精度不受影响。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值