【嵌入式学习-STM32F103-TIM-编码器接口】

这篇具有很好参考价值的文章主要介绍了【嵌入式学习-STM32F103-TIM-编码器接口】。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本质

编码器测速相当于测频法测正交脉冲的频率,CNT计次,每隔一段时间取一次计次。高级,它是带方向的计次。

手册

stm32f103 tim1 编码器,嵌入式学习-STM32,stm32,单片机,c语言,学习

编码器接口简介

通过定时器的编码器接口来实现自动计次。之前的代码是通过触发外部中断,然后在中断函数里手动进行计次。使用编码器接口的好处就是节约软件资源。对于频繁执行,操作简单的任务,一般设计一个硬件电路模块来自动完成。

使用定时器的编码器接口,再配合编码器,就可以测量旋转速度和旋转方向。编码器测速一般应用在电机控制的项目上。使用PWM驱动电机,再使用编码器测量电机的速度,然后再使用PID算法进行闭环控制。
stm32f103 tim1 编码器,嵌入式学习-STM32,stm32,单片机,c语言,学习
编码器的工作流程:根据编码器旋转产生的正交信号脉冲,自动控制CNT自增或自减,从而只是编码器的位置、旋转方向和旋转速度

这是一个编码器,它有两个输出,一个是A相,一个是B相,然后接入到stm32,定制起的编码器接口,编码器接口自动控制定时器时基单元中的CNT计数器进行自增或自减。比如初始化后,CNT初始值为0,然后编码器右转,CNT就++,右转产生一个脉冲,CNT就加一次,比如右转产生10个脉冲停下来,那么CNT就由0自增到10,停下来。编码器左转,CNT就–,左转产生一个脉冲,CNT减一次,如编码器左转产生5个脉冲,CNT就在原来10的基础上自减5停下来。

stm32f103 tim1 编码器,嵌入式学习-STM32,stm32,单片机,c语言,学习
正交编码器(输出两个相位相差90°的方波信号)一般可以测量位置,或者带有方向的速度值,它一般有两个信号输出引脚,一个是A相,一个是B相,当编码器的旋转轴转起来,A和B相会输出方波信号,转的越快,方波的频率就越高,所以方波的频率就代表了速度。取出任意一相的信号来测量频率,就能知道旋转速度。

方向:当正转时,A相提前B相90度,反转时,A相滞后B相90度。接口:一个带有方向控制的外部时钟
使用正交信号精度更高,AB相都可以计次,相当于计次频率提高了一倍,还可以加抗噪声电路。

首先把A相和B相的所有边沿作为计数器的计数时钟,出现边沿信号时,就计数自增或自减,自增或自减的计数方向由另一相的状态来决定。查下表即可。
stm32f103 tim1 编码器,嵌入式学习-STM32,stm32,单片机,c语言,学习
编码器接口有两个输入端,分别要接到编码器的A相和B相,有两个网络标号分别写的是TI1FP1和TI2FP2

stm32f103 tim1 编码器,嵌入式学习-STM32,stm32,单片机,c语言,学习

可以看出这个编码器接口的两个引脚,借用了输入捕获单元的前两个通道,所以最终编码器的输入引脚是定时器的CH1和CH2这两个引脚

stm32f103 tim1 编码器,嵌入式学习-STM32,stm32,单片机,c语言,学习
信号的通路如下(与CH3和CH4无关 ),编码器接口使用CH1和CH2的输入捕获滤波器和边沿检测,但没有使用后面的是否交叉、预分频器和CCR寄存器

stm32f103 tim1 编码器,嵌入式学习-STM32,stm32,单片机,c语言,学习
编码器接口的输出部分就相当于从模式控制器,去控制CNT的计数时钟和计数方向,如果出现了边沿信号,并且对应另一相的状态为正转,则控制CNT自增,否则控制CNT自减。

stm32f103 tim1 编码器,嵌入式学习-STM32,stm32,单片机,c语言,学习
注意:72MHZ内部时钟(CK_PSC)和在时基单元初始化设置的计数方向(上图的+/-)并不会使用,因为此时计数时钟和计数方向都处于编码器接口托管的状态,计数器的自增和自减受编码器的控制

stm32f103 tim1 编码器,嵌入式学习-STM32,stm32,单片机,c语言,学习

编码器接口基本结构

输入捕获的前两个通道,通过GPIO口接入编码器A、B相,通过滤波器和边沿检测极性选择,产生TI1FP1和TI2FP2,通向编码器接口,编码器接口通过预分频器控制CNT计数器的时钟,同时,编码器接口还根据编码器的旋转方向,控制CNT的计数方向,编码器正转时,CNT自增,编码器反转时,CNT自减,ARR有效,一般我们设置ARR为65535,最大量程。补码:65535对应-1,依此类推(读出数据,得到负数的技巧)

stm32f103 tim1 编码器,嵌入式学习-STM32,stm32,单片机,c语言,学习

工作细节和例子

在两相边沿计数,计数精度高(一般使用该模式)
正转

正转的状态都向上计数,反转的状态的都向下计数。

stm32f103 tim1 编码器,嵌入式学习-STM32,stm32,单片机,c语言,学习
实例图1(向上计数、向下计数、正交编码器抗噪声)

如果出现了一个引脚不变,另一个引脚连续跳变多次的毛刺信号,计数器就会加、减、加、减来回摆动,最终计数值还是原来那个数,并不受毛刺噪声的影响。正交编码器抗噪声的原理
stm32f103 tim1 编码器,嵌入式学习-STM32,stm32,单片机,c语言,学习
实例2(TI1反相,TI2不反相)极性

stm32f103 tim1 编码器,嵌入式学习-STM32,stm32,单片机,c语言,学习

编码器接口测速

硬件接线图

计划用TIM3接编码器,所以需要接在PA6和PA7这两个引脚上。
stm32f103 tim1 编码器,嵌入式学习-STM32,stm32,单片机,c语言,学习
stm32f103 tim1 编码器,嵌入式学习-STM32,stm32,单片机,c语言,学习

编程步骤

stm32f103 tim1 编码器,嵌入式学习-STM32,stm32,单片机,c语言,学习
第一步,RCC开启时钟,开启GPIO和定时器的时钟

第二步,配置GPIO,将PA6和PA7配置成输入模式

第三步,配置时基单元,这里预分频一般选择不分频

第四步, 配置输入捕获单元,只需要配置滤波器和极性两个参数

第五步,配置编码器接口模式

最后,调用TIM_Cmd启动定时器

电路初始化完成后,CNT就会随着编码器旋转而自增自减,如果想要测量编码器的位置,直接读出CNT的值即可,如果想要测量编码器的速度和方向,那就需要每隔一段固定的闸门时间,取出CNT,然后把CNT清零。

stm32f103 tim1 编码器,嵌入式学习-STM32,stm32,单片机,c语言,学习
上拉输入还是下拉输入的选择

一般可以看一下接在这个引脚的外部模块输出的默认电平,如果外部模块空闲默认输出高电平,我们就选择上拉输入,默认输入高电平,如果外部模块默认输出低电平,我们配置下拉输入,默认输入低电平。总结,将需要配置电平的位置和外部模块保持默认状态一致,防止默认电平打架。

stm32f103 tim1 编码器,嵌入式学习-STM32,stm32,单片机,c语言,学习
如果不确定外部模块输出的默认状态或者外部信号输出功率非常小,这时尽量选择浮空输入,浮空输入没有上下拉电阻去影响外部信号,缺点是当引脚悬空时,没有默认电平,输入就会受噪声干扰,来回不断跳变。

实验现象

测位置

A、B相各出现了一个下降沿和上升沿,所以计次总共加了4次。

stm32f103 tim1 编码器,嵌入式学习-STM32,stm32,单片机,c语言,学习
如果转到0,再往左转,0自减,计数器反向溢出,回到自动重装值,65535,然后继续往下减。

stm32f103 tim1 编码器,嵌入式学习-STM32,stm32,单片机,c语言,学习

如果我们想让0自减为-1,直接把uint16_t类型强制转换成int16_t即可
stm32f103 tim1 编码器,嵌入式学习-STM32,stm32,单片机,c语言,学习

极性问题

硬件方面:对换AB相接线即可
软件方面:通过修改两个输入通道的极性,把任意一个极性反转一下,方向就会反过来
stm32f103 tim1 编码器,嵌入式学习-STM32,stm32,单片机,c语言,学习

测速度

如果想让编码器测速度,可以在固定的闸门时间读一次CNT,然后把CNT清零,此时CNT的值代表速度,单位是脉冲个数/S

代码

1、通过Delay实现闸门时间,如果程序没有其他东西,可以这么做
2、如果有其他东西,最好不要在主循环加入过长的Delay函数,这样会阻塞主循环的执行,比较好的方法时使用定时中断,这里的定时中断是每隔1s执行一次,可修改定时中断的时间,来调整闸门时间。

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Timer.h"
#include "Encoder.h"
//全局变量
uint16_t Speed;

int main(void)
{
	OLED_Init();
	Timer_Init();
	Encoder_Init();
	
	OLED_ShowString(1, 1, "Speed:");
	
	while (1)
	{
		//在主循环里每隔一段时间get一次CNT值,可快速刷新Speed
		OLED_ShowSignedNum(1, 7, Speed, 5);
		//OLED_ShowSignedNum(1, 7, Encoder_Get(), 5);
		//Delay_ms(1000);//1s  (最好将闸门时间弄短,提高速度刷新频率,防止计数器溢出)
		//因为每一秒都会清零,CNT最多是1妙内的值,就是速度
		//CNT的值代表速度,单位是脉冲个数/s
		
		
	}
}

void TIM2_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
	{
		//每隔一秒读取一下速度,存在speed变量里
		Speed = Encoder_Get();
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
	}
}

Encoder.c

如果想要测量编码器的位置,直接读出CNT的值就可以
如果想要测量编码器的速度和方向,需要每隔一段固定的闸门时间,取出一次CNT,然后再把CNT清零(测频法测量速度

#include "stm32f10x.h"

//编码器接口初始化
void Encoder_Init(void)
{
	//1、开启时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);  //由于代码需要TIM2输出PWM,因此,输入捕获定时器需要换一个
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	//2、配置GPIO
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;  //上拉输入
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;	//PA6和PA7	
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	//3、配置时基单元
	//TIM_InternalClockConfig(TIM3);  //定时器内部时钟配置不需要,因为编码器接口会托管时钟,编码器接口就是一个带方向控制的外部时钟
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;  //向上计数,这个计数值是由编码器托管的,它暂时没有用到
	TIM_TimeBaseInitStructure.TIM_Period = 65535 - 1;		//ARR周期,给最大值,防止溢出,16位计数器可以满量程计数
	TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1;		//PSC,不分频,编码器时钟,直接驱动计数器
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);  //把以上参数配置为TIM3的时基单元
	//4、初始化输入捕获单元
	TIM_ICInitTypeDef TIM_ICInitStruct;
	//输入捕获单元并没有全部使用到,编码器接口只使用了通道1和通道2的滤波器和极性选择,因此只需要配置这两部分的参数即可
	//由于无需配置两个参数,因此结构体配置不完整,又为了防止结构体中出现不确定值可能会造成问题,默认配置
	TIM_ICStructInit(&TIM_ICInitStruct);
	//通道1
	TIM_ICInitStruct.TIM_Channel = TIM_Channel_1;  //选用TIM3的通道1
	TIM_ICInitStruct.TIM_ICFilter = 0xF;   //用于选择输入捕获的滤波器
	//由于待会配置编码器接口时有配置极性选择,所以此处属于重复配置,因此可省略
	//TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;  //上升沿参数代表的是高低电平极性不反转,也就是TI1和TI2是否反相
	//TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;  //不分频就是每次触发都有效,2分频就是每个一次有效一次,以此类推
	//TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI; //配置数据选择器,可以选择直连通道或者交叉通道
	TIM_ICInit(TIM3,&TIM_ICInitStruct);
	
	//通道2
	TIM_ICInitStruct.TIM_Channel = TIM_Channel_2;  //选用TIM3的通道1
	TIM_ICInitStruct.TIM_ICFilter = 0xF;   //用于选择输入捕获的滤波器
	//TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;  ,与5编码器接口配置重复配置,因此这里可删掉,同一由配置编码器接口配置即可。
	TIM_ICInit(TIM3,&TIM_ICInitStruct);
	
	//5、配置编码器接口,只需要调用一个函数即可,保证ICInit在该函数的上面,否则会出现覆盖问题,TI1和TI2都计数
	TIM_EncoderInterfaceConfig(TIM3,TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICPolarity_Rising);
	
	//开启定时器
	TIM_Cmd(TIM3,ENABLE);
}
//测位置
//int16_t Encoder_Get(void)
//{
//直接返回CNT的值
//	return TIM_GetCounter(TIM3);
//}
//测速度
int16_t Encoder_Get(void)
{
//因为先读取后清零,因此需要用Temp缓存一下
	int16_t Temp;
	//获取CNT的值
	Temp = TIM_GetCounter(TIM3);
	//CNT清零
	TIM_SetCounter(TIM3,0);
	//返回temp值
	return Temp;
}


Encoder.h

#ifndef __ENCODER_H
#define __ENCODER_H

void Encoder_Init(void);  //编码器初始化
int16_t Encoder_Get(void);  //获取编码器的位置或速度
#endif

以下是定时中断部分代码,因为利用测频法,因此固定1s定时进入中断一次文章来源地址https://www.toymoban.com/news/detail-791252.html

Timer.c

#include "stm32f10x.h"                  // Device header

void Timer_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	
	TIM_InternalClockConfig(TIM2);
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period = 10000 - 1;
	TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1;
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
	
	TIM_ClearFlag(TIM2, TIM_FLAG_Update);
	TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_Init(&NVIC_InitStructure);
	
	TIM_Cmd(TIM2, ENABLE);
}

/*
void TIM2_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
	{
		
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
	}
}
*/

Timer.h

#ifndef __TIMER_H
#define __TIMER_H

void Timer_Init(void);

#endif

到了这里,关于【嵌入式学习-STM32F103-TIM-编码器接口】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • STM32——TIM编码器接口

    Encoder Interface 编码器接口 编码器接口可接收增量(正交)编码器的信号,根据编码器旋转产生的正交信号脉冲, 自动控制CNT自增或自减 ,从而指示编码器的位置、旋转方向和旋转速度 每个高级定时器和通用定时器都拥有 1个编码器接口 ,C8T6拥有4个编码器接口 两个输入引脚

    2024年01月19日
    浏览(37)
  • STM32 TIM编码器接口

    单片机学习! 目录 文章目录 前言 一、编码器接口简介 1.1 编码器接口作用 1.2 编码器接口工作流程 1.3 编码器接口资源分布 1.4 编码器接口输入引脚 二、正交编码器 2.1 正交编码器功能 2.2 引脚作用 2.3 如何测量方向 2.4 正交信号优势 2.5 执行逻辑 三、编码器定时器框图 3.1 编

    2024年04月14日
    浏览(41)
  • [嵌入式软件][启蒙篇][仿真平台] STM32F103实现串口输出输入、ADC采集

    上一篇:[嵌入式软件][启蒙篇][仿真平台] STM32F103实现LED、按键 学C语言时,使用的printf()函数,就是通过串口打印出来的。 跟外部器件通信,比如GPS模块、蓝牙模块、wifi模块; 两个开发板之间通信,制定私有协议。 PC电脑通信,使用上位机显示数据或控制下位机。 操作:打

    2024年01月22日
    浏览(52)
  • 【单片机】STM32单片机读取旋转编码器,TIM定时器编码器模式捕获,程序

    旋转编码器简单来说,就是会输出2个PWM,依据相位可以知道旋转方向,依据脉冲个数可以知道旋转的角度。一般旋转一圈有一个固定数值的脉冲个数。 旋转编码器广泛用于电机、或者角度传感器,STM32的定时器可以直接接入这两个波形获取到信息。 前两个引脚(接地和Vcc)

    2024年02月13日
    浏览(38)
  • 【嵌入式学习笔记】嵌入式基础9——STM32启动过程

    程序段交叉引用关系(Section Cross References):描述各文件之间函数调用关系 删除映像未使用的程序段(Removing Unused input sections from the image):描述工程中未用到被删除的冗余程序段(函数/数据) 映像符号表(Image Symbol Table):描述各符号(程序段/数据)在存储器中的地址、类

    2024年02月15日
    浏览(74)
  • STM32的时钟系统(嵌入式学习)

    时钟是指用于计量和同步时间的装置或系统。时钟是嵌入式系统的脉搏,处理器内核在时钟驱动下完成指令执行,状态变换等动作,外设部件在时钟的驱动下完成各种工作,例如:串口数据的发送、AD转换、定时器计数等。因此时钟对于计算机系统是至关重要的,通常时钟系

    2024年02月16日
    浏览(41)
  • STM32串口通信详解(嵌入式学习)

    时钟信号在电子领域中是指用于同步和定时电路操作的周期性信号。它在数字系统和通信系统中起着至关重要的作用,用于协调各个组件之间的数据传输和操作。 时钟信号有以下几个重要的方面: 频率:时钟信号的频率是指单位时间内信号周期的数量。它通常以赫兹(Hz)为

    2024年02月09日
    浏览(58)
  • STM32的中断系统详解(嵌入式学习)

    中断是处理器中的一种机制,用于响应和处理突发事件或紧急事件。当发生中断时,当前正在执行的程序会被暂时中止,处理器会跳转到中断处理程序(也称为中断服务例程),对中断事件进行处理。处理完中断后,处理器再返回到被中断的程序继续执行。 中断可以分为内部

    2024年02月12日
    浏览(61)
  • 嵌入式学习笔记——STM32的时钟树

    在之前的所有代码编程的过程中,似乎每次都绕不开一个叫做时钟使能的东西,当时我们是在数据手册上直接看其挂接在那条时钟线上的,那么STM32内部的时钟到底是怎么一个构型呢,本文来对此做一个介绍。 老规矩,一个新的名词出现,首先需要搞清楚它是个啥,下图中对

    2024年02月02日
    浏览(48)
  • stm32f103单片机—编码器测速

    stm32f103ZET6开发板(非指定) MG513P3012V型号电机(带霍尔编码器)(非指定) 此种测速方法要求单片机的定时器具有编码器模式,对于stm32f1系列,具备编码器模式的定时器有TIM1/2/3/4/5/8, 定时器使用通道1、2来实现编码器功能 ,接线时注意把A/B相接到定时器通道1/2的引脚。 电

    2024年02月06日
    浏览(66)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包