定时器中编码器接口的简介及特点
正交译码器
正交译码器功能使用由 TIMERx_CH0 和 TIMERx_CH1 引脚生成的 CI0 和 CI1 正交信号各自相互作用产生计数值。在每个输入源改变期间,DIR 位被硬件自动改变。输入源可以是只有 CI0,可以只有 CI1,或着可以同时有 TI1 和 TI2,通过设置 SMC=0x01, 0x02 或 0x03 来选择使用哪种模式。计数器计数方向改变的机制如下图. 计数方向与编码器信号之间的关系所示。 正交译码器可以当作一个带有方向选择的外部时钟,这意味着计数器会在 0 和自动加载值之间连续的计数。因此,用户必须在计数器开始计数前配置 TIMERx_CAR 寄存器。
编码器的三种模式,由 TIMERx_SMCFG 寄存器的 SMC[2:0]控制
对应下图,编码器模式0、编码器模式1、编码器模式2
比如 1000 线的编码器
编码器模式0、编码器模式1:编码器旋转一周计数器计数 2000
编码器模式2:编码器旋转一周计数器计数 4000
注意: "-" 意思是"无计数"; "X" 意思是不可能。
在【GD32F310G8-PWM单通道输出】文章中有讲到具有编码器接口的定时器,如下所示。
- TIMER0、TIMER14、TIMER15、TIMER16 这四个定时器适合做电机控制(带死区插入功能)
- TIMER0、TIMER1 TIMER2 这三个定时器具有编码器的接口
- TIMER2、TIMER3 还具有霍尔的接口
关于定时器的其他功能介绍参照【GD32F310开发板试用】PWM 单通道输出
开发环境&参考文档
- Keil-MDK 5.34
- Windows10
- 固件库-GD32F3x0_Firmware_Library_V2.2.0
- GD32F310xx-数据手册-Rev1.1
- GD32F3x0-用户手册-Rev2.5
- GD32F3x0-固件库使用指南-Rev1.2
代码部分
这里我们使用的 96 线编码器,采用编码器模式2
encoder.h 文件
#ifndef _ENCODER_H_
#define _ENCODER_H_
#include "gd32f3x0.h"
void HW_EncoderInit(void);
#endif
encoder.c 文件
#include "encoder.h"
void HW_EncoderInit(void)
{
timer_parameter_struct Timer_ParamType;
timer_ic_parameter_struct Timer_IC_ParamType;
rcu_periph_clock_enable(RCU_GPIOA);//启用外设时钟功能
rcu_periph_clock_enable(RCU_TIMER2);
gpio_af_set(GPIOA,GPIO_AF_1,GPIO_PIN_6);//端口复用为TIMER2_CH0模式
gpio_af_set(GPIOA,GPIO_AF_1,GPIO_PIN_7);//端口复用为TIMER2_CH1模式
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_6);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_6);
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_7);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_7);
timer_deinit(TIMER2);
timer_struct_para_init(&Timer_ParamType);
Timer_ParamType.alignedmode = TIMER_COUNTER_EDGE;//配置为边沿对其模式
Timer_ParamType.clockdivision = TIMER_CKDIV_DIV1;//配置死区时间和采样时钟(DTS)之间的分频系数
Timer_ParamType.counterdirection = TIMER_COUNTER_UP;//配置计数方向为向上计数
Timer_ParamType.period = 96*4;//周期
Timer_ParamType.prescaler = 0;//预分频
Timer_ParamType.repetitioncounter = 0;
timer_init(TIMER2,&Timer_ParamType);
timer_channel_input_struct_para_init(&Timer_IC_ParamType);
Timer_IC_ParamType.icfilter = 0x5;//配置滤波器
Timer_IC_ParamType.icpolarity = TIMER_IC_POLARITY_RISING;
Timer_IC_ParamType.icselection = TIMER_IC_SELECTION_DIRECTTI;
Timer_IC_ParamType.icprescaler = TIMER_IC_PSC_DIV1;
timer_input_capture_config(TIMER2,TIMER_CH_0,&Timer_IC_ParamType);
timer_input_capture_config(TIMER2,TIMER_CH_1,&Timer_IC_ParamType);
timer_quadrature_decoder_mode_config(TIMER2,TIMER_ENCODER_MODE2,TIMER_IC_POLARITY_RISING,TIMER_IC_POLARITY_RISING);
timer_enable(TIMER2);
}
main.c 文件
文件中的其他模块使用请参照前几篇文章
#include "gd32f3x0.h"
#include "systick.h"
#include "gpio.h"
#include "encoder.h"
#include "Printf.h"
uint32_t EncoderValue;
int main(void)
{
systick_config();
HW_GpioInit();
HW_UsartInit();
HW_EncoderInit();
while(1)
{
/* insert 500 ms delay */
delay_1ms(100);
/* toggle the LED */
gpio_bit_toggle(GPIOA,GPIO_PIN_1);
EncoderValue = timer_counter_read(TIMER2);
printf("编码器的值:%d",EncoderValue);
}
}