STM32 TIM编码器接口测速

devtools/2025/2/4 19:46:32/

编码器接口简介:

        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);//选择中断分组2NVIC_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.ppmy.cn/devtools/156077.html

相关文章

4 Spark Streaming

4 Spark Streaming 一级目录1. 整体流程2. 数据抽象3. DStream 相关操作4. Spark Streaming 完成实时需求1) WordCount2) updateStateByKey3) reduceByKeyAndWindow 一级目录 Spark Streaming 是一个基于 Spark Core 之上的实时计算框架,可以从很多数据源消费数据并…

PyQt4学习笔记0】QtGui.QApplication

目录 1. 主要功能 2. 创建实例 3. 主要方法和属性 a. 设置应用程序属性 b. 样式表 c. 窗口管理 d. 事件循环 e. 其他 f. 设置全局鼠标光标样式 4. 退出应用程序 5. 示例代码 6. 注意事项 在 PyQt4 中,QtGui.QApplication 是一个非常重要的类,它代表了整个…

深入理解 `box-sizing: border-box;`:CSS 布局的利器

深入理解 box-sizing: border-box;:CSS 布局的利器 默认行为示例代码 使用 box-sizing: border-box;示例代码 全局应用 box-sizing: border-box;示例代码 实际应用场景1. 表单布局2. 网格布局 总结 在 CSS 中,box-sizing 属性决定了元素的总宽度和高度是…

FFmpeg源码:av_base64_decode函数分析

一、引言 Base64(基底64)是一种基于64个可打印字符来表示二进制数据的表示方法。由于log2 646,所以每6个比特为一个单元,对应某个可打印字符。3个字节相当于24个比特,对应于4个Base64单元,即3个字节可由4个…

集合通讯概览

集合通信概览 (1)通信的算法 是根据通讯的链路组成的 (2)因为通信链路 跟硬件强相关,所以每个CCL的库都不一样 芯片与芯片、不同U之间是怎么通信的 多卡训练:多维并行(xxx并行在上一期已经讲述…

LabVIEW透镜多参数自动检测系统

在现代制造业中,提升产品质量检测的自动化水平是提高生产效率和准确性的关键。本文介绍了一个基于LabVIEW的透镜多参数自动检测系统,该系统能够在单一工位上完成透镜的多项质量参数检测,并实现透镜的自动搬运与分选,极大地提升了检…

AJAX综合案例——图书管理

黑马程序员视频地址: AJAX-Day02-10.案例_图书管理AJAX-Day02-10.案例_图书管理_总结_V1.0是黑马程序员前端AJAX入门到实战全套教程,包含学前端框架必会的(ajaxnode.jswebpackgit),一套全覆盖的第25集视频&#xff0c…

DeepSeek大模型系列

DeepSeek 基本使用 对于DeepSeek 的使用来说,可以通过Web和APP两种方式就可以了: Web网站使用地址: https://chat.deepseek.com/APP的下载地址: https://download.deepseek.com/app/ 以上两种方式注册账号就可以,使…