【STM32】TIM定时器编码器

1 编码器接口简介

Encoder Interface 编码器接口

编码器接口可接收增量(正交)编码器的信号,根据编码器旋转产生的正交信号脉冲,自动控制CNT自增或自减,从而指示编码器的位置、旋转方向和旋转速度

接收正交信号,自动执行CNT自增或者自减,编码器接口相当于带有方向控制的外部时钟,同时控制着CNT的计数时钟和计数方向。每隔一段时间去取一次CNT的值,再把CNT清零,每次取出来的值就表示编码器的速度。(测频法)

每个高级定时器和通用定时器都拥有1个编码器接口

两个输入引脚借用了输入捕获的通道1和通道2(CH1和CH2)

1.1 正交编码器

正交编码器一般可以测量位置或者带有方向的速度值

旋转编码器:用来测量位置、速度或旋转方向的装置,当其旋转轴旋转时,其输出端可以输出与旋转速度和方向对应的方波信号,读取方波信号的频率和相位信息即可得知旋转轴的速度和方向

类型:机械触点式/霍尔传感器式/光栅式

 

方波频率代表速度。正转时A相提前B相90°;反转时A相滞后B相90°

首先把A\相和B相的所有边沿作为计数器的计数时钟,出现边沿信号时就计数器自增或者自减;计数的方向由另一相的状态来确定。当出现某个边沿时,判断另一相高低电平,如果另一相的状态出现在上面这个表中,那就是正转,计数自增;否则就是反转,计数自减。这样就可以实现编码器接口的功能了。

编码器接口有两个输入端,分别接到编码器的A相和B相,所以编码器的输入引脚就是定时器的CH1和CH2引脚。编码器的输出部分相当于从模式的控制器了,控制CNT的计数时钟和计数方向。计数器的自增和自减受编码器控制。

1.2 编码器接口基本结构

很清晰

1.3 工作模式

这里TI1FP1和TI2FP2接的就是AB相。计数和前面一样。

正转向上计数,反转向下计数。

1.4 实例图

均不反向,使用TI1和TI2都计数

很清晰。

TI1反向,TI2不反向。极性的变化对计数的影响。

这里的极性选择就是高低电平的极性选择了。如果选择上升沿的参数,就是信号直通过来,高低电平极性不反转;如果选择下降沿的参数,就是信号通过非门,高低电平反转。

很清晰。

手册

2  编码器接口测速

2.1 接线图

引脚定义

计划用TIM3的通道1和通道2

2.2 模块封装

按这个配置

库函数

// 定时器编码器接口配置
void TIM_EncoderInterfaceConfig(TIM_TypeDef* TIMx, uint16_t TIM_EncoderMode,
                                uint16_t TIM_IC1Polarity, uint16_t TIM_IC2Polarity);

版本一:Encoder.c

#include "stm32f10x.h"                  // Device header

// 编码器接口初始化函数
void EnCoder_Init(void)
{
	// 1开启时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	// 2配置GPIO
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;         		// 上拉输入模式
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStruct);
	
	// 3配置时基单元
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	TIM_TimeBaseInitStruct.TIM_Prescaler = 1 - 1;                    	// PSC预分频器的值,不分频
	TIM_TimeBaseInitStruct.TIM_Period = 65536 - 1;                     	// ARR自动重装器的值 
	TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;      	// 向上计数,没有用
	TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;			// 不分频
	TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;                	// 重复计数器的值
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStruct);
	
	// 4配置输入捕获单元(只有极性和滤波器两个参数有用)
	TIM_ICInitTypeDef TIM_ICInitStruct;
	TIM_ICStructInit(&TIM_ICInitStruct);                               // 结构体初始化
	TIM_ICInitStruct.TIM_Channel = TIM_Channel_1;					   // 通道1
	TIM_ICInitStruct.TIM_ICFilter = 0xF;							   // 滤波器
//	TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;		   // 和后面重复
//	TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;       // 无作用
//	TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;                 // 无作用
	TIM_ICInit(TIM3, &TIM_ICInitStruct);
	
	TIM_ICInitStruct.TIM_Channel = TIM_Channel_2;
	TIM_ICInitStruct.TIM_ICFilter = 0xF;
	//	TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;	   // 和后面重复
	TIM_ICInit(TIM3, &TIM_ICInitStruct);
	
	// 5配置编码器接口模式
	// TIM_ICPolarity_Rising这个通道不反向,TIM_ICPolarity_Falling这个通道反向
	// 后两个参数相反就是方向相反
	TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
	// 6启动定时器
	TIM_Cmd(TIM3, ENABLE);
}

// 获取CNT的值
int16_t Encoder_Get(void)
{
    return TIM_GetCounter(TIM3);
}

版本二:Encoder.c

#include "stm32f10x.h"                  // Device header

// 编码器接口初始化函数
void EnCoder_Init(void)
{
	// 1开启时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	// 2配置GPIO
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;         		// 上拉输入模式
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStruct);
	
	// 3配置时基单元
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	TIM_TimeBaseInitStruct.TIM_Prescaler = 1 - 1;                    	// PSC预分频器的值,不分频
	TIM_TimeBaseInitStruct.TIM_Period = 65536 - 1;                     	// ARR自动重装器的值 
	TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;      	// 向上计数,没有用
	TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;			// 不分频
	TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;                	// 重复计数器的值
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStruct);
	
	// 4配置输入捕获单元(只有极性和滤波器两个参数有用)
	TIM_ICInitTypeDef TIM_ICInitStruct;
	TIM_ICStructInit(&TIM_ICInitStruct);                               // 结构体初始化
	TIM_ICInitStruct.TIM_Channel = TIM_Channel_1;					   // 通道1
	TIM_ICInitStruct.TIM_ICFilter = 0xF;							   // 滤波器
//	TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;		   // 和后面重复
//	TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;       // 无作用
//	TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;                 // 无作用
	TIM_ICInit(TIM3, &TIM_ICInitStruct);
	
	TIM_ICInitStruct.TIM_Channel = TIM_Channel_2;
	TIM_ICInitStruct.TIM_ICFilter = 0xF;
	//	TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;	   // 和后面重复
	TIM_ICInit(TIM3, &TIM_ICInitStruct);
	
	// 5配置编码器接口模式
	// TIM_ICPolarity_Rising这个通道不反向,TIM_ICPolarity_Falling这个通道反向
	// 后两个参数相反就是方向相反
	TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
	// 6启动定时器
	TIM_Cmd(TIM3, ENABLE);
}

// 获取CNT的值
int16_t Encoder_Get(void)
{
//    return TIM_GetCounter(TIM3);
	// 读取cnt,把cnt清零的逻辑
	int16_t temp = TIM_GetCounter(TIM3);
	TIM_SetCounter(TIM3, 0);
	return temp;
}

2.3 主函数

版本一:主函数

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


int main()
{
	OLED_Init();								// 初始化OLED
	EnCoder_Init();
//	Timer_Init();								// 初始化定时器
	OLED_ShowString(1, 1, "CNT:");   			// 显示字符串
	
	while (1)
	{
		OLED_ShowNum(1, 5, Encoder_Get(), 5);    // 显示CNT计数器
	}
}

版本二:主函数

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

int16_t speed;


int main()
{
	OLED_Init();								// 初始化OLED
	EnCoder_Init();
	Timer_Init();								// 初始化定时器
	OLED_ShowString(1, 1, "speed:");   			// 显示字符串
	
	while (1)
	{
		OLED_ShowSignedNum(1, 7, speed, 5);    		 // 显示CNT计数器
	}
}


// 中断函数
void TIM2_IRQHandler(void)
{
	// 检测中断标志位,确保是设置的中断源触发的这个函数
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
	{
		// 中断处理
		speed = Encoder_Get();
		// 清除中断标志
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
	}
}

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

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

相关文章

达梦数据库dm8守护集群部署手册

环境说明 操作系统:liunx-centos7.6 服务器:3台虚拟机(主备数据库各一台,监视器一台(可选)) 达梦数据库版本:达梦V8 一、安装前准备工作 参考达梦官方文档:https://eco.dameng.com/documen…

记一次堆内外内存问题的排查和优化

为优化淘宝带宽成本,我们在网关 SDK(Java)统一使用 ZSTD 替代 GZIP 压缩以获取更高的压缩比,从而得到更小的响应包。具体实现采用官方推荐的 zstd-jni 库。zstd-jni 会调用 zstd 的 c 库。 背景 在性能压测和优化过程中&#xff0…

基于 Gin 的 HTTP 中间人代理 Demo

前面实现的代理对于 HTTPS 流量是进行盲转的,也就是说直接在 TCP 连接上传输 TLS 流量,但是我们无法查看或者修改它的内容。当然了,通常来说这也是不必要的。不过对于某些场景下还是有必要的,例如使用 Fiddler 进行抓包或者监控其…

Git 五分钟教程速度入门

Git 五分钟教程速度入门 分类 编程技术 许多人认为 Git 太混乱,或认为它是一种复杂的版本控制系统,其实不然,这篇文章有助于大家快速上手使用 Git。 入门 使用Git前,需要先建立一个仓库(repository)。您可以使用一个已经存在的…

HLS实现图像膨胀和腐蚀运算--xf_dilation和xf_erosion

一、图像膨胀和图像腐蚀概念 我们先定义,需要处理的图片为二值化图像A。图片的背景色为黑色,即像素值为0。图片的目标色为白色,即像素值为1。 再定义一个结构元S,结构元范围内所有的像素为白色,像素值为1。 1、图像的…

自下而上-存储全栈(TiDB/RockDB/SPDK/fuse/ceph/NVMe/ext4)存储技术专家成长路线

数字化时代的到来带来了大规模数据的产生,各行各业都面临着数据爆炸的挑战。 随着云计算、物联网、人工智能等新兴技术的发展,对存储技术的需求也越来越多样化。不同应用场景对存储的容量、性能、可靠性和成本等方面都有不同的要求。具备存储技术知识和技…

HarmonyOS应用开发-闪屏启动页

这是鸿蒙开发者网站的一个应用《溪村小镇》示例代码,把闪屏启动页单拿出来,分析一下代码。 一、先上效果图 这是应用打开时的一个启动页,启动页会根据三个时间段(白天、傍晚、晚上)来分别展示溪村小镇不同的景色。 二…

RocketMQ-RocketMQ高性能核心原理与源码剖析(下)

融汇贯通阶段 ​ 开始梳理一些比较完整,比较复杂的完整业务线。 8、消息持久化设计 1、RocketMQ的持久化文件结构 ​ 消息持久化也就是将内存中的消息写入到本地磁盘的过程。而磁盘IO操作通常是一个很耗性能,很慢的操作,所以,…

MyBatis--07--启动过程分析、SqlSession安全问题、拦截器

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 谈谈MyBatis的启动过程具体的操作过程如下:实现测试类,并测试SqlSessionFactorySqlSession SqlSession有数据安全问题?在MyBatis中,SqlSess…

App备案、ios备案Bundle ID查询、公钥信息、SHA-1值

App备案、ios备案Bundle ID查询、公钥信息、SHA-1值 Bundle ID这个就不说了,都知道是啥,主要说公钥信息和SHA-1值的获取 打开钥匙串访问,找到当前需要备案App的dis证书,如下: #####右键点击显示简介 #####可以看…

ThinkPHP生活用品商城系统

有需要请加文章底部Q哦 可远程调试 ThinkPHP生活用品商城系统 一 介绍 此生活用品商城系统基于ThinkPHP框架开发,数据库mysql,前端bootstrap。系统分为用户和管理员。(附带配套设计文档) 技术栈:ThinkPHPmysqlbootstrapphpstudyvscode 二 …

小米手机锁屏时间设置为永不休眠_手机不息屏_保持亮屏

环境:打开手机自带的锁屏时间设置发现没有 永不息屏的选项 原因:采用了三星OLED屏幕,所以根据OLED屏幕特性,这个是为了防止烧屏而特意设计的。非OLED机型支持设置“永不” 解决方案1:原生系统是支持永不锁屏的&#…

【自定义Source、Sink】Flink自定义Source、Sink对redis进行读写操作

使用ParameterTool读取配置文件 Flink读取参数的对象 Commons-cli: Apache提供的,需要引入依赖ParameterTool:Flink内置 ParameterTool 比 Commons-cli 使用上简便; ParameterTool能避免Jar包的依赖冲突 建议使用第二种 使用Par…

STL(七)(map篇)

### 这里重点学习map ### 在实际做题过程中,multimap几乎用不到### unordered_map拥有极好的平均时间复杂度和极差的最坏时间复杂度,所以他的时间复杂度是不稳定的,unordered_map一般用不到,要做一个了解 1.map map是一种关联容器,用于存储一组键值对(key-value pairs),其中每…

鸿蒙开发组件之Slider

一、Slider控件是鸿蒙开发中的滑动条组建,初始化方式 Slider({min:0, //最小值max:100,//最大值value:30,//默认值step:10,//步长,每次滑动的差值style:SliderStyle.OutSet, //滑块的样式,默认outsetdirection:Axis.Horizontal, //水平方式的…

Transformer 简介

Transformer 是 Google 在 2017 年底发表的论文 Attention Is All You Need 中所提出的 seq2seq 模型。Transformer 模型的核心是 Self-Attention 机制,能够处理输入序列中的每个元素,并能计算其与序列中其他元素的交互关系的方法,从而能够更…

【自定义Source、Sink】Flink自定义Source、Sink对ClickHouse进行读和批量写操作

ClickHouse官网文档 Flink 读取 ClickHouse 数据两种驱动 ClickHouse 官方提供Clickhouse JDBC.【建议使用】第3方提供的Clickhouse JDBC. ru.yandex.clickhouse.ClickHouseDriver ru.yandex.clickhouse.ClickHouseDriver.现在是没有维护 ClickHouse 官方提供Clickhouse JDBC…

【小沐学Python】Python实现语音识别(SpeechRecognition)

文章目录 1、简介2、安装和测试2.1 安装python2.2 安装SpeechRecognition2.3 安装pyaudio2.4 安装pocketsphinx(offline)2.5 安装Vosk (offline)2.6 安装Whisper(offline) 3 测试3.1 命令3.2 fastapi3.3 go…

【数据结构】——排序篇(上)

前言:前面我们已经学过了许许多多的排序方法,如冒泡排序,选择排序,堆排序等等,那么我们就来将排序的方法总结一下。 我们的排序方法包括以下几种,而快速排序和归并排序我们后面进行详细的讲解。 直接插入…

C#注册表技术及操作

目录 一、注册表基础 1.Registry和RegistryKey类 (1)Registry类 (2)RegistryKey类 二、在C#中操作注册表 1.读取注册表中的信息 (1)OpenSubKey()方法 (2)GetSubKeyNames()…
最新文章