STM32 TIM编码器接口测速

编码器接口简介:

Encoder Interface 编码器接口

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

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

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

编码器接口基本结构:

工作模式:

正传的状态都向上计数,反转的状态都向下计数

接线图:

函数介绍:

定时器编码器接口配置,第一个参数选择定时器,第二个参数选择编码器模式,后面两个参数分别选择通道1和通道2的极性

void TIM_EncoderInterfaceConfig(TIM_TypeDef* TIMx, uint16_t TIM_EncoderMode,
                                uint16_t TIM_IC1Polarity, uint16_t TIM_IC2Polarity);

代码配置:

利用编码器接口进行测速

1.定义结构体变量

bash 复制代码
//定义结构体变量
GPIO_InitTypeDef GPIO_InitStructure;							 //定义GPIO结构体变量
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;      //定义TimeBase结构体变量
TIM_ICInitTypeDef TIM_ICInitStructure;						 //定义IC结构体变量  

2.RCC开启时钟

开启GPIO和定时器的时钟

bash 复制代码
//开启RCC时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//打开TIM3时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//打开GPIO A族时钟

3.配置GPIO

这里需要把PA6和PA7配置成输入模式

bash 复制代码
//GPIO配置
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);//GPIO初始化
	

4.配置时基单元

这里预分频器我们选择不分频,自动重装一般给最大65536,只需要个CNT执行计数就行

bash 复制代码
//时基单元配置
	
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;	//时钟分频
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式,选择向上计数
TIM_TimeBaseInitStructure.TIM_Period = 65535 - 1;        //周期 自动重装器ARR的值
TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1;         //预分频器 PSC的值
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;     //重复计数器的值
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);  //TimeBase初始化

5.配置输入捕获单元

这里输入捕获单元只有滤波器和极性这两个参数有用(极性在配置编码器接口模式也可以配置,所以这里就删掉了)

bash 复制代码
//输入捕获单元配置
TIM_ICStructInit(&TIM_ICInitStructure);
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1; //TIM通道选择,这里选择的是TIM3的CH1通道
TIM_ICInitStructure.TIM_ICFilter = 0xF;          //选择输入捕获的滤波器

TIM_ICInit(TIM3,&TIM_ICInitStructure);         //IC初始化
	
TIM_ICInitStructure.TIM_Channel = TIM_Channel_2; //TIM通道选择,这里选择的是TIM3的CH2通道
TIM_ICInitStructure.TIM_ICFilter = 0xF;          //选择输入捕获的滤波器
	
TIM_ICInit(TIM3,&TIM_ICInitStructure);         //IC初始化

6.配置编码器接口模式

后面两个参数可以配置通道1与通道2的极性

bash 复制代码
//配置编码器接口
TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);

最后调用TIM_Cmd,启动定时器

bash 复制代码
//开启定时器
TIM_Cmd(TIM3,ENABLE);

电路初始化完成之后,CNT就会随之编码器的旋转而自增自减,如果想要测量编码器的位置,直接读出CNT的值就行了,如果想测量编码器的速度和方向,那就需要每隔一段固定的闸门时间,取出一次CNT,然后再把CNT清零,这样就是测频法测量速度了

完整代码:

cs 复制代码
void Encoder_Config(void)
{
	//定义结构体变量
	 GPIO_InitTypeDef GPIO_InitStructure;							 //定义GPIO结构体变量
	 TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;//定义TimeBase结构体变量
	 TIM_ICInitTypeDef TIM_ICInitStructure;						 //定义IC结构体变量       
	//开启RCC时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//打开TIM3时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//打开GPIO A族时钟

	//GPIO配置
	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);//GPIO初始化
	
	//时基单元配置
	
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;	//时钟分频
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式,选择向上计数
	TIM_TimeBaseInitStructure.TIM_Period = 65535 - 1;        //周期 自动重装器ARR的值
	TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1;         //预分频器 PSC的值
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;     //重复计数器的值
	TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);  //TimeBase初始化
	
	//输入捕获单元配置
	TIM_ICStructInit(&TIM_ICInitStructure);
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_1; //TIM通道选择,这里选择的是TIM3的CH1通道
	TIM_ICInitStructure.TIM_ICFilter = 0xF;          //选择输入捕获的滤波器

	TIM_ICInit(TIM3,&TIM_ICInitStructure);         //IC初始化
	
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_2; //TIM通道选择,这里选择的是TIM3的CH2通道
	TIM_ICInitStructure.TIM_ICFilter = 0xF;          //选择输入捕获的滤波器
	
	TIM_ICInit(TIM3,&TIM_ICInitStructure);         //IC初始化

	//配置编码器接口
	TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
	
	//开启定时器
	TIM_Cmd(TIM3,ENABLE);
}

功能函数:

读取CNT的值,并读取一次便将CNT的值清零

cs 复制代码
int16_t Encoder_GetTime(void)
{
	
	int16_t temp;
	temp = TIM_GetCounter(TIM3);
	TIM_SetCounter(TIM3,0);
	return temp;
	
}

Timer函数:

这里用定时中断的方法来测量,其他方法涉及到用delay函数的问题,会堵塞主程序,所以最好是用中断解决

cs 复制代码
void Timer_Init(void)
{
	 //---------------------------定义结构体变量-------------------------------
	
	 TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;//定义TIM结构体变量
	 NVIC_InitTypeDef NVIC_InitStructure;							 //定义NVIC结构体变量
	//---------------------------定义结构体变量-------------------------------
	
	 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//打开TIM2的外设时钟
	

	//-----------------------------配置时基单元---------------------------------
	
	 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;						 //是PSC预分频器的值
	 TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;						 //重复计数器的值(这个是高级寄存器才有的,这里不需要用直接给0)
	 TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);						 //TIM初始化
	
	//-----------------------------配置时基单元---------------------------------
	 
	 TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);						//开启更新中断到NVIC通路
	
	 TIM_ClearITPendingBit(TIM2,TIM_IT_Update);        		//清除标志位
	//-----------------------------NVIC配置-------------------------------------
	
	
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//选择中断分组2
	
	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;//选择中断通道
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能中断通道
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;//抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;			 //响应优先级
	NVIC_Init(&NVIC_InitStructure);//NVIC初始化
	
	//-----------------------------NVIC配置-------------------------------------
	
	 TIM_Cmd(TIM2,ENABLE);//启动定时器
}

中断函数:

cs 复制代码
int16_t Speed = 0;
//中断函数

void TIM2_IRQHandler(void)
{
	//获取中断标志位,判断是否触发中断
	if(TIM_GetITStatus(TIM2,TIM_IT_Update) == SET)
	{
		
		Speed = Encoder_GetTime();
		TIM_ClearITPendingBit(TIM2,TIM_IT_Update);//清除中断标志位
		
		
	}
	
}

主函数代码:

cs 复制代码
#include "Encoder.h"
#include "timer.h"
int main(void)
{
	OLED_Init();
  Timer_Init();
	Encoder_Config();
	OLED_ShowString(1, 1, "Speed:");						
	
	while(1)
	{
		 OLED_ShowSignedNum(1, 7, Speed, 5);
	 
	}
	
	
}
相关推荐
辰哥单片机设计7 分钟前
STM32项目分享:STM32智能窗户
单片机·嵌入式硬件
雷门大师姐7 小时前
14.DS18B20温度传感器
单片机·嵌入式硬件
触角010100018 小时前
OLED屏幕开发全解析:从硬件设计到物联网显示实战 | 零基础入门STM32第五十二步
驱动开发·stm32·单片机·嵌入式硬件·物联网
蓑衣客VS索尼克9 小时前
无感方波开环强拖总结
经验分享·单片机·学习
傍晚冰川11 小时前
【江协科技STM32】ADC数模转换器-学习笔记
笔记·科技·stm32·单片机·嵌入式硬件·学习
c-u-r-ry3011 小时前
009---基于Verilog HDL的单比特信号边沿检测
嵌入式硬件·fpga开发
土豆1989102112 小时前
简记_ MCU管脚的防静电处理
嵌入式硬件
Whappy00112 小时前
第三节:基于Winform框架的串口助手小项目---串口操作《C#编程》
linux·单片机·c#
爱吃奶酪的松鼠丶14 小时前
51单片机之蓝牙模块的使用
单片机·嵌入式硬件·51单片机
盐析大白兔15 小时前
STM32G431RBT6--(3)片上外设及其关系
stm32·单片机·嵌入式硬件