stm32-编码器测速

一、编码器简介

编码电机

旋转编码器

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

老电脑装什么系统流畅

对于一些老旧电脑来说,重装系统是提升电脑性能的最佳选择。那么,老电脑装什么系统流畅呢?推荐Windows 7系统,它对硬件的需求相对较低。配置较低的电脑运行Windows 7可以更好地利用系统资源,提高电脑的运行速度和响应能…

javaweb-maven+HTTP协议+Tomcat+SpringBoot入门+请求+响应+分层解耦

Maven IDEA集成Maven 依赖管理 依赖配置 maven是插件完成对应的工作的~ 哇哇哇maven看完啦~~~~~~ Spring.io Springboot是Spring家族的子项目,可以帮助我们非常快速地构建应用程序,简化开发,提高效率。 RestController请…

因聚而生 数智有为丨软通动力携子公司鸿湖万联亮相华为中国合作伙伴大会2024

3月14日,以“因聚而生 数智有为”为主题的“华为中国合作伙伴大会2024”在深圳隆重开幕。作为华为的重要合作伙伴和本次大会钻石级(最高级)合作伙伴,软通动力深度参与本次盛会,携前沿数智化技术成果和与华为的联合解决…

DVWA靶场-CSRF跨站请求伪造

CSRF(跨站请求伪造)简介概念 CSRF(Cross—site request forgery),跨站请求伪造,是指利用受害者未失效的身份认证信息(cookie,会话等),诱骗其点击恶意链接或者访问包含攻击代码的页面…

AJAX学习(四)

版权声明 本文章来源于B站上的某马课程,由本人整理,仅供学习交流使用。如涉及侵权问题,请立即与本人联系,本人将积极配合删除相关内容。感谢理解和支持,本人致力于维护原创作品的权益,共同营造一个尊重知识…

国产Copilot--通义灵码安装教程

文章目录 在 Visual Studio Code 中安装通义灵码步骤1步骤2步骤3步骤4 参考 在 Visual Studio Code 中安装通义灵码 通义灵码,是一款基于通义大模型的智能编码辅助工具,提供行级/函数级实时续写、自然语言生成代码、单元测试生成、代码注释生成、代码解…

Xcode调试Qt 源码

在Mac下使用Xcode 开发Qt程序,由于程序断点或者崩溃后,Qt库的堆栈并不能够正确定位到源码的cpp文件,而是显示的是汇编代码,导致不直观的显示。 加载的其他三方库都是同理。 所以找了攻略和研究后,写的这篇文章。 一&a…

Java_12 杨辉三角 II

杨辉三角 II 给定一个非负索引 rowIndex,返回「杨辉三角」的第 rowIndex 行。 在「杨辉三角」中,每个数是它左上方和右上方的数的和。 示例 1: 输入: rowIndex 3 输出: [1,3,3,1] 示例 2: 输入: rowIndex 0 输出: [1] 示例 3: 输入: rowIndex 1 输…

供电系统分类详解

一、供电系统分类 电力供电系统一般有5种供电模式,常用的有:IT系统,TT系统,TN系统,其中TN系统又可以分为TN-C,TN-S,TN-C-S。 1、TN-C系统(三相四线制) 优点: 该系统中…

193基于matlab的基于两轮驱动机器人的自适应轨迹跟踪算法

基于matlab的基于两轮驱动机器人的自适应轨迹跟踪算法,将被跟踪轨迹分段作为跟踪直线处理,相邻离散点之间为一段新的被跟踪轨迹。程序已调通,可直接运行。 193 自适应轨迹跟踪算法 两轮驱动机器人 - 小红书 (xiaohongshu.com)

传输层_TCPUDP

应用层中调用write/sendrecv/read这些系统接口,并没有将数据发送到网络中,而是向下交付到传输层协议,具体什么时候发送数据,由传输层根据一些策略进行数据的实际发送。传输层的主要功能就是负责数据的传输,包括如果数据…

【学习】PyTorch中的nn.Embedding的用法

基本理解 nn.Embedding(num_embeddings, embedding_dim)其中 num_embeddings 是词表的大小,即 len(vocab);embedding_dim 是词向量的维度。 nn.Embedding()产生一个权重矩阵weight,其shape为(num_embeddings, embedding_dim&…

Java代码审计安全篇-反序列化漏洞

前言: 堕落了三个月,现在因为被找实习而困扰,着实自己能力不足,从今天开始 每天沉淀一点点 ,准备秋招 加油 注意: 本文章参考qax的网络安全java代码审计和部分师傅审计思路以及webgoat靶场,记录…

Go-知识select

Go-知识select 1. select 的特性1.1 chan读写1.2 返回值1.3 default 2. select 经典使用2.1 永久阻塞2.2 快速检错2.3 限时等待 3. 实现原理3.1 数据结构3.2 实现逻辑3.3 原理总结 4. 总结4.1 大概原理4.2 参数4.3 返回值 一个小活动: https://developer.aliyun.com…

AMRT 3D 数字孪生引擎(轻量化图形引擎、GIS/BIM/3D融合引擎):智慧城市、智慧工厂、智慧建筑、智慧校园。。。

AMRT3D 一、概述 1、提供强大完整的工具链 AMRT3D包含开发引擎、资源管理、场景编辑、UI搭建、项目预览和发布等项目开发所需的全套功能,并整合了动画路径、精准测量、动态天气、视角切换和动画特效等工具。 2、轻量化技术应用与个性化定制 AMRT3D适用于快速开…

openGauss学习笔记-243 openGauss性能调优-SQL调优-典型SQL调优点-子查询调优

文章目录 openGauss学习笔记-243 openGauss性能调优-SQL调优-典型SQL调优点-子查询调优243.1 子查询调优243.1.1 子查询背景介绍243.1.2 openGauss对SubLink的优化243.1.3 更多优化示例 openGauss学习笔记-243 openGauss性能调优-SQL调优-典型SQL调优点-子查询调优 SQL调优是一…

Scala--01--简介、环境搭建

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 1. Scala简介1.1 Scala是什么?官网: [https://scala-lang.org/](https://scala-lang.org/)官方文档: [https://docs.scala-lang.…

WPF布局、控件与样式

视频来源:https://www.bilibili.com/video/BV1HC4y1b76v/ 布局 常用布局属性 HorizontalAlignment:用于设置元素的水平位置VerticalAlignment:用于设置元素的垂直位置Margin:指定元素与容器的边距Height:指定元素的…

音频提取:分享几个常用方法,简单好用

有时候我们会在视频中发现一首非常好听的歌曲,但是我们并不需要视频本身。 这时,我们可以提取视频中的音频,将其转化为音频文件,然后在任何时间、任何地点进行欣赏。 下面给大家分享几个提取视频中音频的几个方法,供…

[嵌入式AI从0开始到入土]16_ffmpeg_ascend编译安装及性能测试

[嵌入式AI从0开始到入土]嵌入式AI系列教程 注:等我摸完鱼再把链接补上 可以关注我的B站号工具人呵呵的个人空间,后期会考虑出视频教程,务必催更,以防我变身鸽王。 第1期 昇腾Altas 200 DK上手 第2期 下载昇腾案例并运行 第3期 官…