【STM32开发之寄存器版】(八)-定时器的编码器接口模式

news2024/11/19 18:41:32

一、前言

1.1 编码器接口原理

编码器模式主要用于检测旋转编码器的转动方向和转动速度。旋转编码器一般输出两路相位相差90度的脉冲信号(称为A相和B相),通过这两路信号,定时器可以判断编码器的旋转方向,并计数转动的脉冲数

1.2 本次DEMO目标

本次DEMO将使用STM32F103ZET6的PA6(TIM3_CH1)PA7(TIM3_CH2)的编码器模式,测量电机AB相编码器的正转、反转以及速度信息。并通过串口1打印在上位机XCOM上。

1.3 实验环境介绍

除了之前几篇文章一直使用到的正点原子STM32F103ZET6精英板,本文还是用到了MG513P30_12V直流减速电机。如下图所示:

MG513P30_12V型电机的参数如下表所示: 

额定电压(V)额定电流(A)堵转电流(A)减速后空载转速(rpm)减速后额定转速(rpm)额定扭矩(kg.cm)堵转扭矩(kg.cm)功率(W)
120.363.2366±26293±2114.54

本文使用的MG513P30_12V型电机自带霍尔编码器,其参数如下所示:

型号编码器线数类型供电范围
霍尔编码器13ppr磁感应3.3-5V

本次DEMO的硬件接线方式如下:

开发板带编码器的电机
5V5V
GNDGND
PA6A相
PA7B相

二、STM32处理AB相编码器原理

选择编码器接口模式的方法是:如果计数器只在TI2的边沿计数,则置TIMx_SMCR寄存器中的SMS=001;如果只在TI1边沿计数,则置SMS=010;如果计数器同时在TI1和TI2边沿计数,则置SMS=011。本文选择计数器同时在TI1和TI2边沿计数

通过设置TIMx_CCER寄存器中的CC1P和CC2P位,可以选择TI1和TI2极性;如果需要,还可以对输入滤波器编程。

两个输入TI1和TI2被用来作为增量编码器的接口。假定计数器已经启动(TIMx_CR1寄存器中的CEN=’1’),计数器由每次在TI1FP1或TI2FP2上的有效跳变驱动。TI1FP1和TI2FP2是TI1和TI2在通过输入滤波器和极性控制后的信号;如果没有滤波和变相,则TI1FP1=TI1,TI2FP2=TI2。根据两个输入信号的跳变顺序,产生了计数脉冲和方向信号。依据两个输入信号的跳变顺序,计数器向上或向下计数,同时硬件对TIMx_CR1寄存器的DIR位进行相应的设置。不管计数器是依靠TI1计数、依靠TI2计数或者同时依靠TI1和TI2计数。在任一输入端(TI1或者TI2)的跳变都会重新计算DIR位。本文将TIM3_CH1映射到TI1,将TIM3_CH2映射到TI2。

编码器接口模式基本上相当于使用了一个带有方向选择的外部时钟。这意味着计数器只在0到TIMx_ARR寄存器的自动装载值之间连续计数(根据方向,或是0到ARR计数,或是ARR到0计数)。所以在开始计数之前必须配置TIMx_ARR;同样,捕获器、比较器、预分频器、触发输出特性等仍工作如常。

在这个模式下,计数器依照增量编码器的速度和方向被自动的修改,因此计数器的内容始终指示着编码器的位置。计数方向与相连的传感器旋转的方向对应。下表列出了所有可能的组合,假设TI1和TI2不同时变换。 

由于本文选择在TI1和TI2上计数,故仅需关注上表的最后两行。下图是一个计数器操作的实例,显示了计数信号的产生和方向控制。它还显示了当选择了双边沿时,输入抖动是如何被抑制的;抖动可能会在传感器的位置靠近一个转换点时产生。在这个例子中,我们假定配置如下:
● CC1S=’01’ (TIMx_CCMR1寄存器,IC1FP1映射到TI1) 
● CC2S=’01’ (TIMx_CCMR2寄存器,IC2FP2映射到TI2) 
● CC1P=’0’ (TIMx_CCER寄存器,IC1FP1不反相,IC1FP1=TI1) 
● CC2P=’0’ (TIMx_CCER寄存器,IC2FP2不反相,IC2FP2=TI2) 
● SMS=’011’ (TIMx_SMCR寄存器,所有的输入均在上升沿和下降沿有效). 
● CEN=’1’ (TIMx_CR1寄存器,计数器使能)

 我们将以1-8时刻为例,结合之前的表格对编码器工作原理进行剖析:

时刻TI1和TI2动作计数器动作
1TI2低电平,TI1FP1上升向上计数
2TI1高电平,TI2FP2上升向上计数
3TI2高电平,TI1FP1下降向上计数
4TI1低电平,TI2FP2下降向上计数
5TI1低电平,TI2FP2上升向下计数
6TI2高电平,TI1FP1上升向下计数
7TI1高电平,TI2FP2下降向下计数
8TI2低电平,TI1FP1下降向下计数

三、时钟树分析

对于时钟树的分析与【STM32开发之寄存器版】(六)-通用定时器中断 相同,供给TIM3的时钟TIM3CLK=72MHz,具体的时钟树配置如下图所示:

四、寄存器介绍

为实现定时器的编码器接口模式,需要控制以下几组寄存器:

寄存器作用
RCC_APB1ENRAPB1外设时钟使能寄存器
RCC_APB2ENRAPB2外设时钟使能寄存器
GPIOx_CRL端口配置低寄存器
TIMx_ARR自动重装载寄存器
TIMx_PSC预分频器
TIMx_CCMR1捕获/比较模式寄存器1
TIMx_CCER捕获/比较使能寄存器
TIMx_SMCR从模式控制寄存器
TIMx_CNT计数器
TIMx_CR1控制寄存器1

下面将对这些寄存器进行一一介绍。

4.1 APB1/2 外设时钟使能寄存器

对该寄存器的描述详见【STM32开发之寄存器版】(二)-USART,需要对RCC_APB1ENR的第1位置1,使能定时器3时钟;对RCC_APB2ENR的第2位置1,使能并口A时钟。

4.2 GPIOx_CRL 端口配置低寄存器

对该寄存器的描述详见【STM32开发之寄存器版】(一)-GPIO,将PA6和PA7设置为浮空输入。

4.3 TIMx_ARR 自动重装载寄存器

对该寄存器的描述详见【STM32开发之寄存器版】(六)-通用定时器中断,本文将其设为0XFFFF。

4.4 TIMx_PSC 预分频器

对该寄存器的描述详见【STM32开发之寄存器版】(六)-通用定时器中断,本文将其设置为0,即不分频。

4.5 TIMx_CCMR1 捕获/比较模式寄存器1

《STM32中文参考手册》对TIMx_CCMR1寄存器的描述如下:

这里我们重点关注IC2F、CC2S、IC1F和CC1S。

IC1F和IC2F分别为输入捕获1和输入捕获2的滤波器,我们在这里设置为0110,即数字滤波器长度为6.

CC1S和CC2S为捕获/比较选择,我们将其设置为01,即CC1和CC2通道被配置为输入,IC1映射在TI1上,IC2映射在TI2上

4.6 TIMx_CCER 捕获/比较使能寄存器

《STM32中文参考手册》对TIMx_CCER寄存器的描述如下:

这里我们重点关注CC1P和CC2P,这两位设置为0,当我们将CC1和CC2通道配置为输入后,信号不反相。 

4.7 TIMx_SMCR 从模式控制寄存器

《STM32中文参考手册》对TIMx_SMCR寄存器的描述如下:

这里我们重点关注SMS从模式选择,我们将其设置为011,即编码器模式3,根据另一个信号的输入电平,计数器在TI1FP1和TI2FP2的边沿向上/下计数。

4.8 TIMx_CNT 计数器

《STM32中文参考手册》对TIMx_CNT寄存器的描述如下:

可以直接从CNT中读取编码器计数值, 也可以通过写的方式清除编码器计数值。

4.9 TIMx_CR1 控制寄存器1

对该寄存器的描述详见【STM32开发之寄存器版】(六)-通用定时器中断,第0位为计数器的使能位,该位必须置1,才能让定时器开始计数

五、程序设计

本DEMO中的程序主要分为TIM3编码器模式初始化、编码器速度读取以及轮询主函数。完整版代码见【STM32开发之寄存器版】(八-附)-定时器的编码器接口模式

5.1 TIM3编码器模式初始化

本部分代码在HARDWARE/encoder.c/TIM3_Encoder_Init();该函数的作用是按照第四部分的寄存器介绍,将TIM3初始化为编码器模式。具体代码如下所示:

void TIM3_Encoder_Init(void){
	
	RCC->APB1ENR|=1<<1; 	    //TIM3时钟使能
	RCC->APB2ENR|=1<<2;       //使能PORTA时钟
	
	GPIOA->CRL  &= 0X00FFFFFF;//清除PA7和PA6的控制位
	GPIOA->CRL  |= 0X44000000;//将PA7和PA6设置为浮空输入
	
	TIM3->ARR   =  0xFFFF;	  //设定计数器自动重装值 
	TIM3->PSC   =  0x0000;		//预分频器不分频
	
	TIM3->CR1   &= 0XFCFF;		//清除TIM3_CR1的[9:8]时钟分频因子
	TIM3->CR1   |= 0X0000;    //设置时钟分频因子为0,即定时器时钟tCK_INT(72MHz)与数字滤波器采样频率tDTS相等。
	
	TIM3->CCMR1 &= 0XFF0F;    //清除TIM3_CCMR1的[7:4]IC1F
	TIM3->CCMR1 |= 0X0060;    //设置采样频率为fDTS/4,N=6
	
	TIM3->CCMR1 &= 0X0FFF;    //清除TIM3_CCMR1的[15:12]IC2F
	TIM3->CCMR1 |= 0X6000;    //设置采样频率为fDTS/4,N=6
	
	TIM3->CCER  &= 0XFFDD;    //清除TIM3_CCER的[5]和[1];
	TIM3->CCER  |= 0X0000;    //将CC1和CC2通道设置为输入捕获,不反相。
	
	TIM3->SMCR  &= 0XFFF8;    //清除TIM3_SMCR的[2:0]SMS从模式选择位
	TIM3->SMCR  |= 0X0003;		//设置为编码器模式3 – 根据另一个信号的输入电平,计数器在TI1FP1和TI2FP2的边沿向上/下计数。
	
	TIM3->CCMR1 &= 0XFCFC;    //清除TIM3_CCMR1的[9:8]CC2S和[1:0]CC1S
	TIM3->CCMR1 |= 0X0101;    //在输入捕获模式下,CC2通道被配置为输入,IC2映射在TI2上;CC1通道被配置为输入,IC1映射在TI1上
	
	TIM3->CNT   =  0;         //TIM3计数器清零
	TIM3->CR1   |= 0x01;      //使能定时器3
	
}

5.2 编码器速度读取

本部分代码在HARDWARE/encoder.c/GetMotorPulse();该函数的作用是读取编码器数值,并对电机旋转方向进行判定,最后将编码器数值清零,具体代码如下所示:

void GetMotorPulse(void)
{
	decoderCNT = TIM3->CNT;   //获得编码器计数值
	
	if(decoderCNT > 0X7FFF){
		decoderCNT = decoderCNT-0XFFFF;  //电机反向判定,临界值0X7FFF;
	}
	
	TIM3->CNT = 0;            //计数器清零

}

5.3 轮询主函数 

本部分代码在USER/test.c;该函数的作用是读取并打印编码器速度,具体代码如下所示:

#include "sys.h"
#include "delay.h"
#include "usart.h" 
#include "encoder.h"

int main(void)
{					   	
	Stm32_Clock_Init(9);	//系统时钟设置
	uart_init(72,115200);	//串口初始化为115200
	delay_init(72);	   	 	//延时初始化 
  TIM3_Encoder_Init();  //初始化编码器
	
  while(1)
	{
		GetMotorPulse();
		printf("电机转速为:%d\r\n",decoderCNT);
		delay_ms(20);
	}
}

六、上机实验

6.1 编码器原信号测量

将示波器CH1(黄色线)接编码器A相,CH2(绿色线)接编码器B相,电机正转时,编码器信号值如下所示,A相领先于B相若干相位

 电机正转时,编码器信号值如下所示,B相领先于A相若干相位。

当电机速度加快时,信号频率会增大,单位时间内计数器中的值就会越大。 

6.2 电机转速测试 

对电机进行正转和反转,查看XCOM串口信息,可以看到电机转速值:

至此定时器3编码器模式测试成功! 

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

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

相关文章

嵌入式学习-线性表Day03-栈

嵌入式学习-线性表Day03-栈 栈 顺序栈 2&#xff09;入栈 3&#xff09;出栈 链式栈 栈 什么是栈? 只能在一端进行插入和删除操作的线性表&#xff08;又称为堆栈&#xff09;&#xff0c;进行插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底 栈特点&#xff1a; 先进…

儿童(青少年)可以参加哪些含金量高的比赛?

随着素质教育的推进&#xff0c;越来越多的家长和老师开始关注如何培养孩子的综合素质和能力。而参加各类比赛&#xff0c;不仅可以锻炼孩子的思维、动手能力和团队合作精神&#xff0c;还能帮助孩子在学习的过程中找到兴趣点和成就感。尤其是一些含金量高的比赛&#xff0c;不…

什么是静态加载-前端

什么是前端静态加载 在前端开发中&#xff0c;静态加载是一种常见且重要的技术。简单来说&#xff0c;前端静态加载指的是在页面加载时将所需的资源&#xff08;如HTML、CSS、JavaScript、图片等&#xff09;一并加载到用户的浏览器中。这种方式有助于提高页面的加载速度和用户…

【宽搜】6. leetcode 513 找树左下角的值

1 题目描述 题目链接&#xff1a;找树左下角的值 2 题目解析 思路&#xff1a; 可以使用 层序遍历&#xff0c; 将每一层的值都存入到一个vector< int> 中&#xff0c;当这一层是最后一层的时候&#xff0c;将vector< int>中的第一个值返回即可。 3 代码 cla…

RemoteView(kotlin)

使用场景&#xff1a;通知栏&桌面部件 自定义通知栏 通知权限申请 manifest配置 <uses-permission android:name"android.permission.POST_NOTIFICATIONS" />权限动态申请 package com.example.kotlinlearn.Common;import android.Manifest; import an…

国产长芯微LDUM8801光耦兼容的单通道隔离式栅极驱动器P2P替代UCC23513 FOD8342 TLP5751成本低,质量更好

描述 LDUM8801是单通道兼容光耦输入的隔离式栅极驱动器&#xff0c;可应用于驱动IGBT、SiC 和 MOSFET。它可以提供5A的峰值拉/灌电流。支持150kV/μs的最小共模瞬态免疫&#xff08;CMTI&#xff09;&#xff0c;确保了系统的鲁棒性。驱动器的最大电源电压为32V。 其与光耦式栅…

【计网】【计网】从零开始学习http协议 ---理解http重定向和请求方法

去光荣地受伤&#xff0c; 去勇敢地痊愈自己。 --- 简嫃 《水问》--- 从零开始学习http协议 1 知识回顾2 认识网络重定向3 http请求方法3.1 http常见请求方法3.2 postman工具进行请求3.3 处理GET和POST参数 1 知识回顾 前面两篇文章中我们学习并实现了http协议下的请求与应…

【LeetCode】每日一题 2024_10_9 找到按位或最接近 K 的子数组(LogTrick、位运算)

前言 每天和你一起刷 LeetCode 每日一题~ LeetCode 启动&#xff01; 题目&#xff1a;找到按位或最接近 K 的子数组 代码与解题思路 今天是 2100 的题目&#xff0c;难度略高&#xff0c;不在我的能力范围&#xff0c;推荐题解&#xff1a;两种方法&#xff1a;LogTrick/滑…

设计模式——门面模式 | 外观模式

哈喽&#xff0c;各位盆友们&#xff01;我是你们亲爱的学徒小z&#xff0c;今天给大家分享的文章是设计模式的——门面模式。 文章目录 定义通用类图1.通用结构2.优点3.缺点 使用场景注意事项1.一个子系统可以有多个门面2.门面不参与子系统内的业务逻辑 定义 定义&#xff1a;…

【Flutter】合并多个流Stream

1.说明 无意间发现了一个好用的库rxdart&#xff0c;它为 Dart 的 Stream 添加了额外的功能。 2.功能 &#xff08;1&#xff09;合并多个流Stream 借助Rx.combineLatest2()合并两个流stream1和stream2。 注意&#xff1a;如果dart文件中同时使用了getx&#xff0c;需要隐…

PCL 3D-SIFT关键点检测(Z方向梯度约束

目录 一、概述 1.1原理 1.2实现步骤 1.3应用场景 二、代码实现 2.1关键函数 2.1.1 SIFT关键点检测 2.1.2 可视化函数 2.2完整代码 三、实现效果 PCL点云算法汇总及实战案例汇总的目录地址链接&#xff1a; PCL点云算法与项目实战案例汇总&#xff08;长期更新&#…

调用CString::Format接口格式化字符串时产生异常,可能是将当前的CString对象作为参数传给CString::Format接口导致的

最近有人在技术群里问一个关于使用MFC库中的CString类格式化字符串时遇到的问题&#xff0c;有时格式化出来的字符串有问题&#xff08;不是预期的&#xff09;&#xff0c;有时会产生异常崩溃&#xff0c;让我们帮忙分析一下&#xff0c;看看是什么原因导致的。 后来到MSDN上查…

JAVA基础: synchronized 和 lock的区别、synchronized锁机制与升级

1 synchronized 和 lock的区别 synchronized是一个关键字&#xff0c; lock是一个接口&#xff0c;实际使用的是实现类 synchronized通过触发的是系统级别的锁机制&#xff0c; lock是API级别的锁机制 synchronized自动获得锁&#xff0c;自动释放锁。 lock需要通过方法获得锁…

基于SSM的校园教务系统的设计与实现(论文+源码)_kaic

摘 要 互联网发展至今&#xff0c;无论是其理论还是技术都已经成熟&#xff0c;而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播&#xff0c;搭配信息管理工具可以很好地为人们提供服务。针对校园教务信息管理混乱&#xff0c;出错率高&#xff0c;信息安全性差…

【含开题报告+文档+PPT+源码】基于SSM框架的民宿酒店预定系统的设计与实现

开题报告 随着人们旅游需求的增加&#xff0c;民宿行业呈现出快速发展的趋势。传统的住宿方式逐渐无法满足人们对个性化、舒适、便捷的需求&#xff0c;而民宿作为一种新型的住宿选择&#xff0c;逐渐受到人们的青睐。民宿的特点是具有独特的风格、便捷的地理位置、相对亲近的…

基于yolov8的版面分析AI能力生产全流程

目录 1.coco数据集 1.1 基本定义 1.2应用场景 1.3 数据结构 2.labelme标注工具 2.1 基本定义 2.2 应用场景 2.3 安装步骤 3. 模型训练 3.1 数据标注 3.2 环境准备 3.3 数据预处理 3.4 模型训练 3.5 模型推理 4.参考链接 1.coco数据集 1.1 基本定…

数据库的相关知识

数据库的相关知识 1.数据库能够做什么&#xff1f; 存储大量数据&#xff0c;方便检索和访问保持数据信息的一致、完整共享和安全通过组合分析&#xff0c;产生新的有用信息 2.数据库作用&#xff1f; 存储数据、检索数据、生成新的数据 3.数据库要求&#xff1f; 统一、…

51单片机的自动洗手器【proteus仿真+程序+报告+原理图+演示视频】

1、主要功能 该系统由AT89C51/STC89C52单片机红外传感器继电器LED等模块构成。适用于红外感应洗手器、自动出水等相似项目。 可实现功能: 1、红外传感器实时采集人体信息&#xff0c;如果有人靠近&#xff0c;则闭合水泵继电器开始出水&#xff0c;人离开5s后&#xff0c;继电…

微信5大隐藏技巧,让你成为聊天高手

微信&#xff0c;这个几乎人人都在使用的应用&#xff0c;它的一些隐藏功能却鲜为人知。 今天&#xff0c;就让我们一起来探索这些实用的小技巧&#xff0c;让你的微信使用体验更上一层楼。 一键长截图&#xff0c;保存完整信息 在微信里&#xff0c;当你需要截取某个网页或公…

JAVA八股文1

1.Java 基础 1.1 语法基础 封装 利用抽象数据类型将数据和基于数据的操作封装在一起&#xff0c;使其构成一个不可分割的独立实体。数据被保护在抽象数据类型的内部&#xff0c;尽可能地隐藏内部的细节&#xff0c;只保留一些对外接口使之与外部发生联系。用户无需知道对象内…