• 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 */
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104

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

    定时器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 */
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126

    结束语

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


    — 2021.10.22-21:45于广东深圳

  • 相关阅读:
    anaconda使用系列教程--2)conda命令选项
    经典题记录 字符串相加/相乘
    Android深色主题背景的实现及主题背景颜色互换
    JSON和全局异常处理
    BUUCTF学习(8): 随便注,SQL
    基于Springboot的SSM整合案例(详解)
    Docker安装Mysql
    C++17一个很冷门很有意思的新特性
    快速排序算法
    多模态概述
  • 原文地址:https://blog.csdn.net/niu_88/article/details/133978217