STM32操作增量式编码器(二)----使用编码器接口实现定位

上一个博文介绍了编码器实现测试,这也是编码器最普遍的应用,我们需要操作的东西并不多,通常来说记录脉冲数。

STM32操作增量式编码器(一)----使用外部中断实现测速

1.增量式编码器实现定位思路

对于增量式编码器如何进行定位,我也是一直存在疑惑,并不是说整体定位算法难,这仅仅需要利用一个变量去记录当前脉冲数即可,正转递增,反转递减。但是真实情况真的如此简单吗?

首先我们需要明确两个存在的问题:

1.如何去确定正反转

2.如何准确确定正反转

可能你觉得这是同一个问题,但是真的如此吗?

对于第一个问题,1.如何去确定正反转,我们先来看看编码器正反转输出波形图。

                                        图1-1 增量式编码器输出波形(对于Z相波形,属于零点信号,我们暂时不用理会)

从上述波形,我们可以根据AB相波形的相位差就可以判断出编码器正反转方向,软件实现大概思路就是通过定时器捕获或者外部中断的方式就可实现,这一点实现并不难。

对于第二个问题,2.如何准确确定正反转,首先看看编码器换向的输出波信图。

                                                                      图2-2 增量式编码器换向输出波形图

这里就会遇到理论与现实中间隔着东西,噪声,现实!=理论,这是现实最迷人的地方。

言归正传,从波形图可以看到,编码器换向过程,输出波形就会出现抖动,它是未知的,抖动都可以认为是未知的,这个抖动正是编码器定位的遇到的最大问题,减少噪声的影响,我们应该想到各式各样的滤波算法(博主小白,只能用各式各样去修饰滤波算法了),这个滤波算法的性能将决定定位的精度,这确实也是一个深入研究的点。

2.使用STM32接口轻松实现编码器定位

为什么说STM32作为一个32位的MCU在如今的微处理器如此耀眼,当然是有原因的,STM32提供了在嵌入式领域的常用接口而且十分好用。博文使用STM32F4的编码器接口实现编码器定位。

2.1编码器接口概述

无厘头帖数据手册,像极了高中时写作文的----鲁迅曾今说过。。。。。

STM32F4的编码器接口介绍在STM32Fxx中文参考手册,英语水平较高的小伙伴也可以看英文手册。

我们通过下面的波信图分析或许更加直观一点:

                                                                 图2-1 编码器接口模式下的计数器工作实例

怎么一回事呢,图中的TI1、TI2就是定时器的输入通道,例如TIM3的 CH1 -->GPIOA6、CH2 -->GPIOA7,接的就是编码器输出信号的AB相,从图中可以看到在这个官方例程配置下,计数器在TI1、TI2的上升沿下降沿都计数,相当于编码器走一步,计数器计数 * 4,最值得关注的不是这一段,是正向转动和反向转动以及抖动阶段,我们可以知道,编码器接口计数自动帮我们区分正反转,更重要的是,它帮我们处理抖动状态,wow,感动,所以说STM32好用,好用到我们只需要读CNT就可以实现定位了,仅仅需要按部就班的配置就完事。除了这个我们还发现STM32提供一个转向的标志位,不需要我们通过CNT递增递减去判断。

这个标志位是TIMx_CR1寄存器,有具体应用场合的小伙伴可以了解。

2.2 编码器接口配置

这个配置是对于寄存器配置而言的,对于操作库函数而言,这些配置几乎就是非常直观了,按部就班配置即可。

我会在代码下载中放两种代码,分别是F1和F4的,区别就是F1操作寄存器配置,F4操作库函数配置。(以下是F4配置代码)

//author:ora
//email:[email protected]

#include "ROTARYENCODER.h"
#include "usart.h"
#include "lcd.h"


#define ENCODER_TIM_PERIOD (u16)(65000)
#define COUNTER_RESET   (u16)30000

void rotaryEncoder_init(void)
{

	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	TIM_ICInitTypeDef TIM_ICInitStructure;
	
	//开启时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
	
	//PA6、PA7输入模式
	GPIO_InitStructure.GPIO_Speed         = GPIO_Speed_100MHz;       
	GPIO_InitStructure.GPIO_Mode         = GPIO_Mode_AF;       
	GPIO_InitStructure.GPIO_OType         = GPIO_OType_OD;       
	GPIO_InitStructure.GPIO_Pin         = GPIO_Pin_6|GPIO_Pin_7;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	//启动GPIO复用
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource6,GPIO_AF_TIM3);
    GPIO_PinAFConfig(GPIOA,GPIO_PinSource7,GPIO_AF_TIM3);
	

	/* Timer configuration in Encoder mode */ 
//	TIM3->PSC = 0x0;//预分频器
//	TIM3->ARR = ENCODER_TIM_PERIOD-1;//设定计数器自动重装值 
//	TIM3->CR1 &=~(3<<8);// 选择时钟分频:不分频
//	TIM3->CR1 &=~(3<<5);// 选择计数模式:边沿对齐模式
	
	//配置定时器
	TIM_TimeBaseStructure.TIM_Prescaler = 0x0;
	TIM_TimeBaseStructure.TIM_Period = ENCODER_TIM_PERIOD;
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
	
	//配置编码器模式
	TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_BothEdge, TIM_ICPolarity_BothEdge);
	
	//设置输入捕获滤波器
	TIM_ICStructInit(&TIM_ICInitStructure);
    TIM_ICInitStructure.TIM_ICFilter = 6;
    TIM_ICInit(TIM3, &TIM_ICInitStructure);	
		
	//设置初始值、使能计时器
	TIM3->CNT = COUNTER_RESET;
	TIM3->CR1 |= 0x01;    //CEN=1,使能定时器

}

3.无厘头代码下载

https://github.com/oraSC/STM32-course/tree/master/%E7%BC%96%E7%A0%81%E5%99%A8

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章