STM32 TIM编码器接口测速

news/2025/1/31 6:30:24 标签: stm32, 嵌入式硬件, 单片机

编码器接口简介:

        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.定义结构体变量

//定义结构体变量
GPIO_InitTypeDef GPIO_InitStructure;							 //定义GPIO结构体变量
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;      //定义TimeBase结构体变量
TIM_ICInitTypeDef TIM_ICInitStructure;						 //定义IC结构体变量  

2.RCC开启时钟

开启GPIO和定时器的时钟

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

3.配置GPIO

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

//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执行计数就行

//时基单元配置
	
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.配置输入捕获单元

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

//输入捕获单元配置
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的极性

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

最后调用TIM_Cmd,启动定时器

//开启定时器
TIM_Cmd(TIM3,ENABLE);

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

完整代码:

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的值清零

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

Timer函数:

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

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);//启动定时器
}

中断函数:

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);//清除中断标志位
		
		
	}
	
}

主函数代码:

#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);
	 
	}
	
	
}


http://www.niftyadmin.cn/n/5838395.html

相关文章

Vue3.0教程004:ref和reactive对比

文章目录 3.4 ref创建基本类型的响应式数据3.5 reactive创建对象类型响应数据3.6 ref创建对象类型的响应式数据3.7 ref对比reactive 3.4 ref创建基本类型的响应式数据 在script中引入ref import {ref} from vue;需要哪个数据是响应式的,就用ref包裹哪个数据&#…

“星门计划对AI未来的意义——以及谁将掌控它”

“星门计划对AI未来的意义——以及谁将掌控它” 图片由DALL-E 3生成 就在几天前,唐纳德特朗普宣布了“星门计划”,OpenAI随即跟进,分享了更多细节。他们明确表示,计划在未来四年内投资5000亿美元,在美国为OpenAI构建一…

Deepseek本地部署(ollama+open-webui)

ollama 首先是安装ollama,这个非常简单 https://ollama.com/ 下载安装即可 open-webui 这个是为了提供一个ui,毕竟我们也不想在cmd和模型交互,很不方便。 第一,需要安装python3.11,必须是3.11(其他版…

windows10 配置使用json server作为图片服务器

步骤1:在vs code中安装json server, npm i -g json-server 注意:需要安装对应版本的json server,不然可能会报错,比如: npm i -g json-server 0.16.3 步骤2:出现如下报错: json-server 不是…

【Postman接口测试】Postman的安装和使用

在软件测试领域,接口测试是保障软件质量的关键环节之一,而Postman作为一款功能强大且广受欢迎的接口测试工具,能够帮助测试人员高效地进行接口测试工作。本文将详细介绍Postman的安装和使用方法,让你快速上手这款工具。 一、Pos…

基于阿里云百炼大模型Sensevoice-1的语音识别与文本保存工具开发

基于阿里云百炼大模型Sensevoice-1的语音识别与文本保存工具开发 摘要 随着人工智能技术的不断发展,语音识别在会议记录、语音笔记等场景中得到了广泛应用。本文介绍了一个基于Python和阿里云百炼大模型的语音识别与文本保存工具的开发过程。该工具能够高效地识别东…

oracle中使用in 和 not in 查询效率分析

在Oracle数据库中,IN和NOT IN的查询效率受多种因素影响,以下是关键点总结和优化建议: 1. IN 的效率 优化方式: IN 通常会被优化为 OR条件 或 半连接(Semi-Join),如果子查询关联到外部表&#x…

[免费]微信小程序智能商城系统(uniapp+Springboot后端+vue管理端)【论文+源码+SQL脚本】

大家好,我是java1234_小锋老师,看到一个不错的微信小程序智能商城系统(uniappSpringboot后端vue管理端),分享下哈。 项目视频演示 【免费】微信小程序智能商城系统(uniappSpringboot后端vue管理端) Java毕业设计_哔哩哔哩_bilibili 项目介绍…