stm32-编码器测速

news2025/1/11 11:02:03

一、编码器简介

编码电机

旋转编码器

A,B相分别接通道一和二的引脚,VCC,GND接单片机VCC,GND

二、正交编码器工作原理

以前的代码是通过触发外部中断,然后在中断函数里手动进行计次。使用编码器接口的好处就是节约软件资源。对于频繁执行,操作简单的任务,一般设计一个硬件电路模块来自动完成。

使用定时器的编码器接口,再配合编码器,就可以测量旋转速度和旋转方向。编码器测速一般应用在电机控制的项目上。使用PWM驱动电机,再使用编码器测量电机的速度,然后再使用PID算法进行闭环控制。

平横车经常用到

1.计数方式

 2.框图分析

 由图可知,只有CH1和CH2有编码器接口,且编码器只用到了输入捕获结构体的输入滤波和边沿检测器,则其余的结构体成员都不用区配置。

 由框图可知,配置Encoder需要配置GPIO,输入捕获结构体的部分元素,时基单元,我们一般给ARR为65535-1,即最大计数量程,防止计数溢出。PSC=1-1,不分频,直接72M进行计数

3.计数方向与编码器信号的关系

 TIM_EncoderInterfaceConfig(TIM3,TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICPolarity_Rising)

这里TIM_EncoderMode_TI12即对应上面的计数边沿,仅在TI1和TI2计数就相当于只在A或B相的边沿计数,我们一般都使用AB相都计数

极性修改:可以使用上方的函数进行,也可以硬件直接调换AB相引脚

三、固件库使用

 

1.开启GPIO和TIM的时钟

2.配置GPIO结构体,模式配置为上拉输入

3.不用配置内部时钟源,因为编码器托管了时钟,编码器接口就是带方向控制的外部时钟,      所以内部时钟就没有用了    

4.配置时基单元,计数模式就不用配置了,取决于编码器的AB相边沿,ARR为65535-1,     PSC = 1-1不分频

5.配置输入捕获单元(因为是由)TI1FP1和2接入到编码器接口的,所以捕获单元结构体    元素只需配置输入滤波和边沿检测即可,这里边沿检测给上升沿还是下降沿并不是说是

   哪个有效,因为编码器模式下上/下沿都有效,这里指电平极性是否翻转,高电平不反转,

    低电平翻转

6.TIM_EncoderInterfaceConfig();配置编码器,TIM_Cmd();使能定时器

7.使用中断读取Encoder的值(测速度)

   若要测位置就直接读取Encoder的值即可,不需要中断

上拉输入还是下拉输入的选择

一般可以看一下接在这个引脚的外部模块输出的默认电平,如果外部模块空闲默认输出高电平,我们就选择上拉输入,默认输入高电平,如果外部模块默认输出低电平,我们配置下拉输入,默认输入低电平。总结,将需要配置电平的位置和外部模块保持默认状态一致,防止默认电平打架。

如果不确定外部模块输出的默认状态或者外部信号输出功率非常小,这时尽量选择浮空输入,浮空输入没有上下拉电阻去影响外部信号,缺点是当引脚悬空时,没有默认电平,输入就会受噪声干扰,来回不断跳变。

测位置:A、B相各出现了一个下降沿和上升沿,所以计次总共加了4次。

               如果转到0,再往左转,0自减,计数器反向溢出,回到自动重装值,65535,然后继续往下减

                解决方法是:如果我们想让0自减为-1,直接把uint16_t类型强制转换成int16_t即可

 

如果想让编码器测速度,可以在固定的闸门时间读一次CNT,然后把CNT清零,此时CNT的值代表速度,单位是脉冲个数/S 

(测频法)

#include "encoder.h"


void Encoder_Init(void)
{
	//开启GPIO和TIM3时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	
	//初始化GPIO
	GPIO_InitTypeDef GPIO_InitStruct;//定义GPIO结构体
	//GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;//输入不需要配置速度
	GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_IPU;
	GPIO_InitStruct.GPIO_Pin   = GPIO_Pin_6 | GPIO_Pin_7;
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	
	//因为编码器接口会托管时钟,编码器接口就是带方向控制的外部时钟,所以内部时钟就没有用了	
	//TIM_InternalClockConfig(TIM2);
	
	//配置时基单元
	//初始化时基单元
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	TIM_TimeBaseInitStruct.TIM_Prescaler = 1-1;//PSC-预分频器,给0,不分频
	//TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;//计数方向被编码器托管了
	TIM_TimeBaseInitStruct.TIM_Period = 65535-1;//ARR寄存器-重装载寄存器
	TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;/*不分频----滤波器的采样频率,                                    
                                                                  可以由内部时钟直接提供,														                 
                                                        也可以由内部时钟加一个时钟分频而来,
												分频系数就是由TIM_ClockDivision决定*/
	TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;//重复计数器,只有高级定时器才有	
	TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct);

	//配置输入捕获单元
	TIM_ICInitTypeDef TIM_ICInitStruct;
	TIM_ICStructInit(&TIM_ICInitStruct);
	TIM_ICInitStruct.TIM_Channel = TIM_Channel_1;
	TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;//电平极性选择,高电平极性不反        
                                                                 转,低电平极性反转
	//TIM_ICInitStruct.TIM_ICSelection //直连or交叉连
	//TIM_ICInitStruct.TIM_ICPrescaler //分频器因子,即每N个边沿跳变事件捕获一次-CCMR1_ICPS
	TIM_ICInitStruct.TIM_ICFilter = 0xF;//CCMR1_ICF
	TIM_ICInit(TIM3, &TIM_ICInitStruct);
	
	TIM_ICInitStruct.TIM_Channel = TIM_Channel_2;
	TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;//电平极性选择,高电平极性不反    
                                                             转,低电平极性反转
	TIM_ICInitStruct.TIM_ICFilter = 0xF;//CCMR1_ICF
	TIM_ICInit(TIM3,&TIM_ICInitStruct);
	
	TIM_EncoderInterfaceConfig(TIM3,TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICPolarity_Rising);//这里的上升沿和上面结构体配置的效果一样,所以前面的可以删去

	//使能TIM
	TIM_Cmd(TIM3,ENABLE);
}

int16_t Encoder_Get(void)//int16_t 为了显示负数
{
	int16_t temp;
	temp = TIM_GetCounter(TIM3);
	TIM_SetCounter(TIM3,0);//这里每次获得了编码器的值后就清零CNT是为了得到速度
                           //我们使用了中断,一秒进入一次然后读取CNT的值作为旋转速度
	return temp;
}

#include "bsp_tim.h"

void Time_Config()
{
	//开启时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
	
	//选择时基单元的时钟-为内部时钟--定时器上电后默认是内部时钟,故不写这一个也行
	TIM_InternalClockConfig(TIM2);
	
	//初始化时基单元
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	TIM_TimeBaseInitStruct.TIM_Prescaler = 7200-1;//PSC-预分频器
	TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;//向上计数 
	TIM_TimeBaseInitStruct.TIM_Period = 10000-1;//ARR寄存器-重装载寄存器
	TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;/*不分频----滤波器的采样频率,可以由内部时钟直接提供,
																													也可以由内部时钟加一个时钟分频而来,
																													分频系数就是由TIM_ClockDivision决定*/
	TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;//重复计数器,只有高级定时器才有
	
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct);
	
	//使能中断-事件更新
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
	
	TIM_ClearFlag(TIM2,TIM_IT_Update);//因为TIM_TimeBaseInit函数最后有一个直接操作UG位的操作
	                                  //使得直接产生了一个更新事件,因此直接进行给UIE位置1
									 //直接进入了中断,使得我们初始化ARR和PSC还未写入到
									//影子寄存器,使得Num一上电就是1
									//所以在进入中断之前先清楚中断标志位
	
	//使能中断之后就要进入NVIC了
	//先优先级分组
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
	//配置结构体
	NVIC_InitTypeDef NVIC_InitStruct;
	NVIC_InitStruct.NVIC_IRQChannel = TIM2_IRQn;//中断通道
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStruct);
	
	//启动定时器
	TIM_Cmd(TIM2,ENABLE);
	//在_it文件里编写中断服务函数
}

#include ".\tim\bsp_tim.h"
#include "encoder.h"
#include ".\OLED\OLED.h"



int16_t speed;
int main()
{
	Time_Config();
	Encoder_Init();
	OLED_Init();
	while(1)
	{
		OLED_ShowSignedNum(1,5,speed,5);
	}
}
void TIM2_IRQHandler()
{
	//先获取中断标志位
	if(TIM_GetITStatus(TIM2,TIM_IT_Update) == SET)
	{
		speed = Encoder_Get();
		//清楚中断标志位
		TIM_ClearFlag(TIM2,TIM_FLAG_Update);
	}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1520179.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

QT下跨平台库实现及移植经验分享

最近在移植公司一个QT桌面软件到android上,有一些公司自定义的库,用了很多windows的api,移植过程很是曲折,在此有一些感悟分享一下~ 一.自编写跨平台库 1.有时候为了程序给第三方用需要编译一些qt封装库,并可能跨平台…

思科防火墙如何进行ACL操作

环境: 思科防火墙ASA5555 Cisco Adaptive Security Appliance Software Version 9.4(2)6 Device Manager Version 7.5(2)153 问题描述: 思科防火墙如何进行ACL操作 解决方案: 进入en模式 1.查看现有全部list show running-config | i…

stm32-定时器输出比较PWM

目录 一、输出比较简介 二、PWM简介 三、输出比较模式实现 1.输出比较框图(以通用定时器为例) 2.PWM基本结构 四、固件库实现 1.程序1:PWM呼吸灯 2.程序2:PWM驱动直流电机 3.程序3:控制舵机 一、输出比较简介 死区生成和互补输出一般…

Tomcat Session集群---会话绑定

实验配置: 7-1安装Nginx 7-2和7-3安装Tomcat 1.配置7-1 1.做负载均衡,反向代理 [rootlocalhost ~]# vim /etc/nginx/nginx.conf17 http {18 upstream tomcat {19 server 192.168.91.102:8080;20 server 192.168.91.103:8080;2…

ideaSSM校医院管理网页模式开发mysql数据库web结构java编程计算机网页源码maven项目

一、源码特点 idea ssm 校医院管理系统是一套完善的完整信息管理系统,结合SSM框架完成本系统SpringMVC spring mybatis ,对理解JSP java编程开发语言有帮助系统采用SSM框架(MVC模式开发), 系统具有完整的源代码和数据…

HarmonyOS应用开发者高级认证答案

** HarmonyOS应用开发者高级认证 ** 以下是高级认证答案,存在个别选项随机顺序答案,自行辨别 判断题 云函数打包完成后,需要到 AppGallery Connect 创建对应函数的触发器才可以在端侧中调用 错 在 column 和 Row 容器组件中,a…

UDF提权

目录 一、UDF概述 二、提权条件 三、漏洞复现 (一) 信息收集 1. Nmap信息收集 1.1、查看当前IP地址 1.2、扫描当前网段,找出目标机器 1.3、快速扫描目标机全端口 2. dirb目录扫描 3. 第一个flag 3.1、目录遍历漏洞 3.2、flag 4. 敏感信息利用 (二) 漏…

Hive-技术补充-初识ANTLR

一、背景 要清晰的理解一条Hql是如何编译成MapReduce任务的,就必须要学习ANTLR。下面是ANTLR的官方网址,下面让我们一起来跟着官网学习吧,在学习的过程中我参考了《antlr4权威指南》,你也可以读下这本书,一定会对你有…

labview技术交流-判断两个数组的元素是否完全相同

问题来源 分析并判断两个一维数组中包含的元素是否完全相同,不考虑索引顺序。比如说[1,5,7,3]和[3,5,7,1]是完全相同的两个一维数组,那[1,5,7,3]和[5,7,1,4]就不是相同的数组。结合我给出的示例,大家有没有什么思路呢? 思路分析 …

Java数据结构-优先级队列

文章目录 前言一、优先级队列1.1 概念 二、优先级队列的模拟实现2.1 堆的概念2.2 堆的存储方式2.3 堆的创建2.3.1 堆向下调整2.3.2 堆的创建2.3.3 建堆的时间复杂度 2.4 堆的插入与删除2.4.1 堆的插入2.4.2 堆的删除 2.5 用堆模拟实现优先级队列 三、常用接口介绍3.1 PriorityQ…

MediaBox音视频终端SDK已适配鸿蒙星河版(HarmonyOS NEXT)

2024年1月,HarmonyOS NEXT 鸿蒙星河版系统开发者预览版开放申请,该系统将只能安装为鸿蒙开发的原生应用,而不再兼容安卓应用。对此,阿里云MediaBox音视频终端SDK产品已实现功能的鸿蒙化迁移和重构,全面适配鸿蒙系统Har…

Html提高——HTML5 新增的语义化标签

引入&#xff1a; 以前布局&#xff0c;我们基本用 div 来做。div 对于搜索引擎来说&#xff0c;是没有语义的。 但是在html5里增加了语义化标签&#xff0c;如 <header>&#xff1a;头部标签 <nav>&#xff1a;导航标签 <article>&#xff1a;内容标签 &…

ASP.NET Mvc+FFmpeg+Video实现视频转码

目录 首先&#xff0c;做了视频上传的页面&#xff1a; FFmpeg&#xff1a;视频转码 FFmpegHelper工作类&#xff1a; 后台控制器代码&#xff1a; 前端视图代码&#xff1a; 参考文章&#xff1a; 首先&#xff0c;做了视频上传的页面&#xff1a; 借鉴了这篇文章 ASP.…

Qt学习--this指针的使用

在 C 中&#xff0c;this 指针是一个特殊的指针&#xff0c;它指向当前对象的实例。 在 C 中&#xff0c;每一个对象都能通过 this 指针来访问自己的地址。 this是一个隐藏的指针&#xff0c;可以在类的成员函数中使用&#xff0c;它可以用来指向调用对象。 当一个对象的成员…

【算法杂货铺】二分算法

目录 &#x1f308;前言&#x1f308; &#x1f4c1; 朴素二分查找 &#x1f4c2; 朴素二分模板 &#x1f4c1; 查找区间端点处 细节&#xff08;重要&#xff09; &#x1f4c2; 区间左端点处模板 &#x1f4c2; 区间右端点处模板 &#x1f4c1; 习题 1. 35. 搜索插入位…

实验01 ASP.NET网站的建立及运行

【实验目的】 &#xff08;1&#xff09;能熟悉ASP.NET的开发环境Visual Studio Community 2019&#xff08;VSC 2019&#xff09;。 &#xff08;2&#xff09;能通过解决方案管理网站&#xff0c;会在解决方案中创建网站。 &#xff08;3&#xff09;会设置IIS 10中的网站…

德迅蜂巢(容器安全)全面出击

随着云计算的发展&#xff0c;以容器和微服务为代表的云原生技术&#xff0c;受到了人们的广泛关注&#xff0c;德迅云安全德迅蜂巢&#xff08;容器安全&#xff09;是企业容器运行时和容器编排的首要选择。然而&#xff0c;在应用容器过程中&#xff0c;大多数企业都遇到过不…

VS2022 配置QT5.9.9

QT安装 下载地址&#xff1a;https://download.qt.io/archive/qt/ 下载安装后进行配置 无法运行 rc.exe 下载VS2022 官网下载 配置 1.扩展-管理扩展-下载Qt Visual Studio Tools 安装 2.安装完成后&#xff0c;打开vs2022,点击扩展&#xff0c;会发现多出了QT VS Tools,点…

应用层_HTTPHTTPS

在应用层中&#xff0c;协议一般是程序员定制的&#xff0c;但现在已经有了许多非常好用的协议&#xff0c;我们可以直接参考使用。其中http和https便是其中最常用的协议之一。 一.HTTP 超文本传输协议&#xff08;Hypertext Transfer Protocol&#xff0c;HTTP&#xff09;…

Unreal发布Android App如何面对混乱的Android SDK开发环境

Unreal发布Android App如何面对混乱的Android SDK开发环境 混乱的Android SDK开发环境Unreal 4可以借用Unity3D安装的Android环境Unreal 5需要安装Android Studio开发环境Android Studio的DK版本目录处理gradle和java版本gradle提示错误总结 混乱的Android SDK开发环境 Unreal…