STM32F407 电机编码器测量

12 篇文章 12 订阅
7 篇文章 9 订阅

一、STM32F407 定时器编码器功能

1.1 STM32定时器简介

STM32的定时器功能非常强大,根据官方手册,定时器的功能如下
高级定时器
TIM1 和 TIM8 主要特性
TIM1 和 TIM8 定时器具有以下特性:
● 16 位递增、递减、递增/递减自动重载计数器。
● 16 位可编程预分频器,用于对计数器时钟频率进行分频(即运行时修改),分频系数
介于 1 到 65536 之间。
● 多达 4 个独立通道,可用于:
— 输入捕获
— 输出比较
— PWM 生成(边沿和中心对齐模式)
— 单脉冲模式输出
● 带可编程死区的互补输出。
● 使用外部信号控制定时器且可实现多个定时器互连的同步电路。
● 重复计数器,用于仅在给定数目的计数器周期后更新定时器寄存器。
● 用于将定时器的输出信号置于复位状态或已知状态的断路输入。
● 发生如下事件时生成中断/DMA 请求:
— 更新:计数器上溢/下溢、计数器初始化(通过软件或内部/外部触发)
— 触发事件(计数器启动、停止、初始化或通过内部/外部触发计数)
— 输入捕获
— 输出比较
— 断路输入
● 支持定位用增量(正交)编码器和霍尔传感器电路。
● 外部时钟触发输入或逐周期电流管理。

通用定时器
TIM2 到 TIM5 主要特性
通用 TIMx 定时器具有以下特性:
● 16 位(TIM3 和 TIM4)或 32 位(TIM2 和 TIM5) 递增、递减和递增/递减自动重载计
数器。
● 16 位可编程预分频器,用于对计数器时钟频率进行分频 (即运行时修改),分频系数介
于 1 到 65536 之间。
● 多达 4 个独立通道,可用于:
— 输入捕获
— 输出比较
— PWM 生成(边沿和中心对齐模式)
— 单脉冲模式输出
● 使用外部信号控制定时器且可实现多个定时器互连的同步电路。
● 发生如下事件时生成中断/DMA 请求:
— 更新:计数器上溢/下溢、计数器初始化(通过软件或内部/外部触发)
— 触发事件(计数器启动、停止、初始化或通过内部/外部触发计数)
— 输入捕获
— 输出比较
● 支持定位用增量(正交)编码器和霍尔传感器电路
● 外部时钟触发输入或逐周期电流管理

1.2 STM32定时器编码器功能

根据下面的图可以看出通用定时器也是有编码器输入功能。
在这里插入图片描述

在编码输入时是有上升沿与下降沿的,我们可以利用外部中断分别捕获编码器A、B项边沿,手写逻辑消除毛刺并解析编码器数据,但这是比较复杂的。其实这里的脉冲输入是一种特殊的输入捕获情况,因此stm32专门在定时器中提供了编码器模式,可大大简化解析过程。

选择编码器接口模式时,如果计数器仅在 TI2 边沿处计数,在 TIMx_SMCR 寄存器中写入
SMS=001;如果计数器仅在 TI1 边沿处计数,写入 SMS=010;如果计数器在 TI1 和 TI2 边 沿处均计数,则写入 SMS=011。

通过编程 TIMx_CCER 寄存器的 CC1P 和 CC2P 位,选择 TI1 和 TI2 极性。如果需要,还可对输入滤波器进行编程TI1 和 TI2 两个输入用于连接增量编码器。请参见表 75。如果使能计数器(在 TIMx_CR1 寄 存器的 CEN 位中写入“1”),则计数器的时钟由 TI1FP1 或 TI2FP2 上的每次有效信号转 换提供。TI1FP1 和 TI2FP2 是进行输入滤波器和极性选择后 TI1 和 TI2 的信号,如果不进行 滤波和反相,则 TI1FP1=TI1,TI2FP2=TI2。将根据两个输入的信号转换序列,产生计数脉 冲和方向信号。根据该信号转换序列,计数器相应递增或递减计数,同时硬件对 TIMx_CR1 寄存器的 DIR 位进行相应修改。任何输入(TI1 或 TI2)发生信号转换时,都会计算 DIR 位,无论计数器是仅在 TI1 或 TI2 边沿处计数,还是同时在 TI1 和 TI2 处计数。

编码器接口模式就相当于带有方向选择的外部时钟。这意味着,计数器仅在 0 到 TIMx_ARR 寄存器中的自动重载值之间进行连续计数(根据具体方向,从 0 递增计数到 ARR,或从 ARR 递减计数到 0)。因此,在启动前必须先配置 TIMx_ARR。同样,捕获、比较、预分频 器、触发输出功能继续正常工作。

在此模式下,计数器会根据增量编码器的速度和方向自动进行修改,因此,其内容始终表示编码器的位置。计数方向对应于所连传感器的旋转方向。下表汇总了可能的组合(假设 TI1 和 TI2 不同时切换)。
在这里插入图片描述
下图为双项模式下计数效果,可见在A、B中仅一项有**抖动(**就是编译器无效的脉冲,需要过滤)时,计数值加减后保持不变,实现了抖动补偿
在这里插入图片描述
从图上可以看出,定时器是采集A、B两相的脉冲,当编码器输出一个周期时,定时器计数值为4,这是要必须记住的哈。

二、带编码器的直流电机

我手上刚好有一个带编码器的直流电机,电机参数如下,520电机包含编码器款该电机采用全金属齿轮,具备功率大、抗干扰好、精度高、寿命长的特点。
在这里插入图片描述
在这里插入图片描述
在这里需要说明一下,如果电机转一圈,那么黄线输出的脉冲数量为:1130 = 330个, 那么绿线输出的脉冲数量为:1130 = 330个。根据上面分析的定时器编码器模式,电机转一圈,定时器计数脉冲的个数为:330*4 = 1320个。

三、代码与验证

电机实物图
在这里插入图片描述

3.1 初始化代码

/****************************************
引脚说明

A相连接PB6
B相连接PB7

PB6 -- TIM4_CH1
PB7 -- TIM4_CH2

****************************************/

void TIM4_Int_Init(void) 
{		
	GPIO_InitTypeDef 	        GPIO_InitStruct;
	TIM_TimeBaseInitTypeDef	 	TIM_TimeBaseInitStructure;
	TIM_ICInitTypeDef 			TIM_ICInitStructure;
	NVIC_InitTypeDef			NVIC_InitStructure;
		
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE);//开启GPIOC的时钟
	

	
	GPIO_InitStruct.GPIO_Pin  	= GPIO_Pin_6|GPIO_Pin_7;
	GPIO_InitStruct.GPIO_Mode	= GPIO_Mode_AF;
	GPIO_InitStruct.GPIO_Speed	= GPIO_Speed_100MHz;
	GPIO_InitStruct.GPIO_OType	= GPIO_OType_OD;
	GPIO_InitStruct.GPIO_PuPd	=  GPIO_PuPd_UP;
	
	GPIO_Init(GPIOB, &GPIO_InitStruct);                          
	
	GPIO_PinAFConfig(GPIOB,GPIO_PinSource6,GPIO_AF_TIM4);//将引脚6映像到TIM8
    GPIO_PinAFConfig(GPIOB,GPIO_PinSource7,GPIO_AF_TIM4);//将引脚7映像到TIM8
	
		

  //定时器设置-------------------------------------------------------------	
    TIM_TimeBaseInitStructure.TIM_Period = 330*4;   				//重装载值 这是两相脉冲总数量
	TIM_TimeBaseInitStructure.TIM_Prescaler=0x0; 				 	//预分频
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; 	//向上计数
	TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; 		//时钟分割
	
	TIM_TimeBaseInit(TIM4,&TIM_TimeBaseInitStructure);//初始化TIM3

    //编码器模式设置--------------------------------------------------------------			  		

	TIM_EncoderInterfaceConfig(TIM4,TIM_EncoderMode_TI12,TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//计数模式3
	
	TIM_ICStructInit(&TIM_ICInitStructure); 
    TIM_ICInitStructure.TIM_ICFilter = 10;  //滤波器值
    TIM_ICInit(TIM4, &TIM_ICInitStructure);
    //溢出中断设置--------------------------------------------------------------
	TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE); //允许TIM4溢出中断
	
	NVIC_InitStructure.NVIC_IRQChannel					=TIM4_IRQn; 
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x01; 
	NVIC_InitStructure.NVIC_IRQChannelSubPriority		=0x01; 
	NVIC_InitStructure.NVIC_IRQChannelCmd				=ENABLE;
	NVIC_Init(&NVIC_InitStructure);
  
   //Reset counter-----------------------------------------------
   TIM_SetCounter(TIM4,0); //TIM3->CNT=0
   TIM_Cmd(TIM4, ENABLE); 
}




主函数

int Encoder_Timer_Overflow; //编码器溢出次数
 
u16 Previous_Count; 
u32 speed=0;
int circle_count = 0;   //记录电机正反转

//void TIM8_CC_IRQHandler(void)
//{
//	if(TIM_GetITStatus(TIM8,TIM_IT_Update)==SET)
//	{
//		Encoder_Timer_Overflow++;
//	}
//	TIM_ClearITPendingBit(TIM8,TIM_IT_Update); 

//}

//电机转动一圈产生中断
void TIM4_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM4,TIM_IT_Update)==SET)
	{
		Encoder_Timer_Overflow++;
		
		
		if((TIM4->CR1>>4 & 0x01)==0)     //DIR==0  通过寄存器TIMx_CR1第四位判断  0:电机正转
			circle_count++;
		else if((TIM4->CR1>>4 & 0x01)==1)//DIR==1  通过寄存器TIMx_CR1第四位判断  1:电机正转
			circle_count--;
	}
	TIM_ClearITPendingBit(TIM4,TIM_IT_Update); 

}
 
void Read_Encoder(void)
{
                                                       
  u16 Current_Count;           //一段时间的脉冲数                                  
  u16 Enc_Timer_Overflow_one;  //当前脉冲数                                  
                    
  Enc_Timer_Overflow_one=Encoder_Timer_Overflow;                  //获取中断溢出次数  
  Current_Count = TIM_GetCounter(TIM4);                           //得到脉冲数
  Encoder_Timer_Overflow=0;                                       //清0方便下次计算

  //speed = (u32)(Enc_Timer_Overflow_one*车轮周长+Current_Count/(330*4.0)*车轮周长);   //进行平均测速
 
}





int main(void)
{
	u16 m = 0,n = 0;
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	
	Delay_Init();
	usart1_init(115200);
	//TIM8_Int_Init();
	TIM4_Int_Init();
	
	
	while(1)
	{	


		delay_ms(500);
		delay_ms(500);
		//CNT的值,能够表示当前获取了多少个脉冲
		printf("获取定时器中的CNT值:%d\r\n",TIM4->CNT);
		//值为正,表示正转圈数比反转圈数多,反之亦然;值递增,表示正在正转,值递减,表示正在反转。
		printf("目前轮子正或反的圈数:%d\r\n",circle_count);

	}
	
	return 0;
}


3.2 验证

在这里插入图片描述

总结一下,通过对这些的理解,那么可以计算速度、角度、加速度等。
最后代码链接:https://download.csdn.net/download/wwwqqq2014/87124313?spm=1001.2014.3001.5503

  • 9
    点赞
  • 57
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

C是最好的编程语言

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值