概述

编码器的作用是用来计算电机的转速, 下图清晰的展示了编码器的工作原理. 通过在电机的传动轴上加装一个码盘,电机带动码盘转动, 而发射机与接收器成一对,

  1. 当光线穿过码盘上的孔的时候,我们假定接收器收到了高电平
  2. 当光线被阻断的时候,我们认为接收器收到了低电平

这样通过计算单位时间内高电平的次数除以码盘的孔数我们就可以很轻松的计算出电机的转速
encoder.gif
我们常用的是霍尔编码器也称AB相编码器,它通过电路信号的变化来获取电机的转速,如果正转,一相输出超前另一相,如果反转一相滞后另一相
通过这样的方式,我们就可以计算电机转动的方向,同时还可以读取电机的转速
04-编码器测速 - 图2

image.png
我们所用的减速电机是7线的, 减速比是1:50 电机转动50圈输出轴输出1圈, 每圈会产生7个信号.
由于每相都有上升沿和下降沿,所以单相1圈信号数量为 72, 再由于信号是AB相同时产生的, 所以电机转动一圈所产生的实际信号量= 72(上升沿和下降沿)*2(A相和B相)

了解了编码器的原理,接下来我们就使用GD32来获取编码器数据.

原理图

image.png

示例代码

实现编码器数据读取开发步骤:

  1. 选定gpio口, PA15,PB3 TIMER1_CH0,TIMER1_CH1
  2. 使用GD32定时器编码器模式
    1. 配置定时器 timer_init
    2. 配置定时器输入
    3. 配置定时器模式,编码器解码的功能

      定时器初始

      ```c

      include “bsp_encoder.h”

      include

define RCU_ENCODER_L1 RCU_GPIOA // PA15

define PORT_ENCODER_L1 GPIOA

define PIN_ENCODER_L1 GPIO_PIN_15

define AF_ENCODER_L1 GPIO_AF_1

define TIMER_CH_ENCODER_L1 TIMER_CH_0

define RCU_ENCODER_L2 RCU_GPIOB //PB3

define PORT_ENCODER_L2 GPIOB

define PIN_ENCODER_L2 GPIO_PIN_3

define AF_ENCODER_L2 GPIO_AF_1

define TIMER_CH_ENCODER_L2 TIMER_CH_1

define TIMER_ENCODER_L TIMER1

define RCU_TIMER_ENCODER_L RCU_TIMER1

define RCU_ENCODER_R1 RCU_GPIOB //PB4

define PORT_ENCODER_R1 GPIOB

define PIN_ENCODER_R1 GPIO_PIN_4

define AF_ENCODER_R1 GPIO_AF_2

define TIMER_CH_ENCODER_R1 TIMER_CH_0

define RCU_ENCODER_R2 RCU_GPIOB //PB5

define PORT_ENCODER_R2 GPIOB

define PIN_ENCODER_R2 GPIO_PIN_5

define AF_ENCODER_R2 GPIO_AF_2

define TIMER_CH_ENCODER_R2 TIMER_CH_1

define RCU_TIMER_ENCODER_R RCU_TIMER2

define TIMER_ENCODER_R TIMER2

void bsp_encoder_gpio_left_init(){ // 开启时钟线 rcu_periph_clock_enable(RCU_ENCODER_L1); rcu_periph_clock_enable(RCU_ENCODER_L2);

  1. gpio_af_set(PORT_ENCODER_L1,AF_ENCODER_L1,PIN_ENCODER_L1);
  2. gpio_mode_set(PORT_ENCODER_L1,GPIO_MODE_AF,GPIO_PUPD_NONE,PIN_ENCODER_L1);
  3. gpio_af_set(PORT_ENCODER_L2,AF_ENCODER_L2,PIN_ENCODER_L2);
  4. gpio_mode_set(PORT_ENCODER_L2,GPIO_MODE_AF,GPIO_PUPD_NONE,PIN_ENCODER_L2);

}

void bsp_encoder_gpio_right_init(){ // 开启时钟线 rcu_periph_clock_enable(RCU_ENCODER_R1); rcu_periph_clock_enable(RCU_ENCODER_R2);

  1. gpio_mode_set(PORT_ENCODER_R1,GPIO_MODE_AF,GPIO_PUPD_NONE,PIN_ENCODER_R1);
  2. gpio_mode_set(PORT_ENCODER_R2,GPIO_MODE_AF,GPIO_PUPD_NONE,PIN_ENCODER_R2);
  3. gpio_af_set(PORT_ENCODER_R1,AF_ENCODER_R1,PIN_ENCODER_R1);
  4. gpio_af_set(PORT_ENCODER_R2,AF_ENCODER_R2,PIN_ENCODER_R2);

}

void bsp_encoder_timer_left_init(){ rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL4); rcu_periph_clock_enable(RCU_TIMER_ENCODER_L);

  1. timer_deinit(TIMER_ENCODER_L);
  2. // 配置定时器参数
  3. timer_parameter_struct timer_parameter;
  4. timer_struct_para_init(&timer_parameter);
  5. timer_parameter.period = 65535;
  6. timer_parameter.prescaler = 0;
  7. timer_init(TIMER_ENCODER_L,&timer_parameter);
  8. // 配置定时器输入
  9. timer_ic_parameter_struct timer_ic_parameter;
  10. timer_channel_input_struct_para_init(&timer_ic_parameter);
  11. timer_ic_parameter.icfilter = 10;
  12. timer_input_capture_config(TIMER_ENCODER_L,TIMER_CH_ENCODER_L1,&timer_ic_parameter);
  13. timer_input_capture_config(TIMER_ENCODER_L,TIMER_CH_ENCODER_L2,&timer_ic_parameter);
  14. timer_quadrature_decoder_mode_config(TIMER_ENCODER_L,TIMER_QUAD_DECODER_MODE2,TIMER_IC_POLARITY_FALLING,TIMER_IC_POLARITY_FALLING);
  15. timer_counter_value_config(TIMER_ENCODER_L,0);
  16. timer_auto_reload_shadow_enable(TIMER_ENCODER_L);
  17. timer_enable(TIMER_ENCODER_L);

}

void bsp_encoder_timer_right_init(){ rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL4); rcu_periph_clock_enable(RCU_TIMER_ENCODER_R);

  1. timer_deinit(TIMER_ENCODER_R);
  2. // 配置定时器参数
  3. timer_parameter_struct timer_parameter;
  4. timer_struct_para_init(&timer_parameter);
  5. timer_parameter.period = 65535;
  6. timer_parameter.prescaler = 0;
  7. timer_init(TIMER_ENCODER_R,&timer_parameter);
  8. // 配置定时器输入
  9. timer_ic_parameter_struct timer_ic_parameter;
  10. timer_channel_input_struct_para_init(&timer_ic_parameter);
  11. timer_ic_parameter.icfilter = 10;
  12. timer_input_capture_config(TIMER_ENCODER_R,TIMER_CH_ENCODER_R1,&timer_ic_parameter);
  13. timer_input_capture_config(TIMER_ENCODER_R,TIMER_CH_ENCODER_R2,&timer_ic_parameter);
  14. timer_quadrature_decoder_mode_config(TIMER_ENCODER_R,TIMER_QUAD_DECODER_MODE2,TIMER_IC_POLARITY_FALLING,TIMER_IC_POLARITY_FALLING);
  15. timer_counter_value_config(TIMER_ENCODER_R,0);
  16. timer_auto_reload_shadow_enable(TIMER_ENCODER_R);
  17. timer_enable(TIMER_ENCODER_R);

}

void bsp_encoder_init(void) { bsp_encoder_gpio_left_init(); bsp_encoder_timer_left_init();

  1. bsp_encoder_gpio_right_init();
  2. bsp_encoder_timer_right_init();

}

short bsp_encoder_get_left() { short value = (short)timer_counter_read(TIMER_ENCODER_L); //timer_counter_value_config(TIMER_ENCODER_L, 0);
return value; } short bsp_encoder_get_right() { short value = (short)timer_counter_read(TIMER_ENCODER_R); //timer_counter_value_config(TIMER_ENCODER_R, 0);
return value; }

void bsp_encoder_test(){ bsp_encoder_init();

  1. while(1){
  2. short left = bsp_encoder_get_left();
  3. short right = bsp_encoder_get_right();
  4. printf("left=%d,right=%d\r\n",left,right);
  5. delay_1ms(100);
  6. }

}

  1. <a name="Vgkgm"></a>
  2. ### 读编码器
  3. ```c
  4. short enc = (short)timer_counter_read(TIMER_RENCODER1);

返回值若为正数,说明电机正转, 反之电机为反转. 这里我们需要定时器的寄存器是16位的,所以刚好是两个字节,那么它的取值范围是-32767到32767之间的整数值。
如果超过了这个范围, 寄存器数据就会溢出,所以为了避免数据溢出,我们每次读完之后,应该将清空寄存器中的数值

  1. timer_counter_value_config(TIMER_RENCODER1, 0);