【STM32】TIM定时器编码器

1 编码器接口简介

Encoder Interface 编码器接口

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

接收正交信号,自动执行CNT自增或者自减,编码器接口相当于带有方向控制的外部时钟,同时控制着CNT的计数时钟和计数方向。每隔一段时间去取一次CNT的值,再把CNT清零,每次取出来的值就表示编码器的速度。(测频法)

每个高级定时器和通用定时器都拥有1个编码器接口

两个输入引脚借用了输入捕获的通道1和通道2(CH1和CH2)

1.1 正交编码器

正交编码器一般可以测量位置或者带有方向的速度值

旋转编码器:用来测量位置、速度或旋转方向的装置,当其旋转轴旋转时,其输出端可以输出与旋转速度和方向对应的方波信号,读取方波信号的频率和相位信息即可得知旋转轴的速度和方向

类型:机械触点式/霍尔传感器式/光栅式

方波频率代表速度。正转时A相提前B相90°;反转时A相滞后B相90°

首先把A\相和B相的所有边沿作为计数器的计数时钟,出现边沿信号时就计数器自增或者自减;计数的方向由另一相的状态来确定。当出现某个边沿时,判断另一相高低电平,如果另一相的状态出现在上面这个表中,那就是正转,计数自增;否则就是反转,计数自减。这样就可以实现编码器接口的功能了。

编码器接口有两个输入端,分别接到编码器的A相和B相,所以编码器的输入引脚就是定时器的CH1和CH2引脚。编码器的输出部分相当于从模式的控制器了,控制CNT的计数时钟和计数方向。计数器的自增和自减受编码器控制。

1.2 编码器接口基本结构

很清晰

1.3 工作模式

这里TI1FP1和TI2FP2接的就是AB相。计数和前面一样。

正转向上计数,反转向下计数。

1.4 实例图

均不反向,使用TI1和TI2都计数

很清晰。

**TI1反向,TI2不反向。**极性的变化对计数的影响。

这里的极性选择就是高低电平的极性选择了。如果选择上升沿的参数,就是信号直通过来,高低电平极性不反转;如果选择下降沿的参数,就是信号通过非门,高低电平反转。

很清晰。

手册

2 编码器接口测速

2.1 接线图

引脚定义

计划用TIM3的通道1和通道2

2.2 模块封装

按这个配置

库函数

cpp 复制代码
// 定时器编码器接口配置
void TIM_EncoderInterfaceConfig(TIM_TypeDef* TIMx, uint16_t TIM_EncoderMode,
                                uint16_t TIM_IC1Polarity, uint16_t TIM_IC2Polarity);

版本一:Encoder.c

cpp 复制代码
#include "stm32f10x.h"                  // Device header

// 编码器接口初始化函数
void EnCoder_Init(void)
{
	// 1开启时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	// 2配置GPIO
	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);
	
	// 3配置时基单元
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	TIM_TimeBaseInitStruct.TIM_Prescaler = 1 - 1;                    	// PSC预分频器的值,不分频
	TIM_TimeBaseInitStruct.TIM_Period = 65536 - 1;                     	// ARR自动重装器的值 
	TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;      	// 向上计数,没有用
	TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;			// 不分频
	TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;                	// 重复计数器的值
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStruct);
	
	// 4配置输入捕获单元(只有极性和滤波器两个参数有用)
	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_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;       // 无作用
//	TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;                 // 无作用
	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);
	
	// 5配置编码器接口模式
	// TIM_ICPolarity_Rising这个通道不反向,TIM_ICPolarity_Falling这个通道反向
	// 后两个参数相反就是方向相反
	TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
	// 6启动定时器
	TIM_Cmd(TIM3, ENABLE);
}

// 获取CNT的值
int16_t Encoder_Get(void)
{
    return TIM_GetCounter(TIM3);
}

版本二:Encoder.c

cpp 复制代码
#include "stm32f10x.h"                  // Device header

// 编码器接口初始化函数
void EnCoder_Init(void)
{
	// 1开启时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	// 2配置GPIO
	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);
	
	// 3配置时基单元
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	TIM_TimeBaseInitStruct.TIM_Prescaler = 1 - 1;                    	// PSC预分频器的值,不分频
	TIM_TimeBaseInitStruct.TIM_Period = 65536 - 1;                     	// ARR自动重装器的值 
	TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;      	// 向上计数,没有用
	TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;			// 不分频
	TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;                	// 重复计数器的值
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStruct);
	
	// 4配置输入捕获单元(只有极性和滤波器两个参数有用)
	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_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;       // 无作用
//	TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;                 // 无作用
	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);
	
	// 5配置编码器接口模式
	// TIM_ICPolarity_Rising这个通道不反向,TIM_ICPolarity_Falling这个通道反向
	// 后两个参数相反就是方向相反
	TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
	// 6启动定时器
	TIM_Cmd(TIM3, ENABLE);
}

// 获取CNT的值
int16_t Encoder_Get(void)
{
//    return TIM_GetCounter(TIM3);
	// 读取cnt,把cnt清零的逻辑
	int16_t temp = TIM_GetCounter(TIM3);
	TIM_SetCounter(TIM3, 0);
	return temp;
}

2.3 主函数

版本一:主函数

cpp 复制代码
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Timer.h"
#include "EnCoder.h"


int main()
{
	OLED_Init();								// 初始化OLED
	EnCoder_Init();
//	Timer_Init();								// 初始化定时器
	OLED_ShowString(1, 1, "CNT:");   			// 显示字符串
	
	while (1)
	{
		OLED_ShowNum(1, 5, Encoder_Get(), 5);    // 显示CNT计数器
	}
}

版本二:主函数

cpp 复制代码
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Timer.h"
#include "EnCoder.h"

int16_t speed;


int main()
{
	OLED_Init();								// 初始化OLED
	EnCoder_Init();
	Timer_Init();								// 初始化定时器
	OLED_ShowString(1, 1, "speed:");   			// 显示字符串
	
	while (1)
	{
		OLED_ShowSignedNum(1, 7, speed, 5);    		 // 显示CNT计数器
	}
}


// 中断函数
void TIM2_IRQHandler(void)
{
	// 检测中断标志位,确保是设置的中断源触发的这个函数
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
	{
		// 中断处理
		speed = Encoder_Get();
		// 清除中断标志
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
	}
}
相关推荐
cjy_Somnr2 小时前
keil5报错显示stm32的SWDIO未连接不能烧录
stm32·单片机·嵌入式硬件
Lay_鑫辰2 小时前
西门子诊断-状态和错误位(“轴”工艺对象 V1...3)
服务器·网络·单片机·嵌入式硬件·自动化
无垠的广袤5 小时前
【工业树莓派 CM0 NANO 单板计算机】本地部署 EMQX
linux·python·嵌入式硬件·物联网·树莓派·emqx·工业物联网
雲烟7 小时前
嵌入式设备EMC安规检测参考
网络·单片机·嵌入式硬件
泽虞7 小时前
《STM32单片机开发》p7
笔记·stm32·单片机·嵌入式硬件
田甲7 小时前
【STM32】 数码管驱动
stm32·单片机·嵌入式硬件
up向上up8 小时前
基于51单片机垃圾箱自动分类加料机快递物流分拣器系统设计
单片机·嵌入式硬件·51单片机
纳祥科技17 小时前
Switch快充方案,内置GaN,集成了多个独立芯片
单片机
单片机日志18 小时前
【单片机毕业设计】【mcugc-mcu826】基于单片机的智能风扇系统设计
stm32·单片机·嵌入式硬件·毕业设计·智能家居·课程设计·电子信息
松涛和鸣19 小时前
从零开始理解 C 语言函数指针与回调机制
linux·c语言·开发语言·嵌入式硬件·排序算法