TIM编码器接口测速

本文详细介绍了STM32中编码器接口的工作原理,包括编码器的A/B相脉冲处理、正交编码器的使用、不同计数模式以及接线图示例。此外,还展示了如何在main.c和TIM.c文件中初始化和配置编码器接口,以及TIM2中断处理实现速度测量。
摘要由CSDN通过智能技术生成

1.编码器接口简介

  • 编码器有两个输出,一个A相,一个B相,然后接入STM32的定时器的编码器接口,编码器接口自动控制定时器时基单元中的CNT计数器进行自增或自减。假设CNT初始值为0,若编码器右转,CNT++,右转产生一个脉冲,CNT就加一次,右转产生多少脉冲,CNT就自增到多少;若编码器右转CNT++,编码器左转CNT--,左转产生一个脉冲,CNT减一次,左转产生多少脉冲,CNT就自减到多少,若先右转产生10个脉冲,再左转产生5个脉冲,那CNT计数值为10-5=5
  • 编码器接口,相当于是一个带有方向控制的外部时钟,它同时控制这CNT的计数时钟和计数方向。所以CNT的值就可以表示编码器的位置,如果我们每隔一段固定时间取CNT的值,再把CNT清零,取出CNT的值就相当于编码器的速度。相当于测频法。
  • 在单片机中,只有高级定时器和通用定时器有编码器接口,但如果一个定时器被配置成编码器接口模式,其他工作基本无法进行,编码器接在每个定时器的CH1和CH2通道,CH3和CH4不能接编码器。

2.正交编码器

  • 增量式编码器也成为正交编码器,是通过两个信号线的脉冲输出来进行数据处理,一个输出脉冲信号就对应于一个增量位移,编码器每转动固定的位移,就会产生一个脉冲信号  通过读取单位时间脉冲信号的数量,便可以达到测速的效果
  • 增量式编码器有两个脉冲输出,A相和B相,并且两个相位永远存在90°相位差。 如果两个信号相位差为90度,则这两个信号称为正交。由于两个信号相差90度,因此可以根据两个信号哪个先哪个后来判断方向、并且可以根据AB相脉冲信号数量测得速度,位移等

编码器接口有三种计数模式,三种计数模式如下

通过A,B相的边沿和另一相的高低电平来判断此时处于正转还是反转。

3.编码器接口电路

  • 从图中可以看出,编码器接口接入的是CH1通道的TI1FP1和CH2通道的TI2FP2
  • CH1通道的TI1FP1和CH2通道的TI2FP2仅仅使用了其中CH1和CH2的输入滤波器和边沿检测器,后面的是否交叉、预分频器和CCR寄存器并未使用
  • 在这里,我们并不会使用72M内部时钟和在时基单元初始化设置的计数方向,因为此时计数时钟和计数方向都处于编码器接口托管的状态,计数器的自增和自减手编码器控制。

4. 编码器接口基本结构 

从图中可看出,使用编码器接口要做到

(1)开启GPIO时钟和TIM时钟

(2)配置GPIO和时基单元(时基单元中PSC赋值为0,不分频;ARR赋初值65535,防止计数器溢出)

(3)配置输入捕获IC_Init(注意在输入捕获结构体配置中,我们无需全部配置,因为我们只用到了输入滤波器和边沿检测器;我们可以将无用部分删除,但为了避免出错,在进行结构体赋值时用TIM_ICStructInit(&TIM_ICInitStructure);给结构体附一个默认值,避免因删去无用部分导致的出错,例程如下)

    TIM_ICInitTypeDef TIM_ICInitStructure;
	TIM_ICStructInit(&TIM_ICInitStructure);//结构体赋默认值
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
	TIM_ICInitStructure.TIM_ICFilter = 0xF;
	TIM_ICInit(TIM3, &TIM_ICInitStructure);
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
	TIM_ICInitStructure.TIM_ICFilter = 0xF;
	TIM_ICInit(TIM3, &TIM_ICInitStructure);

(4)配置编码器接口模式(这里直接调用库函数)

TIM_EncoderInterfaceConfig(TIM_TypeDef* TIMx, uint16_t TIM_EncoderMode,
                                uint16_t TIM_IC1Polarity, uint16_t TIM_IC2Polarity);
  • 其中TIM_TypeDef* TIMx,                           //选择TIM定时器
  •         uint16_t TIM_EncoderMode,             //选择计数模式,三种选一种,详见上文图表
  •         uint16_t TIM_IC1Polarity,                  //选择TIM通道1极性,Falling / Rising ,注意这里的极性选择含义为是否发生电平翻转, Rising电平不翻转, Falling电平翻转
  •         uint16_t TIM_IC2Polarity,                  //选择TIM通道2极性

5.接线图

6.Encoder.c

#include "stm32f10x.h"                  // Device header


	
void Encoder_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//开启时钟,根据接线图可知需开启GPIOA时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//开启时钟,TIM2已用作定时器,所以选择TIM3
	
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;//编码器接口模式需要接入TI1FP1和TI2FP2,查引脚图可知,分别对应PA6和PA7口
	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;//在这里,我们并不会使用72M内部时钟和在时基单元初始化设置的计数方向
	                                                            //因为此时计数时钟和计数方向都处于编码器接口托管的状态,计数器的自增和自减手编码器控制。
    TIM_TimeBaseInitStruct.TIM_Period = 65536 - 1;//给最大防止溢出
	TIM_TimeBaseInitStruct.TIM_Prescaler = 1-1;
	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;//选择通道1
	TIM_ICInitStruct.TIM_ICFilter = 0xF;
	TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;//这里极性选择的意义是不发生电平翻转
	TIM_ICInit(TIM3, &TIM_ICInitStruct);//输入捕获通道1配置结束
	
	
	TIM_ICStructInit(&TIM_ICInitStruct);
	TIM_ICInitStruct.TIM_Channel = TIM_Channel_2;//选择通道2
	TIM_ICInitStruct.TIM_ICFilter = 0xF;
	TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;//这里极性选择的意义是不发生电平翻转,此处与后方极性选择配置重复
	                                                        //可删除,不删除也不会出错,但要注意将编码接接口模式配置放在此语句之后
	TIM_ICInit(TIM3, &TIM_ICInitStruct);//输入捕获通道2配置结束
	
	TIM_EncoderInterfaceConfig(TIM3,TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICPolarity_Falling);
	//配置编码接接口模式            //编码器计数模式T1T2都计数
	TIM_Cmd(TIM3,ENABLE);
	
}

int16_t Encoder_Get(void)//函数返回CNT的值
{
	int16_t Temp;//因为TIM_GetCounter是无符号16位的定义,所以用有符号16位定义变量来接收CNT数据
	Temp = TIM_GetCounter(TIM3);//这样就可以做到编码器反转,为负数;编码器正转,为正数
	TIM_SetCounter(TIM3,0);//返回CNT值之后,将CNT清零
	return Temp;//返回CNT值
}



 7.main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Timer.h"
#include "Encoder.h"

int16_t Speed;


int main(void)
{	
    Timer_Init();
	OLED_Init();
	Encoder_Init();
	
	OLED_ShowString(1, 1, "Speed:");
	
	while (1)
	{
		OLED_ShowSignedNum(1,7,Speed,5); //显示速度
	
		
	}
}

void TIM2_IRQHandler(void)//TIM2定时器定时1s的时间
{
	if(TIM_GetITStatus(TIM2,TIM_IT_Update) == SET)//当TIM2定时器定时1s的时间时,产生中断标志位
	{
	 Speed = Encoder_Get();//将CNT的值赋给有符号全局变量Speed
	 TIM_ClearITPendingBit(TIM2,TIM_IT_Update);//清除中断标志位
	}
	
}

8.TIM.c

#include "stm32f10x.h"                  // Device header

void Timer_Init(void)
{

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
	
	TIM_InternalClockConfig(TIM2);//
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period = 10000 - 1;//ARR
	TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1;//
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);//

	TIM_ClearFlag(TIM2,TIM_FLAG_Update);
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//NVIC
	
	NVIC_InitTypeDef NVIC_InitStruct;//NVIC
	NVIC_InitStruct.NVIC_IRQChannel = TIM2_IRQn;//
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;//
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
	NVIC_Init(&NVIC_InitStruct);
	
	TIM_Cmd(TIM2,ENABLE);//
}

/*
void TIM2_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM2,TIM_IT_Update) == SET)
	{
	
	 TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
	}
	
}
*/

 

  • 26
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值