STM32 TIM编码器接口测速

server/2025/2/6 0:52:11/

编码器接口简介:

        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/server/165282.html

相关文章

DeepSeek 遭 DDoS 攻击背后:DDoS 攻击的 “千层套路” 与安全防御 “金钟罩”

当算力博弈升级为网络战争:拆解DDoS攻击背后的技术攻防战——从DeepSeek遇袭看全球网络安全新趋势 在数字化浪潮席卷全球的当下,网络已然成为人类社会运转的关键基础设施,深刻融入经济、生活、政务等各个领域。从金融交易的实时清算&#xf…

Android车机DIY开发之学习篇(七)NDK交叉工具构建

Android车机DIY开发之学习篇(七)NDK交叉工具构建 1.ubuntu安装GCC sudo apt-get update sudo apt-get install gcc g sudo gcc --version sudo g --version 2.测试GCC VSCODE中新建Hello.c编译 #include <stdio.h> int main(void) { printf(“Hello, this is a progr…

【Linux】文件描述符

初识文件 之前我们认识到当我们进行创建出一个空文件在磁盘上也是占用一部分空间的&#xff0c;因为文件的组成是由文件内容和文件属性共同构成。 文件内容属性&#xff0c;那我们对文件进行操作无外乎就是对内容和属性两个方面进行操作。 文件在磁盘上进行存储&#xff0c;…

maven、npm、pip、yum官方镜像修改文档

文章目录 Maven阿里云网易华为腾讯云 Npm淘宝腾讯云 pip清华源阿里中科大华科 Yum 由于各博客繁杂&#xff0c;本文旨在记录各常见镜像官网&#xff0c;及其配置文档。常用镜像及配置可评论后加入 Maven 阿里云 官方文档 setting.xml <mirror><id>aliyunmaven&l…

【大数据技术】本机DataGrip远程连接虚拟机MySQL/Hive

本机DataGrip远程连接虚拟机MySQL/Hive datagrip-2024.3.4VMware Workstation Pro 16CentOS-Stream-10-latest-x86_64-dvd1.iso写在前面 本文主要介绍如何使用本机的DataGrip连接虚拟机的MySQL数据库和Hive数据库,提高编程效率。 安装DataGrip 请按照以下步骤安装DataGrip软…

深度学习篇---二维码预训练模型

文章目录 前言第一部分&#xff1a;二维码1. 二维码结构定位标记分隔符定时标记格式信息数据码字纠错码字 2. 二维码识别步骤步骤一&#xff1a;图像预处理灰度化二值化 步骤二&#xff1a;定位标记检测查找定位标记确定二维码位置和方向 步骤三&#xff1a;图像校正透视变换 步…

2025年1月22日(网络编程 udp)

系统信息&#xff1a; ubuntu 16.04LTS Raspberry Pi Zero 2W 系统版本&#xff1a; 2024-10-22-raspios-bullseye-armhf Python 版本&#xff1a;Python 3.9.2 已安装 pip3 支持拍摄 1080p 30 (1092*1080), 720p 60 (1280*720), 60/90 (640*480) 已安装 vim 已安装 git 学习…

前端 | 浅拷贝深拷贝

在前端开发中&#xff0c;我们经常需要复制对象或数组&#xff0c;但不同的复制方式可能会影响数据的完整性和应用的稳定性。本文将深入探讨浅拷贝&#xff08;Shallow Copy&#xff09;和深拷贝&#xff08;Deep Copy&#xff09;的区别、实现方式及适用场景。 1. 浅拷贝 1.…