【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);
	}
}
相关推荐
好想有猫猫2 分钟前
【51单片机】串口通信原理 + 使用
c语言·单片机·嵌入式硬件·51单片机·1024程序员节
云卓科技21 分钟前
无人车之路径规划篇
人工智能·嵌入式硬件·算法·自动驾驶
stm 学习ing1 小时前
C语言 循环高级
c语言·开发语言·单片机·嵌入式硬件·算法·嵌入式实时数据库
w微信150135078122 小时前
小华一级 代理商 HC32F005C6PA-TSSOP20 HC32F005系列
c语言·arm开发·单片机·嵌入式硬件
北京迅为3 小时前
【北京迅为】《STM32MP157开发板嵌入式开发指南》-第七十八章 Qt控制硬件
linux·stm32·单片机·嵌入式硬件
编程圈子4 小时前
I.MX6U 裸机开发2. 芯片简介、汇编基础及GPIO操作准备工作
嵌入式硬件·arm
淘晶驰AK6 小时前
电子设计竞赛准备经历分享
嵌入式硬件·fpga开发
Matlab程序猿小助手6 小时前
【MATLAB源码-第208期】基于matlab的改进A*算法和传统A*算法对比仿真;改进点:1.无斜穿障碍物顶点2.删除中间多余节点,减少转折。
开发语言·嵌入式硬件·算法·matlab·机器人
田三番6 小时前
使用 vscode 简单配置 ESP32 连接 Wi-Fi 每日定时发送 HTTP 和 HTTPS 请求
单片机·物联网·http·https·嵌入式·esp32·sntp
lucy153027510796 小时前
【青牛科技】GC2803:白色家电与安防领域中 ULN2803 的卓越替代者
科技·单片机·智能家居·能源·安防·开关电源·白色家电