STM32学习笔记(6_8)- TIM定时器的编码器接口代码

news2024/11/19 9:30:50

无人问津也好,技不如人也罢,都应静下心来,去做该做的事。

最近在学STM32,所以也开贴记录一下主要内容,省的过目即忘。视频教程为江科大(改名江协科技),网站jiangxiekeji.com

现在开始上难度,STM32功能最强大、结构最复杂的外设——定时器,分四期介绍。

第一期介绍最基础的定时功能理论、定时器中断和定时器内外时钟源选择的代码。

第二期介绍定时器输出比较功能的代码,输出比较功能常用产生PWM波驱动电机。

上期介绍定时器输入捕获功能代码,常用测量方波频率。

最后介绍定时器的编码器接口代码,更方便读取正交编码器的输出波形,常用编码电机测速。

上下拉的选择原则:如果GPIO口接的外部模块默认输出低电平,我们配置下拉输入,默认输入低电平。和外部模块保持默认状态一致,防止默认电平打架。不过一般来说,默认高电平,这是一个习惯的状态。

接线图

这里使用TIM3的CH1、CH2来做定时器的编码器接口输入GPIO,所以A相接PA6、B相接PA7或者A相接PA7、B相接PA6,都是可以的,只是正反转的极性区别。

编码器接口程序测速现象

 在这里接了一个旋转编码器模块,这个代码和之前我们写的旋转编码器计次的代码,实现的功能基本都是一样的。OLED显示的是Speed速度,向右慢速旋转,数值为正,计次比较小。向右快速旋转,计次就会增大;然后向左慢速旋转,数值为负,计次比较小;然后停下来,速度就是0。

编码器接口常用函数

TIM_EncoderInterfaceConfig(哪个定时器,选择编码器模式,通道1的电平极性,通道2的电平极性):定时器编码器接口配置

void TIM_EncoderInterfaceConfig(TIM_TypeDef* TIMx, uint16_t TIM_EncoderMode,
                                uint16_t TIM_IC1Polarity, uint16_t TIM_IC2Polarity);

初始化步骤

第一步,RCC开启时钟,开启GPIO和定时器的时钟

	/*开启时钟*/
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);			//开启TIM3的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);			//开启GPIOA的时钟

第二步,配置GPIO,这里需要把PA6和PA7配置成输入模式

上下拉的选择原则:如果GPIO口接的外部模块默认输出低电平,我们配置下拉输入,默认输入低电平。和外部模块保持默认状态一致,防止默认电平打架。不过一般来说,默认高电平,这是一个习惯的状态。

	/*GPIO初始化*/
	GPIO_InitTypeDef GPIO_InitStructure;
	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);							//将PA6和PA7引脚初始化为上拉输入

第三步,配置时基单元,这里预分频器我们一般选择不分频,自动重装一般给最大65535,
只需要一个CNT执行计数就行了

	/*时基单元初始化*/
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;				//定义结构体变量
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;     //时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式,选择向上计数
	TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1;               //计数周期,即ARR的值
	TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1;                //预分频器,即PSC的值
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;            //重复计数器,高级定时器才会用到
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);             //将结构体变量交给TIM_TimeBaseInit,配置TIM3的时基单元

第四步,配置输入捕获单元,不过这里输入捕获单元只有滤波器和极性这两个参数有用,后面的参数没有用到,与编码器无关。但是为避免出现奇奇怪怪的问题,这里先用TIM_ICStructInit()函数把输入捕获单元的结构体成员都赋一个初始值,再单独去修改滤波器和极性这两个参数。

	/*输入捕获初始化*/
	TIM_ICInitTypeDef TIM_ICInitStructure;							//定义结构体变量
	TIM_ICStructInit(&TIM_ICInitStructure);							//结构体初始化,若结构体没有完整赋值
																	//则最好执行此函数,给结构体所有成员都赋一个默认值
																	//避免结构体初值不确定的问题
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;				//选择配置定时器通道1
	TIM_ICInitStructure.TIM_ICFilter = 0xF;							//输入滤波器参数,可以过滤信号抖动
	TIM_ICInit(TIM3, &TIM_ICInitStructure);							//将结构体变量交给TIM_ICInit,配置TIM3的输入捕获通道
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;				//选择配置定时器通道2
	TIM_ICInitStructure.TIM_ICFilter = 0xF;							//输入滤波器参数,可以过滤信号抖动
	TIM_ICInit(TIM3, &TIM_ICInitStructure);							//将结构体变量交给TIM_ICInit,配置TIM3的输入捕获通道

第五步,配置编码器接口模式,这个直接调用一个库函数就可以了

	/*编码器接口配置*/
	TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
																	//配置编码器模式以及两个输入通道是否反相
																	//注意此时参数的Rising和Falling已经不代表上升沿和下降沿了,而是代表是否反相
																	//此函数必须在输入捕获初始化之后进行,否则输入捕获的配置会覆盖此函数的部分配置

最后,调用TIM_Cmd,启动定时器,就完事了

	/*TIM使能*/
	TIM_Cmd(TIM3, ENABLE);			//使能TIM3,定时器开始运行

电路初始化好后,CNT就会随着编码器旋转而自增自减。如果想要测量编码器的位置,那直接读出CNT的值就行了;如果想测量编码器的速度和方向,那就需要每隔一段固定的闸门时间,取出一次CNT,然后再把CNT清零,这样就是测频法测量速度了

代码展示

Hardware文件夹下新建编码器接口文件(Encoder),添加Encoder.h、.c文件,在Encoder_Init函数这里进行编码器接口的初始化。

main函数

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Timer.h"
#include "Encoder.h"

int16_t Speed;			//定义速度变量

int main(void)
{
	/*模块初始化*/
	OLED_Init();		//OLED初始化
	Timer_Init();		//定时器初始化
	Encoder_Init();		//编码器初始化
	
	/*显示静态字符串*/
	OLED_ShowString(1, 1, "Speed:");		//1行1列显示字符串Speed:
	
	while (1)
	{
		OLED_ShowSignedNum(1, 7, Speed, 5);	//不断刷新显示编码器测得的最新速度
	}
}

/**
  * 函    数:TIM2中断函数
  * 参    数:无
  * 返 回 值:无
  * 注意事项:此函数为中断函数,无需调用,中断触发后自动执行
  *           函数名为预留的指定名称,可以从启动文件复制
  *           请确保函数名正确,不能有任何差异,否则中断函数将不能进入
  */
void TIM2_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)		//判断是否是TIM2的更新事件触发的中断
	{
		Speed = Encoder_Get();								//每隔固定时间段读取一次编码器计数增量值,即为速度值
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);			//清除TIM2更新事件的中断标志位
															//中断标志位必须清除
															//否则中断将连续不断地触发,导致主程序卡死
	}
}

Encoder.h文件

#ifndef __ENCODER_H
#define __ENCODER_H

void Encoder_Init(void);
int16_t Encoder_Get(void);

#endif

Encoder.c文件

#include "stm32f10x.h"                  // Device header

/**
  * 函    数:编码器初始化
  * 参    数:无
  * 返 回 值:无
  */
void Encoder_Init(void)
{
	/*开启时钟*/
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);			//开启TIM3的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);			//开启GPIOA的时钟
	
	/*GPIO初始化*/
	GPIO_InitTypeDef GPIO_InitStructure;
	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);							//将PA6和PA7引脚初始化为上拉输入
	
	/*时基单元初始化*/
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;				//定义结构体变量
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;     //时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式,选择向上计数
	TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1;               //计数周期,即ARR的值
	TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1;                //预分频器,即PSC的值
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;            //重复计数器,高级定时器才会用到
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);             //将结构体变量交给TIM_TimeBaseInit,配置TIM3的时基单元
	
	/*输入捕获初始化*/
	TIM_ICInitTypeDef TIM_ICInitStructure;							//定义结构体变量
	TIM_ICStructInit(&TIM_ICInitStructure);							//结构体初始化,若结构体没有完整赋值
																	//则最好执行此函数,给结构体所有成员都赋一个默认值
																	//避免结构体初值不确定的问题
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;				//选择配置定时器通道1
	TIM_ICInitStructure.TIM_ICFilter = 0xF;							//输入滤波器参数,可以过滤信号抖动
	TIM_ICInit(TIM3, &TIM_ICInitStructure);							//将结构体变量交给TIM_ICInit,配置TIM3的输入捕获通道
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;				//选择配置定时器通道2
	TIM_ICInitStructure.TIM_ICFilter = 0xF;							//输入滤波器参数,可以过滤信号抖动
	TIM_ICInit(TIM3, &TIM_ICInitStructure);							//将结构体变量交给TIM_ICInit,配置TIM3的输入捕获通道
	
	/*编码器接口配置*/
	TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
																	//配置编码器模式以及两个输入通道是否反相
																	//注意此时参数的Rising和Falling已经不代表上升沿和下降沿了,而是代表是否反相
																	//此函数必须在输入捕获初始化之后进行,否则输入捕获的配置会覆盖此函数的部分配置
	
	/*TIM使能*/
	TIM_Cmd(TIM3, ENABLE);			//使能TIM3,定时器开始运行
}

/**
  * 函    数:获取编码器的增量值
  * 参    数:无
  * 返 回 值:自上此调用此函数后,编码器的增量值
  */
int16_t Encoder_Get(void)
{
	/*使用Temp变量作为中继,目的是返回CNT后将其清零*/
	int16_t Temp;
	Temp = TIM_GetCounter(TIM3);
	TIM_SetCounter(TIM3, 0);
	return Temp;
}

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

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

相关文章

원클릭으로 주류 전자상거래 플랫폼 상품 상세 데이터 수집 및 접속 시연 예제 (한국어판)

클릭 한 번으로 전자상거래 플랫폼 데이터를 캡처하는 것은 일반적으로 웹 페이지에서 정보를 자동으로 추출 할 수있는 네트워크 파충류 기술과 관련됩니다.그러나 모든 형태의 데이터 수집은 해당 웹 사이트의 사용 약관 및 개인 정보 보호 정책 및 현지 법률 및 규정을 준수…

百度蜘蛛池平台在线发外链-原理以及搭建教程

蜘蛛池平台是一款非常实用的SEO优化工具,它可以帮助网站管理员提高网站的排名和流量。百度蜘蛛池原理是基于百度搜索引擎的搜索算法,通过对网页的内容、结构、链接等方面进行分析和评估,从而判断网页的质量和重要性,从而对网页进行…

JAVA面试大全之基础篇

目录 1、语法基础 1.1、面向对象特性?​​​​​​​ 1.2、a a b 与 a b 的区别 1.3、3*0.1 0.3 将会返回什么? true 还是 false? 1.4、能在 Switch 中使用 String 吗? 1.5、对equals()和hashCode()的理解? 1.6、final、finalize 和 finally 的不同之…

【物联网开源平台】tingsboard二次开发

别看这篇了,这篇就当我的一个记录,我有空我再写过一篇,编译的时候出现了一个错误,然后我针对那一个错误执行了一个命令,出现了绿色的succes,我就以为整个tingsboard项目编译成功了,后面发现的时候&#xff…

怎么清理苹果电脑内存?CleanMyMac X4.15.2最新中文版使用教程

近日,我的苹果电脑似乎遭遇了一点小麻烦,每当深入工作或沉浸于娱乐之时,突如其来的一个警告弹窗就像一颗冰凉的霰弹,打断了我所有的思绪:内存不足!!!怎么清理苹果电脑内存&#xff0…

机器学习——神经网络简单了解

一、神经网络基本概念 神经网络可以分为生物神经网络和人工神经网络 (1)生物神经网络,指的是生物脑内的神经元、突触等构成的神经网络,可以使生物体产生意识,并协助生物体思考、行动和管理各机体活动。 (2)人工神经网络,是目前热门的深度学习的研究…

蔓灵花组织wmRAT分析

wmRAT分析 MD5:35639088a2406aa9e22fa8c03e989983 样本分析 多次调用sleep函数绕过沙箱检测。 创建线程获取username computername 磁盘驱动器个数 通过域名microsoft.com获取ip地址 通过c2服务器域名maxdimservice.com获取ip地址85.239.53.31 408460函数获取…

44 el-dialog 的 appendToBody 属性, 导致 vue 响应式失效

前言 我们经常会碰到 一些 模型和视图 不同步的问题 通常意义上 主要的问题为 列表的某响应式数据更新着更新着 后面就变成非响应式对象了, 然后 就造成了 数据一直在更新, 但是 视图的渲染后面就未渲染了, 这是一个由于 模型上的问题 导致的数据的不在响应式更新 又或者 是…

借力AI+视频号电商,腾讯广告业务这驾马车能跑多远?

腾讯的“功劳簿”又添上了几笔。 日前,腾讯披露了2023年四季度及全年财报。报告显示,2023年,腾讯营收6090.15亿元,同比增长10%;调整后净利润(Non-IFRS)1576.88亿元,同比增长36%。 …

在stable diffusion中手指纠错的指令和关键词是什么?

在Stable Diffusion模型中,如果您想对生成的图像中的手指进行纠错,您可以在描述中使用特定的指令和关键词来引导模型关注于手指区域并作出调整。 "Perfect hand" (完美的手) "Five fingers" (五个…

中国科学院半导体研究所汪林望:在曙光超级计算机上对第一性原理计算软件LS3DF进行1000万个硅原子模拟

编者荐语: 面对纳米材料等大体系时,电荷补丁法可以计算几千甚至上万原子, 但是电荷补丁法作为非自洽计算,不能给出原子受力,也不能用来弛豫原子坐标。面对摩尔条纹或线性位错等问题,我们需要弛豫原子的坐标…

javaSwing模拟写字板

一、摘要 目前,很多新的技术领域都涉及到了Java语言,Java语言是面向对象编程,并且涉及到网络、多线程等重要的基础知识,因此Java语言也是学习面向对象编程和网络编程的首选语言。此简易JAVA写字板程序,使用Java程序编…

Object Detection--Loss Function:从IoU到CIoU

本篇总结Loss Function中的IoU系列代码。 1. IoU 交并集,两个框交集面积除以并集面积。(论写写画画的重要性)(找原文看看) """ box1[x1, y1, x2, y2] box2[x1, y1, x2, y2] return iou ""…

Qt 作业 24/3/26

1、实现闹钟 #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QTime> #include <QLineEdit>QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic:Widget(QWidget *parent …

python(django)之单一接口管理功能后台开发

1、创建数据模型 在apitest/models.py下加入以下代码 class Apis(models.Model):Product models.ForeignKey(product.Product, on_deletemodels.CASCADE, nullTrue)# 关联产品IDapiname models.CharField(接口名称, max_length100)apiurl models.CharField(接口地址, max_…

关键技术解析:CH-99除硼树脂在超纯水制备中对硼高效去除的应用实践与性能优势

超纯水(UPW)是科技和研究领域的关键资源&#xff0c;其中硼元素的去除对于保证其品质至关重要。本文将介绍一种高效的除硼技术——Tulsimer CH-99树脂&#xff0c;并阐述其在超纯水制备中的应用及优势。 首先&#xff0c;让我们了解超纯水的制备过程。超纯水是通过一系列精密的…

JAVA面试大全之集合IO篇

目录 1、集合 1.1、Collection 1.1.1、集合有哪些类&#xff1f; 1.1.2、ArrayList的底层&#xff1f; 1.1.3、ArrayList自动扩容&#xff1f; 1.1.4、ArrayList的Fail-Fast机制&#xff1f; 1.2、MAP 1.2.1、Map有哪些类&#xff1f; 1.2.2、JDK7 HashMap如何实现…

二进制日志备份与恢复

二进制备份是 MySQL 数据库备份的一种方式&#xff0c;它通过记录数据库的所有更改操作&#xff0c;以二进制格式保存&#xff0c;实现对数据库的增量备份和恢复。binlog_format 是 MySQL 中用来指定二进制日志格式的参数&#xff0c;有三种常见的选项&#xff1a;STATEMENT、R…

就业班 第二阶段 2401--3.26 day6 Shell初识 连接vscode

远程连接vs_code可能出现的问题 C:\Users\41703\.ssh 验证远程主机的身份&#xff0c;如果连不上vscode&#xff0c;可以尝试删除这里面的公钥代码。 重新安装那个扩展&#xff0c;排除扩展本身的问题 谁连过我&#xff0c;并操作了什么 curl https://gitea.beyourself.org.c…

pytorch反向传播算法

目录 1. 链式法则复习2. 多输出感知机3. 多层感知机4. 多层感知机梯度推导5. 反向传播的总结 1. 链式法则复习 2. 多输出感知机 3. 多层感知机 如图&#xff1a; 4. 多层感知机梯度推导 简化式子把( O k O_k Ok​ - t k t_k tk​) O k O_k Ok​(1 - O k O_k Ok​)起个别名…