一、简介
旋转编码器简单来说,就是会输出2个PWM,依据相位可以知道旋转方向,依据脉冲个数可以知道旋转的角度。一般旋转一圈有一个固定数值的脉冲个数。旋转编码器广泛用于电机、或者角度传感器,STM32的定时器可以直接接入这两个波形获取到信息。
除了以顺时针方向和逆时针方向旋转旋钮外,编码器还有一个开关(低电平有效),按下内部的旋钮可以按下该开关。来自此开关的信号通过引脚3(Switch)获得。最后它有两个输出引脚。
1.增量编码器
(1)增量编码器给出两相方波,它们的相位差90°,通常称为A通道和B通道。
(2)其中一个通道给出与转速相关的信息,与此同时,通过两个通道信号进行顺序对比,得到旋转方向的信息。
(3)还有一个特殊信号称为Z或者零通道,该通道给出编码器的绝对零位,此信号是一个方波与A通道方波的中心线重合。
2.工作原理
两个信号相位差为90度,则这两个信号称为正交。由于两个信号相差90度,因此可以根据两个信号哪个先哪个后来判断方向、根据每个信号脉冲数量
的多少及整个编码轮的周长
就可以算出当前行走的距离、如果再加上定时器的话还可以计算出速度。
3.编码器接口
(1)编码器接口可接收增量(正交)编码器的信号
(2)根据编码器旋转产生的正交信号脉冲,自动控制CNT自增或自减
(3)指示编码器的位置、旋转方向和旋转速度 (PWM就是通计时器计次达到测频率的目的,而编码器是带方向的计次)
(4)每个高级定时器和通用定时器都拥有1个编码器接口(外部中断,是软件操作,定时器是硬件。硬件收到限制,比如stm32的高级和通用定时器一共就4个。编码器最多接4个。但是可以通过外部中断,来控制编码器手动自增自减。比如CNT计次,也可以通过中断的方式,实现CNT计次,然后手动把CNT取出来放到变量里)
(5)两个输入引脚借用了输入捕获的通道1和通道2
- 编码器的输入是CH1,CH2.输出相当于是从模式控制器,控制CNT计数的控制速度和计数方向。
- 如果出现了边沿信号,并且另外一项为正转,则控制CNT自增。否则控制CNT自减。
- ARR为65535 正转最大值是65535。那么反转直接将无符号数据改为有符号对应的 65534就是-1
4.编码器接口的三种工作模式
一般情况适用最下面的计数方式,精度最高
5.正交编码器抗噪声原理
此图展示了,向上计数,和向下计数,以及抗噪声的原理。TI1 反相后,需要对TI1取反,才是正确的。
二、使用定时器实现
1.Encoder.c
void Encode_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;//上拉输入
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
//配置时基单元
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; //分频
//TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; //递增
TIM_TimeBaseInitStruct.TIM_Period = 65536-1; //ARR
TIM_TimeBaseInitStruct.TIM_Prescaler = 1-1; //预分频器,psc 预分频值
TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct);
//初始化输入捕获单元
TIM_ICInitTypeDef TIM_ICInitStruct;
TIM_ICStructInit(&TIM_ICInitStruct);
TIM_ICInitStruct.TIM_Channel = TIM_Channel_1 ;
TIM_ICInitStruct.TIM_ICFilter = 0xF; //采样值越大,滤波的效果越好
// TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising; //极性选择上升沿,这里的上升沿标识的是高低电平不反转,对 应的通道给上升沿就是不反向
TIM_ICInit(TIM3,&TIM_ICInitStruct);
TIM_ICInitStruct.TIM_Channel = TIM_Channel_2;
TIM_ICInitStruct.TIM_ICFilter = 0xF; //采样值越大,滤波的效果越好
//TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising; //极性选择 上升沿,这里的上升沿标识的是高低电平不反转,对应的通道给上升沿就是不反向
TIM_ICInit(TIM3,&TIM_ICInitStruct);
TIM_EncoderInterfaceConfig(TIM3,TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICPolarity_Rising);
TIM_Cmd(TIM3,ENABLE);
}
//快速完成负数转换,引脚转换就会导致极性发生改变 ,随便一个极性改变,也导致反转
int16_t Encode_Get(void)
{
int16_t Temp;
Temp = TIM_GetCounter(TIM3);
TIM_SetCounter(TIM3,0); //将CNT清零 ,读取TIM3时基单元种计数器的值, 然后将计数器清零
return Temp;
}
2.中断函数
//定时中断 通过定时中断
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2,TIM_FLAG_Update)== SET) //当前状态是TIM2的标志位
{
Speed = Encode_Get(); //得到这个计数值
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
}
}
三、使用中断实现
1.初始化使用的GPIO引脚
将引脚进行初始化,配置成上拉输入模式,默认为低电平。
#include "gpio.h"
#define PWR_B GET_PIN(A, 15) // 调节编码器的功率,B引脚
#define PWR_A GET_PIN(C, 10) // 调节编码器的功率,A引脚
#define PT_B GET_PIN(C, 11) // 调节编码器的脉宽,B引脚
#define PT_A GET_PIN(C, 12) // 调节编码器的脉宽,A引脚
#define IT_B GET_PIN(D, 0) // 调节编码器的时间间隔,B引脚
#define IT_A GET_PIN(D, 1) // 调节编码器的时间间隔,A引脚
/*=====================================================### 全局变量定义 ####=================================================*/
// GPIO引脚初始化常量表
const gpio_init_t GPIO_INIT_TAB