stm32-TIM编码器接口

一、知识点

1.编码器接口(Encoder Interface)

编码器接口可接收增量(正交)编码器的信号,根据编码器旋转产生的正交信号脉冲,自动控制CNT自增或自减,从而指示编码器的位置、旋转方向和旋转速度

例子解释
若初始化之后CNT初始值为0,右转产生8个脉冲后停下来,CNT就从0自增加到8,再让编码器向左转产生5个脉冲,那么CNT就从8自减5至3。
所以编码器接口就相当于一个带有方向控制的外部时钟,它同时控制着CNT的计数时钟和计数方向,CNT的值就表示了编码器的位置
若每隔一段时间取出CNT的值,再把CNT清零,每次取出来的值就表示了编码器的速度

2.资源简介

在这里插入图片描述
编码器接口有使用CH1和CH2的输入捕获滤波器和边沿检测,编码器接口没有使用后面的是否交叉、预分频器、CCR寄存器与编码器接口无关
编码器接口的输出部分:相当于从模式控制器,去控制CNT的计数时钟和计数方向

  • 每个高级定时器和通用定时器都拥有1个编码器接口
  • 两个输入引脚借用了输入捕获的通道1和通道2(通道3和通道4不能用)
  • 如果一个定时器配置为编码器接口模式,则该编码器干不了其他的事,C8T6这一类型芯片只有四个定时器,即最多只能接四个编码器。

3.正交信号

在这里插入图片描述
像这样一个信号比另一个信号慢90度,则这两个信号被称为正交信号

  • 原理
    首先把A相和B相的所有边缘,作为计数器的计数时钟,出现边缘信号时就计数自增或自减,增还是减由另一相的高低电平决定

  • 好处
    a、正交信号精度更高,因为A、B相都可以计次,相当关于计次频率提高了一倍
    b、其次正交信号可以以抗噪声,因为正交信号两个信号必须是交替跳变的,可以设计一个抗噪声电路,如果一个信号不变,另一个信号连续跳变,也就是产生了噪声,这时计次值是不会变化的

4.工作模式

在这里插入图片描述
在TI1和TI2上计数
a.均不反向
在这里插入图片描述

b.TI1反向,TI2不反向
![](https://img-blog.csdnimg.cn/818cd2d29f274909882db47aba37afaf.png)

5.uint16_t和int16_t

想把65535变成-1,则利用补码原则(把uint16_t写成int16_t)

二、实例(编码器接口测速)

1.基本思路

在这里插入图片描述

一、RCC开启时钟,开启GPIO和定时器时钟
二、配置GPIO口
三、配置时基单元(预分频器选择不分频,自动重装选65535,CNT只需要计数就可以)
四、配置输入捕获单元(只需要配置滤波器和极性两个参数)
五、配置编码器接口模式
六、开启定时器(TIM_Cmd)

测量编码器的速度和方向:需要每隔一段固定的闸门时间,取出一次CNT,然后再把CNT清零,这是测频法测量速度

2.代码

Encoder.c

#include "stm32f10x.h"                  // Device header

void Encoder_Init(void)
{
	//RCC开启时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	//配置GPIO口
	GPIO_InitTypeDef GPIO_InitStructure;
	//空闲默认高电平,选择上拉输入,空闲默认低电平,选择下拉输入
	//浮空输入:没有上拉电阻和下拉电阻去影响外部信号,
	//缺点:当引脚浮空时,没有默认的电平,易受到噪声的影响,来回不断跳变
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

//编码器接口的实质是一个带方向控制的外部时钟,故内部时钟没用

	//配置时基单元
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1;		//ARR
	TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1;		//PSC
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
	
	//配置输入捕获单元
	TIM_ICInitTypeDef TIM_ICInitStructure;
	TIM_ICStructInit(&TIM_ICInitStructure);  //赋一个初值,防止干扰
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
	TIM_ICInitStructure.TIM_ICFilter = 0xF;
	TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
	TIM_ICInit(TIM3, &TIM_ICInitStructure);
	
	TIM_ICStructInit(&TIM_ICInitStructure);
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
	TIM_ICInitStructure.TIM_ICFilter = 0xF;
	TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
	TIM_ICInit(TIM3, &TIM_ICInitStructure);
	//后面两个参数为通道1和通道2的电平特性,上升沿:高低电平不反转(编码器上升沿和下降沿都有效)
	
	//配置编码器接口模式
TIM_EncoderInterfaceConfig(TIM3,TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICPolarity_Rising);
	
	//开启时钟
	TIM_Cmd(TIM3,ENABLE);
}

int16_t Encoder_Get(void)
{
	int16_t temp;
	temp=TIM_GetCounter(TIM3);
	TIM_SetCounter(TIM3,0);
	return temp;
}

main.c

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

int16_t Speed;

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

void TIM2_IRQHandler(void)  //中断读取Speed
{
	if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET)
	{
		Speed=Encoder_Get();
		TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
	}
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值