单片机-STM32部分:13-1、编码器

飞书文档https://x509p6c8to.feishu.cn/wiki/BpEywhaX9iqbiLkdqdAcmDnwnab

EC旋转编码器

在产品开发过程中,需要位置闭环的的产品,类似电机类产品来说,编码器至关重要,它不仅可以使我们对带年纪进行精确的速度闭环,位置闭环,还可以通过时间积分,根据运动学关系,获得速度、位置等信息。

本节课,我们使用拨轮滚轮旋转编码器 EC11E153440D,带大家了解下编码器如何驱动。

编码器有四根线,A\B是编码输出,S是按钮状态,C是公共端。

那么我们该怎样去使用这个编码器呢,从给出的数据手册上面我们看到一个波形,我们就是通过这个波形去判断编码器是否转动以及编码器转动的方向?

可以从图中可以看出当从CW方向转动的时候,A的波形上升沿比B波形的上升沿快,具体快多少,这里数据手册给出24±3°,当从CCW方向转动的这个时候恰好相反,B的相位上升沿快于A的上升沿。这样可以通过捕获上升沿的顺序来判断编码器的方向。

因此:我们有两种方式来判断编码器转动和方向:

1、设置IOA为上升沿触发中断,在中断中检测B的电平状态,来判断旋转方向,这种方式比较简单。

2、可以同时捕获A项的上升、下降边沿,然后判断A项第一个边沿中断时候获取B和A项的电平,在第二个边沿触发中断的时候捕获B和A项的电平,根据两次捕获B和A项的值就可以知道旋转的方向。

复制代码
bool is_ccw_end = false;
bool is_cw_end = false;

  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    if(is_ccw_end == true){
      is_ccw_end = false;
      printf("正转\n");
    }
    if(is_cw_end == true){
      is_cw_end = false;
      printf("反转\n");
    }
  }

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){

    if(GPIO_Pin == A1_Pin)  //判断中断来自哪一条中断线
    {
         //进入中断之后,判断B1 PIN的电平来决定哪个方向
         if(HAL_GPIO_ReadPin(B1_GPIO_Port, B1_Pin) == 0){
            //CW方向
            is_cw_end = true;
         }else{
            //CCW方向
            is_ccw_end = true;
         }                   
    }
}

以CW方向为例,第一次捕获A项的的边缘位上升沿,此时A = 1,B = 0;那么第二次就必须捕获下降沿,A = 0,B = 1。假如A第一次没有在边沿捕获到上升沿的时候,捕获的是下降沿,第二次就一定捕获到上升沿。CCW方向也是如此的,这样我们就判断这四种情况,其他的都不用管,这样可以过滤掉干扰,从而实现更准确的控制。

设置PB0和PB1为编码器的A1、B1端口

PB0设置为外部中断,触发模式为上升、下降沿触发

PB1设置为输入模式

同时开启PB0的中断EXTI0

打开USART1作为日志口,方便调试

复制代码
              //CW方向
              set_cw_status();
              is_ccw_start = false;
         }else{
              //CCW方向
             set_ccw_status();
             is_cw_start = false;
         }
       }
    }
}

int fputc(int ch, FILE *f)
{
    HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1, 0xFFFF);
    return ch;
}
/* USER CODE END 4 */

参考工程:

参考飞书文档

STM32 的定时器有编码器模式( Encoder Mode )

大大的方便我们的开发。使用STM32cubeMX配置工具,使得这个过程变得无比简单。

|--------------------------------------------------------------------------------------------------------------------------------------|
| 如果TI1和TI2分别接编码器的A相和B相的话,那么,当编码器正转的时候,如下图计数器会向上计数,反转的时候会向下计数,注意了这个向下计数并不会出现负的值。 例如: 正转(0,1,2,...,65535,0) 反转(0,65535,65534,...,2,1,0) |

配置定时器TIM的编码器模式

设置定时器TIM的Combined Channels的选项为Encoder Mode,编码器模式;

设置定时器 TIM 相关参数:

PSC:0 ; Counter:65535 (设置计数器的值为65535,最大值);

配置编码器模式相关参数:

在参数配置中的Econder Mode中选择Econder Mode TI1 and TI2;

|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 如果编码模式设置为 Encoder Mode TI1 and TI2 则会默认检测AB相的上升沿与下降沿; 每一个上升沿和下降沿都触发计数,所以每转一格计数器就会+4; 需要增加测量的精度时,可以采用4倍频方式,即分别在A、B相波形的上升沿和下降沿计数,分辨率可以提高4倍, 如果只是测速,不要求方向,那么只需要用单片机随意选择一个信号线就行了。 |

在TI1、TI2的选项中选择Rising Edge上升沿触发计数;

|---------------------------------------------------------------------------|
| 这个参数的意思是在检测到上升沿的时候就触发encoder捕获AB相的值,而并不是这里设置的是上升沿就只检测AB相的上升沿,下降沿还是同样会计数的。 |

Input Filter:滤波值,起到消抖作用

选择GPIO模式配置,配置定时器两个GPIO引脚模式,全部改成Pull-Up,即上拉模式,主要用于没有外部上拉的编码器读取时,可以确定引脚电平,防止出错;

编写代码

添加定时器3的通道1和通道2的Encoder Mode开启使能函数

|------------------------------------------------------------------------------------------------------------------|
| /* USER CODE BEGIN 2 */ HAL_TIM_Encoder_Start(&htim3,TIM_CHANNEL_1 | TIM_CHANNEL_2); /* USER CODE END 2 */ |

编码器数据的读取使用:
在循环中调用 __HAL_TIM_IS_TIM_COUNTING_DOWN 可以获得当前电机的转向 0****为正、 1 为负 ;
在循环中调用 __HAL_TIM_GET_COUNTER 获取计数器的计数值,即编码器的脉冲数;

复制代码
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    int Direction = __HAL_TIM_IS_TIM_COUNTING_DOWN(&htim3);    //读取编码器转动方向
    //若需要检测编码器转了多少格,记得要/4,因为转一格是+4;
    int CaptureNumber = (short)__HAL_TIM_GET_COUNTER(&htim3)/4;  //读取编码器数据
    printf("Direction is %d \r\n",Direction);
    printf("CaptureNumber is %d \r\n",CaptureNumber);
    HAL_Delay(500);
  }
  /* USER CODE END 3 */

//short的表示范围(-32768-32767),也就是说当读出来的值为(32767, 32768, 32769,...,65535,65536,65537...)的时候会因为溢出而转换为(32767,-32768,-32767,..., -1, ,0, , 1)就这样不断地循环下去。所以我们的电机反转的时候读出的数就是反方向的速度值。
相关推荐
Tronlong创龙9 小时前
SBC‑TLT153 嵌入式 Linux 应用开发,交叉编译与 GDB 调试实践(上)
嵌入式硬件·嵌入式开发·硬件开发·工业控制·工业开发板
巴渝小禹10 小时前
单片机死循环delay_us()计算方法
单片机·嵌入式硬件
Yiran_G10 小时前
LoRa串口模组和SoC模组怎么选?从MCU架构看无线通信方案设计
嵌入式硬件·物联网
HQB202611 小时前
CN6150|简芯维尔 6V/500mA 高速低噪声 CMOS‑LDO 线性稳压器
嵌入式硬件·硬件工程
科芯创展12 小时前
XZ3445 高集成升压/升降压DC-DC电源芯片技术解析
单片机·嵌入式硬件
艾芯微科技12 小时前
高充放电流锂电充放 SoC:ETA9885E10,便携储能、小移动电源 BOM 选型笔记
网络·单片机·嵌入式硬件·集成测试·51单片机
艾芯微科技12 小时前
钰泰 ETA6973PQ3Y|QFN3×3 2A 同步降压 Buck,I2C 可配置多档输出,动态调压 PMIC
网络·单片机·嵌入式硬件·fpga开发·集成测试·51单片机
Brilliantwxx13 小时前
【STM32】 通用定时器:输入捕获与输出比较详解 测脉宽、测频率
stm32·单片机·嵌入式硬件·mcu
意法半导体STM3214 小时前
【官方原创】LAT1703 STM32C5 LL Cordic例程
stm32·单片机·嵌入式硬件·stm32c5·ll cordic