首页 > 其他分享 >stm32-编码器测速

stm32-编码器测速

时间:2024-03-14 21:29:26浏览次数:12  
标签:NVIC 编码器 stm32 TIM TimeBaseInitStruct GPIO 测速 时钟

一、编码器简介

 

编码电机

 

旋转编码器

 

A,B相分别接通道一和二的引脚,VCC,GND接单片机VCC,GND

二、正交编码器工作原理

1.计数方式

 2.框图分析

 由图可知,只有CH1和CH2有编码器接口,且编码器只用到了输入捕获结构体的输入滤波和边沿检测器,则其余的结构体成员都不用区配置。

 由框图可知,配置Encoder需要配置GPIO,输入捕获结构体的部分元素,时基单元,我们一般给ARR为65535-1,即最大计数量程,防止计数溢出。PSC=1-1,不分频,直接72M进行计数

3.计数方向与编码器信号的关系

 TIM_EncoderInterfaceConfig(TIM3,TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICPolarity_Rising)

这里TIM_EncoderMode_TI12即对应上面的计数边沿,仅在TI1和TI2计数就相当于只在A或B相的边沿计数,我们一般都使用AB相都计数

 

 

三、固件库使用

1.开启GPIO和TIM的时钟

2.配置GPIO结构体,模式配置为上拉输入

3.不用配置内部时钟源,因为编码器托管了时钟,编码器接口就是带方向控制的外部时钟,      所以内部时钟就没有用了    

4.配置时基单元,计数模式就不用配置了,取决于编码器的AB相边沿,ARR为65535-1,     PSC = 1-1不分频

5.配置输入捕获单元(因为是由)TI1FP1和2接入到编码器接口的,所以捕获单元结构体    元素只需配置输入滤波和边沿检测即可,这里边沿检测给上升沿还是下降沿并不是说是

   哪个有效,因为编码器模式下上/下沿都有效,这里指电平极性是否翻转,高电平不反转,

    低电平翻转

6.TIM_EncoderInterfaceConfig();配置编码器,TIM_Cmd();使能定时器

7.使用中断读取Encoder的值

上拉输入还是下拉输入的选择

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

如果不确定外部模块输出的默认状态或者外部信号输出功率非常小,这时尽量选择浮空输入,浮空输入没有上下拉电阻去影响外部信号,缺点是当引脚悬空时,没有默认电平,输入就会受噪声干扰,来回不断跳变。

#include "encoder.h"


void Encoder_Init(void)
{
	//开启GPIO和TIM3时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	
	//初始化GPIO
	GPIO_InitTypeDef GPIO_InitStruct;//定义GPIO结构体
	//GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;//输入不需要配置速度
	GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_IPU;
	GPIO_InitStruct.GPIO_Pin   = GPIO_Pin_6 | GPIO_Pin_7;
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	
	//因为编码器接口会托管时钟,编码器接口就是带方向控制的外部时钟,所以内部时钟就没有用了	
	//TIM_InternalClockConfig(TIM2);
	
	//配置时基单元
	//初始化时基单元
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	TIM_TimeBaseInitStruct.TIM_Prescaler = 1-1;//PSC-预分频器,给0,不分频
	//TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;//计数方向被编码器托管了
	TIM_TimeBaseInitStruct.TIM_Period = 65535-1;//ARR寄存器-重装载寄存器
	TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;/*不分频----滤波器的采样频率,                                    
                                                                  可以由内部时钟直接提供,														                 
                                                        也可以由内部时钟加一个时钟分频而来,
												分频系数就是由TIM_ClockDivision决定*/
	TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;//重复计数器,只有高级定时器才有	
	TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct);

	//配置输入捕获单元
	TIM_ICInitTypeDef TIM_ICInitStruct;
	TIM_ICStructInit(&TIM_ICInitStruct);
	TIM_ICInitStruct.TIM_Channel = TIM_Channel_1;
	TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;//电平极性选择,高电平极性不反        
                                                                 转,低电平极性反转
	//TIM_ICInitStruct.TIM_ICSelection //直连or交叉连
	//TIM_ICInitStruct.TIM_ICPrescaler //分频器因子,即每N个边沿跳变事件捕获一次-CCMR1_ICPS
	TIM_ICInitStruct.TIM_ICFilter = 0xF;//CCMR1_ICF
	TIM_ICInit(TIM3, &TIM_ICInitStruct);
	
	TIM_ICInitStruct.TIM_Channel = TIM_Channel_2;
	TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;//电平极性选择,高电平极性不反    
                                                             转,低电平极性反转
	TIM_ICInitStruct.TIM_ICFilter = 0xF;//CCMR1_ICF
	TIM_ICInit(TIM3,&TIM_ICInitStruct);
	
	TIM_EncoderInterfaceConfig(TIM3,TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICPolarity_Rising);//这里的上升沿和上面结构体配置的效果一样,所以前面的可以删去

	//使能TIM
	TIM_Cmd(TIM3,ENABLE);
}

int16_t Encoder_Get(void)//int16_t 为了显示负数
{
	int16_t temp;
	temp = TIM_GetCounter(TIM3);
	TIM_SetCounter(TIM3,0);//这里每次获得了编码器的值后就清零CNT是为了得到速度
                           //我们使用了中断,一秒进入一次然后读取CNT的值作为旋转速度
	return temp;
}

#include "bsp_tim.h"

void Time_Config()
{
	//开启时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
	
	//选择时基单元的时钟-为内部时钟--定时器上电后默认是内部时钟,故不写这一个也行
	TIM_InternalClockConfig(TIM2);
	
	//初始化时基单元
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	TIM_TimeBaseInitStruct.TIM_Prescaler = 7200-1;//PSC-预分频器
	TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;//向上计数 
	TIM_TimeBaseInitStruct.TIM_Period = 10000-1;//ARR寄存器-重装载寄存器
	TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;/*不分频----滤波器的采样频率,可以由内部时钟直接提供,
																													也可以由内部时钟加一个时钟分频而来,
																													分频系数就是由TIM_ClockDivision决定*/
	TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;//重复计数器,只有高级定时器才有
	
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct);
	
	//使能中断-事件更新
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
	
	TIM_ClearFlag(TIM2,TIM_IT_Update);//因为TIM_TimeBaseInit函数最后有一个直接操作UG位的操作
	                                  //使得直接产生了一个更新事件,因此直接进行给UIE位置1
									 //直接进入了中断,使得我们初始化ARR和PSC还未写入到
									//影子寄存器,使得Num一上电就是1
									//所以在进入中断之前先清楚中断标志位
	
	//使能中断之后就要进入NVIC了
	//先优先级分组
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
	//配置结构体
	NVIC_InitTypeDef NVIC_InitStruct;
	NVIC_InitStruct.NVIC_IRQChannel = TIM2_IRQn;//中断通道
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStruct);
	
	//启动定时器
	TIM_Cmd(TIM2,ENABLE);
	//在_it文件里编写中断服务函数
}

#include ".\tim\bsp_tim.h"
#include "encoder.h"
#include ".\OLED\OLED.h"



int16_t speed;
int main()
{
	Time_Config();
	Encoder_Init();
	OLED_Init();
	while(1)
	{
		OLED_ShowSignedNum(1,5,speed,5);
	}
}
void TIM2_IRQHandler()
{
	//先获取中断标志位
	if(TIM_GetITStatus(TIM2,TIM_IT_Update) == SET)
	{
		speed = Encoder_Get();
		//清楚中断标志位
		TIM_ClearFlag(TIM2,TIM_FLAG_Update);
	}
}

 

 

标签:NVIC,编码器,stm32,TIM,TimeBaseInitStruct,GPIO,测速,时钟
From: https://blog.csdn.net/2301_79330491/article/details/136721271

相关文章

  • STM32G431RBT6LED灯02
    cubeMX根据引脚 选取这些引脚,设置为GPIO_Output除复用引脚之外的需要设置输出为HighLED控制语句<led.c>#include<led.c>voidLED_Disp(uchardsLED){HAL_GPIO_WritePin(GPIOC,GPIO_PIN_All,GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOC,dsLED<<8,GPIO_PIN_RESET);HAL_G......
  • STM32标准库低功耗
    STM32标准库低功耗1.睡眠模式1.1.进入以及退出方法睡眠模式较为简单,仅需要简单调用函数即可,且函数定义处于内核层,不需要引用多余的头文件。睡眠模式:仅内核停止,所有外设仍旧运行。调用"__WFI()"函数,退出方式为任意中断。调用"__WFE()"函数,退出方式为唤醒事件。2.停......
  • stm32F103 移植Free RTOS
    #stm32F103移植FreeRTOS1.下载FreeRTOS源码[官网下载](http://www.freertos.org)[代码托管网站下载](https://sourceforge.net/projects/freertos/files/FreeRTOS)2.FreeRTOS文件介绍进入Source文件夹进入portable文件夹进入RVDS3.FreeRTOS移......
  • stm32 foc 库输出波形
    前言本文为学习st的FOC库笔记,记录FOC库实际输出的PWM波形之间的区别。关键词:SPWM,SVPWM,Overmodulation,DiscontinuousPWM标准波形输出对应Modulationflags为None可以看到,输出波形为马鞍波,即生成波形为SVPWM。对比逆克拉克变换生成的SPWM,生成的波形两者幅值相同。......
  • 深度学习--自编码器(AE)、变分自编码器(VAE)
    提示:仅供自己学习、复习需要,有任何问题可在评论区提出。深度学习--自编码器一、自编码器AE二、变分自编码器VAE1.为什么要有VAE2.VAE推导一、自编码器AE自编码器是一种无监督的特征学习,其目的是利用无标签数据找到一个有效的低维的特征提取器。那什么是特征学习......
  • STM32模拟IIC读取ACD10红外二氧化碳数据
    引脚介绍ACD10通过IIC来通信我们使用下图右边四个引脚就可以了,系统默认模式为IIC通信方式,他也支持USART串口通信不过需要配置pin5引脚(低电平)。模拟IIC通信配置比较简单,在单片机上面随便找两个引脚就可以。用来配置SDA数据与SCL时钟引脚。读取数据命令官方给我们命令行列......
  • 基于STM32F103C8T6单片机学习(江科大版本)
    学习内容1:用库函数来控制IO输出控制LED闪烁,LED流水灯,蜂鸣器主要用到GPIO_unit()函数配置GPIO口和RCC外设时钟控制函数,GPIO的写函数,setbitsresitbits,write等函数 1.led闪烁1.文件配置LED闪烁硬件电路图​​​​​ 首先打开文件管理器,在STM32>工程项目文件......
  • 在stm32f767中使用fmc外挂dram
    `uint16_tbuf[6]attribute((at(0xd0000000)))={0};//将缓冲数组分配到外部dram中。voidTestDram(void){uint16_txxx[6]={0x1111,0x2222,0x3333,0x4444,0x5555,0x6666};for(inti=0;i<5;i++){buf[i]=xxx[i];}for(inti=0;i<5;i++){ if(xxx[i]!......
  • stm32 TIM输出比较(OC) PWM
    stm32P6-4 05:00  ([6-4]PWM驱动LED呼吸灯&PWM驱动舵机&PWM驱动直流电机_哔哩哔哩_bilibili)1.stm32f10x.tim.h部分头文件讲解voidTIM_DeInit(TIM_TypeDef*TIMx);​​​​​​​voidTIM_TimeBaseInit(TIM_TypeDef*TIMx,TIM_TimeBaseInitTypeDef*TIM_TimeBaseInitStruct......
  • STM32 LwIP学习过程问题总结(一):LwIP ping不通,抓包发现ICMP校验和为0x0000
    一、问题今天在将之前的STM32LwIP1.4.1版本程序移植到2.1.2版本上时,发现ping不同,但是开发板有ICMP回复包,黄颜色警告checksum为0x0000。说明LwIP移植应该是没问题,数据处理这一块出错了。 在网上找了下相关的错误,ST论坛有个问题和我这个一样。HardwareIPv4checksumonanST......