STM32F407 电机编码器测量

news2024/10/6 16:24:03

文章目录

  • 一、STM32F407 定时器编码器功能
    • 1.1 STM32定时器简介
    • 1.2 STM32定时器编码器功能
  • 二、带编码器的直流电机
  • 三、代码与验证
      • 3.1 初始化代码
      • 3.2 验证

一、STM32F407 定时器编码器功能

1.1 STM32定时器简介

STM32的定时器功能非常强大,根据官方手册,定时器的功能如下
高级定时器
TIM1 和 TIM8 主要特性
TIM1 和 TIM8 定时器具有以下特性:
● 16 位递增、递减、递增/递减自动重载计数器。
● 16 位可编程预分频器,用于对计数器时钟频率进行分频(即运行时修改),分频系数
介于 1 到 65536 之间。
● 多达 4 个独立通道,可用于:
— 输入捕获
— 输出比较
— PWM 生成(边沿和中心对齐模式)
— 单脉冲模式输出
● 带可编程死区的互补输出。
● 使用外部信号控制定时器且可实现多个定时器互连的同步电路。
● 重复计数器,用于仅在给定数目的计数器周期后更新定时器寄存器。
● 用于将定时器的输出信号置于复位状态或已知状态的断路输入。
● 发生如下事件时生成中断/DMA 请求:
— 更新:计数器上溢/下溢、计数器初始化(通过软件或内部/外部触发)
— 触发事件(计数器启动、停止、初始化或通过内部/外部触发计数)
— 输入捕获
— 输出比较
— 断路输入
● 支持定位用增量(正交)编码器和霍尔传感器电路。
● 外部时钟触发输入或逐周期电流管理。

通用定时器
TIM2 到 TIM5 主要特性
通用 TIMx 定时器具有以下特性:
● 16 位(TIM3 和 TIM4)或 32 位(TIM2 和 TIM5) 递增、递减和递增/递减自动重载计
数器。
● 16 位可编程预分频器,用于对计数器时钟频率进行分频 (即运行时修改),分频系数介
于 1 到 65536 之间。
● 多达 4 个独立通道,可用于:
— 输入捕获
— 输出比较
— PWM 生成(边沿和中心对齐模式)
— 单脉冲模式输出
● 使用外部信号控制定时器且可实现多个定时器互连的同步电路。
● 发生如下事件时生成中断/DMA 请求:
— 更新:计数器上溢/下溢、计数器初始化(通过软件或内部/外部触发)
— 触发事件(计数器启动、停止、初始化或通过内部/外部触发计数)
— 输入捕获
— 输出比较
● 支持定位用增量(正交)编码器和霍尔传感器电路
● 外部时钟触发输入或逐周期电流管理

1.2 STM32定时器编码器功能

根据下面的图可以看出通用定时器也是有编码器输入功能。
在这里插入图片描述

在编码输入时是有上升沿与下降沿的,我们可以利用外部中断分别捕获编码器A、B项边沿,手写逻辑消除毛刺并解析编码器数据,但这是比较复杂的。其实这里的脉冲输入是一种特殊的输入捕获情况,因此stm32专门在定时器中提供了编码器模式,可大大简化解析过程。

选择编码器接口模式时,如果计数器仅在 TI2 边沿处计数,在 TIMx_SMCR 寄存器中写入
SMS=001;如果计数器仅在 TI1 边沿处计数,写入 SMS=010;如果计数器在 TI1 和 TI2 边 沿处均计数,则写入 SMS=011。

通过编程 TIMx_CCER 寄存器的 CC1P 和 CC2P 位,选择 TI1 和 TI2 极性。如果需要,还可对输入滤波器进行编程TI1 和 TI2 两个输入用于连接增量编码器。请参见表 75。如果使能计数器(在 TIMx_CR1 寄 存器的 CEN 位中写入“1”),则计数器的时钟由 TI1FP1 或 TI2FP2 上的每次有效信号转 换提供。TI1FP1 和 TI2FP2 是进行输入滤波器和极性选择后 TI1 和 TI2 的信号,如果不进行 滤波和反相,则 TI1FP1=TI1,TI2FP2=TI2。将根据两个输入的信号转换序列,产生计数脉 冲和方向信号。根据该信号转换序列,计数器相应递增或递减计数,同时硬件对 TIMx_CR1 寄存器的 DIR 位进行相应修改。任何输入(TI1 或 TI2)发生信号转换时,都会计算 DIR 位,无论计数器是仅在 TI1 或 TI2 边沿处计数,还是同时在 TI1 和 TI2 处计数。

编码器接口模式就相当于带有方向选择的外部时钟。这意味着,计数器仅在 0 到 TIMx_ARR 寄存器中的自动重载值之间进行连续计数(根据具体方向,从 0 递增计数到 ARR,或从 ARR 递减计数到 0)。因此,在启动前必须先配置 TIMx_ARR。同样,捕获、比较、预分频 器、触发输出功能继续正常工作。

在此模式下,计数器会根据增量编码器的速度和方向自动进行修改,因此,其内容始终表示编码器的位置。计数方向对应于所连传感器的旋转方向。下表汇总了可能的组合(假设 TI1 和 TI2 不同时切换)。
在这里插入图片描述
下图为双项模式下计数效果,可见在A、B中仅一项有**抖动(**就是编译器无效的脉冲,需要过滤)时,计数值加减后保持不变,实现了抖动补偿
在这里插入图片描述
从图上可以看出,定时器是采集A、B两相的脉冲,当编码器输出一个周期时,定时器计数值为4,这是要必须记住的哈。

二、带编码器的直流电机

我手上刚好有一个带编码器的直流电机,电机参数如下,520电机包含编码器款该电机采用全金属齿轮,具备功率大、抗干扰好、精度高、寿命长的特点。
在这里插入图片描述
在这里插入图片描述
在这里需要说明一下,如果电机转一圈,那么黄线输出的脉冲数量为:1130 = 330个, 那么绿线输出的脉冲数量为:1130 = 330个。根据上面分析的定时器编码器模式,电机转一圈,定时器计数脉冲的个数为:330*4 = 1320个。

三、代码与验证

电机实物图
在这里插入图片描述

3.1 初始化代码

/****************************************
引脚说明

A相连接PB6
B相连接PB7

PB6 -- TIM4_CH1
PB7 -- TIM4_CH2

****************************************/

void TIM4_Int_Init(void) 
{		
	GPIO_InitTypeDef 	        GPIO_InitStruct;
	TIM_TimeBaseInitTypeDef	 	TIM_TimeBaseInitStructure;
	TIM_ICInitTypeDef 			TIM_ICInitStructure;
	NVIC_InitTypeDef			NVIC_InitStructure;
		
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE);//开启GPIOC的时钟
	

	
	GPIO_InitStruct.GPIO_Pin  	= GPIO_Pin_6|GPIO_Pin_7;
	GPIO_InitStruct.GPIO_Mode	= GPIO_Mode_AF;
	GPIO_InitStruct.GPIO_Speed	= GPIO_Speed_100MHz;
	GPIO_InitStruct.GPIO_OType	= GPIO_OType_OD;
	GPIO_InitStruct.GPIO_PuPd	=  GPIO_PuPd_UP;
	
	GPIO_Init(GPIOB, &GPIO_InitStruct);                          
	
	GPIO_PinAFConfig(GPIOB,GPIO_PinSource6,GPIO_AF_TIM4);//将引脚6映像到TIM8
    GPIO_PinAFConfig(GPIOB,GPIO_PinSource7,GPIO_AF_TIM4);//将引脚7映像到TIM8
	
		

  //定时器设置-------------------------------------------------------------	
    TIM_TimeBaseInitStructure.TIM_Period = 330*4;   				//重装载值 这是两相脉冲总数量
	TIM_TimeBaseInitStructure.TIM_Prescaler=0x0; 				 	//预分频
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; 	//向上计数
	TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; 		//时钟分割
	
	TIM_TimeBaseInit(TIM4,&TIM_TimeBaseInitStructure);//初始化TIM3

    //编码器模式设置--------------------------------------------------------------			  		

	TIM_EncoderInterfaceConfig(TIM4,TIM_EncoderMode_TI12,TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//计数模式3
	
	TIM_ICStructInit(&TIM_ICInitStructure); 
    TIM_ICInitStructure.TIM_ICFilter = 10;  //滤波器值
    TIM_ICInit(TIM4, &TIM_ICInitStructure);
    //溢出中断设置--------------------------------------------------------------
	TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE); //允许TIM4溢出中断
	
	NVIC_InitStructure.NVIC_IRQChannel					=TIM4_IRQn; 
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x01; 
	NVIC_InitStructure.NVIC_IRQChannelSubPriority		=0x01; 
	NVIC_InitStructure.NVIC_IRQChannelCmd				=ENABLE;
	NVIC_Init(&NVIC_InitStructure);
  
   //Reset counter-----------------------------------------------
   TIM_SetCounter(TIM4,0); //TIM3->CNT=0
   TIM_Cmd(TIM4, ENABLE); 
}




主函数

int Encoder_Timer_Overflow; //编码器溢出次数
 
u16 Previous_Count; 
u32 speed=0;
int circle_count = 0;   //记录电机正反转

//void TIM8_CC_IRQHandler(void)
//{
//	if(TIM_GetITStatus(TIM8,TIM_IT_Update)==SET)
//	{
//		Encoder_Timer_Overflow++;
//	}
//	TIM_ClearITPendingBit(TIM8,TIM_IT_Update); 

//}

//电机转动一圈产生中断
void TIM4_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM4,TIM_IT_Update)==SET)
	{
		Encoder_Timer_Overflow++;
		
		
		if((TIM4->CR1>>4 & 0x01)==0)     //DIR==0  通过寄存器TIMx_CR1第四位判断  0:电机正转
			circle_count++;
		else if((TIM4->CR1>>4 & 0x01)==1)//DIR==1  通过寄存器TIMx_CR1第四位判断  1:电机正转
			circle_count--;
	}
	TIM_ClearITPendingBit(TIM4,TIM_IT_Update); 

}
 
void Read_Encoder(void)
{
                                                       
  u16 Current_Count;           //一段时间的脉冲数                                  
  u16 Enc_Timer_Overflow_one;  //当前脉冲数                                  
                    
  Enc_Timer_Overflow_one=Encoder_Timer_Overflow;                  //获取中断溢出次数  
  Current_Count = TIM_GetCounter(TIM4);                           //得到脉冲数
  Encoder_Timer_Overflow=0;                                       //清0方便下次计算

  //speed = (u32)(Enc_Timer_Overflow_one*车轮周长+Current_Count/(330*4.0)*车轮周长);   //进行平均测速
 
}





int main(void)
{
	u16 m = 0,n = 0;
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	
	Delay_Init();
	usart1_init(115200);
	//TIM8_Int_Init();
	TIM4_Int_Init();
	
	
	while(1)
	{	


		delay_ms(500);
		delay_ms(500);
		//CNT的值,能够表示当前获取了多少个脉冲
		printf("获取定时器中的CNT值:%d\r\n",TIM4->CNT);
		//值为正,表示正转圈数比反转圈数多,反之亦然;值递增,表示正在正转,值递减,表示正在反转。
		printf("目前轮子正或反的圈数:%d\r\n",circle_count);

	}
	
	return 0;
}


3.2 验证

在这里插入图片描述

总结一下,通过对这些的理解,那么可以计算速度、角度、加速度等。
最后代码链接:https://download.csdn.net/download/wwwqqq2014/87124313?spm=1001.2014.3001.5503

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

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

相关文章

旅游网页设计 web前端大作业 全球旅游私人订制 旅游公司网站模板(HTML+CSS+JavaScript)

👨‍🎓学生HTML静态网页基础水平制作👩‍🎓,页面排版干净简洁。使用HTMLCSS页面布局设计,web大学生网页设计作业源码,这是一个不错的旅游网页制作,画面精明,排版整洁,内容…

OctaneRender界面布局自定义界面教程丨使用教程

您可以通过单击并拖动每个窗格左上角的方块(图 1)来重新排列 OctaneRender 界面(图形编辑器、渲染视口、节点检查器和大纲视图)中每个窗格的窗口。 图 1:窗格排列图标 用任何鼠标按钮单击同一个方块会显示更多用于…

SpringBoot SpringBoot 开发实用篇 5 整合第三方技术 5.20 ActiveMQ 安装

SpringBoot 【黑马程序员SpringBoot2全套视频教程,springboot零基础到项目实战(spring boot2完整版)】 SpringBoot 开发实用篇 文章目录SpringBootSpringBoot 开发实用篇5 整合第三方技术5.20 ActiveMQ 安装5.20.1 下载5.20.2 安装5.20.3 使…

[附源码]SSM计算机毕业设计基于的城镇住房公积金管理系统JAVA

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

Unity Hair 毛发系统 初体验

文章目录🎈 简介🎈 所需环境🎈 下载安装🎈 使用初体验🍭 创建一个Hair示例🍭 Hair Asset🍭 尝试给Avatar创建头发🍭 如何更改材质🎈 简介 8月份的时候Unity官方发布了Ha…

第7章 Elasticsearch面试题

7 . 1 为什么要使用Elasticsearch? 系统中的数据,随着业务的发展,时间的推移,将会非常多,而业务中往往采用模糊查询进行数据的搜索,而模糊查询会导致查询引擎放弃索引,导致系统查询数据时都是全表扫描&am…

即将见面:SpreadJS V16:重大改进

内容摘自互联网::::::: 新功能背景:在SpreadJS V16之前,关于文件toJSON()之后,生成的json文件太大,一直被很多客户诟病。例如,同样一…

PySide创建界面关联项目(五) 百篇文章学PyQT

本文章是百篇文章学PyQT的第五篇,本文讲述如何使用PySide创建UI界面,并且关联入PyCharm 新建的项目中成功运行第一个PyQT程序,博主在本篇文章中将遇到和踩过的坑总结出来,可以供大家参考,希望大家安装顺利。包括 安装、…

我的Vue组件化开发首个项目todolist

TodoList 学习笔记: 总结TodoList案例 1.组件化编码流程: (1).拆分静态组件:组件要按照功能点拆分,命名不要与htm|元素冲突。 (2).实现动态组件:考虑好数据的存放位置,数据是一个组件在用, 还是一些组件在用: . 1).-个组件在…

Vue简单实例——从webpack到vue,再到weex

这一章节,我们主要针对从webpack,vue,weex的框架结构上来说明对比这三个框架的区别 主要功能: webpack: webpack是前端项目工程化的具体解决方案。 它提供了友好的前端模块化开发支持,以及代码压缩混淆&…

基于身份的分段:三种技术路线解析与建议

SmartX 趋势分享 SmartX 趋势分享由 SmartX 团队内部分享的权威机构市场报告、全球重要媒体文章精选整理而成。内容涉及现代数据中心相关产业趋势以及金融、医疗、制造等行业全球用户需求与实践前沿洞察。在“零信任实践”系列的第一篇文章中,我们介绍了两种实现零信…

基于springboot“漫画之家”系统设计与实现-计算机毕业设计源码+LW文档

摘 要 随着信息技术和网络技术的飞速发展,人类已进入全新信息化时代,传统管理技术已无法高效,便捷地管理信息。为了迎合时代需求,优化管理效率,各种各样的管理系统应运而生,各行各业相继进入信息管理时代&a…

vue3+ts部分场景示例

模板语法 插值变量 div{{插值}}div const message: number 84; 指定变量为数字类型 const message: string小明 ; 指定字符串类型 const message: booleanfalse ; 指定布尔值类型 const message: any小明 ; any指定任意类型 const message: object{} ; 指定对象…

代码随想录算法训练营第七天|二叉树(截止到层序遍历)

二叉树的递归遍历 递归遍历是最简单的 // 前序 class Solution { public:void traversal(TreeNode* cur, vector<int>& vec) {if (cur NULL) return;vec.push_back(cur->val); // 中traversal(cur->left, vec); // 左traversal(cur->right, vec); //…

【高级篇】线程与线程池

一、线程回顾 1、初始化线程的 4 种方式 1&#xff09;、继承 Thread public static class Thread01 extends Thread{Overridepublic void run() {System.out.println("当前线程&#xff1a;"Thread.currentThread().getId());int i 10 / 2;System.out.println(&qu…

web前端期末大作业——HTML+CSS简单的旅游网页设计与实现

&#x1f468;‍&#x1f393;静态网站的编写主要是用 HTML DⅣV CSSJS等来完成页面的排版设计&#x1f469;‍&#x1f393;&#xff0c;一般的网页作业需要融入以下知识点&#xff1a;div布局、浮动定位、高级css、表格、表单及验证、js轮播图、音频视频Fash的应用、uli、下拉…

项目上云实战:如何把Java项目搬上云服务器?

1.中小型企业项目开发完成后应如何运行&#xff1f; 最近在后台私信中&#xff0c;很多小伙伴问询博主&#xff0c;中小企业项目开发完成后&#xff0c;是否在pc机上直接运行。答案是否定的&#xff0c;专业的软件开发企业都会选择linux服务器作为运行环境&#xff0c;企业服务…

[附源码]java毕业设计学生档案管理系统论文

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

基于java+springboot+mybatis+vue+elementui的毕业生信息招聘平台

项目介绍 随着我国教育改革的重大发展&#xff0c;越来越多的人都有了机会接受高等教育&#xff0c;同时每个大学生在毕业的时候都面临着一个重要的问题&#xff0c;那就是如何进行就业和找工作的问题&#xff0c;为了能够帮助更多的大学生找到适合自己的工作&#xff0c;我们…

m基于matlab的DQPSK调制解调技术的仿真

目录 1.算法概述 2.仿真效果预览 3.MATLAB部分代码预览 4.完整MATLAB程序 1.算法概述 4进制的DPSK通常记为DQPSK。DQPSK信号编码方式如下表&#xff1a; 表中 θk是相对于前一相邻码元的相位变化。共有A、B两种方式。B方式中相邻码元间总有相位改变&#xff0c;故有利于在…