电机学习笔记 stm32编码器模式

本文详细介绍了如何在STM32平台上利用M法和T法计算编码器转速,涉及编码器配置、计数器操作、中断处理以及转速计算公式。通过4倍频计数和TIM3初始化,探讨了如何处理编码器接口和编写相关回调函数,以实时监测电机转速变化。
摘要由CSDN通过智能技术生成

M法

M法: n(转速 r/s)= M0(编码器单位时间内的脉冲数) / (T0(单位时间)* C(单圈的脉冲数))
即 单位时间内的脉冲数 / 单圈的脉冲数
推导方法:
M0 / T0 = 1秒的总脉冲数 M1
M1 / C = 1秒转过多少圈(转速)
T法:
n(转速 r/s)= F1(测量的脉冲频率) / ( C(单圈的脉冲数) * M2(测量的脉冲数)) = 1 / C * TE(编码器两个脉冲之间的时间)
推导方法 :
1 / F1 = T1(周期), T1 * M2 = TE
TE * C = T2 (编码器转一圈所用的时间)
1秒 / T2 (即1秒内转过多少圈 (转速) )

32编码模式

在这里插入图片描述

4倍频计数
在这里插入图片描述
代码配置
在这里插入图片描述我们是2倍频
后面代码这里我们改一下改成为4倍频
TIM_ENCODERMODE_TI2改为TIM_ENCODERMODE_TI12

/* TIM3 init function */
void MX_TIM3_Init(void)
{
  TIM_Encoder_InitTypeDef sConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};

  htim3.Instance = TIM3;
  htim3.Init.Prescaler = 0;
  htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim3.Init.Period = 65535;
  htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  sConfig.EncoderMode = TIM_ENCODERMODE_TI12;
	
  sConfig.IC1Polarity = TIM_ICPOLARITY_RISING;
  sConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI;
  sConfig.IC1Prescaler = TIM_ICPSC_DIV1;
  sConfig.IC1Filter = 0;
	
  sConfig.IC2Polarity = TIM_ICPOLARITY_RISING;
  sConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI;
  sConfig.IC2Prescaler = TIM_ICPSC_DIV1;
  sConfig.IC2Filter = 0;
	
  if (HAL_TIM_Encoder_Init(&htim3, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }

}

然后我们还要能定时器的更新事件中断,使能编码器接口

 void Encoder_Configuration(void)
{
		/* 清零计数器 */
  __HAL_TIM_SET_COUNTER(&htim3, 0);
	  /* 清零中断标志位 */
  __HAL_TIM_CLEAR_IT(&htim3,TIM_IT_UPDATE);
	/* 使能定时器的更新事件中断 */
	__HAL_TIM_ENABLE_IT(&htim3,TIM_IT_UPDATE);
  /* 设置更新事件请求源为:计数器溢出 */
  __HAL_TIM_URS_ENABLE(&htim3);
	
	/* 使能编码器接口 */
  HAL_TIM_Encoder_Start(&htim3, TIM_CHANNEL_ALL);
	
}	

对于编码器接口输入通道的配置,我们只讲解通道 1 的配置情况,通道 2 是一样的。首先是输
入信号极性,成员 IC1Polarity 在输入捕获模式中是用来设置触发边沿的,但在编码器模式中是
用来设置输入信号是否反相的。设置为 RISING 表示不反相,FALLING 表示反相。此成员与编
码器的计数触发边沿无关,只用来匹配编码器和电机的方向,当设定的电机正方向与编码器正方
向不一致时不必更改硬件连接,直接在程序中修改 IC1Polarity 即可。
接下来是成员 IC1Selection,这个成员用于选择输入通道,IC1 可以是 TI1 输入的 TI1FP1,也
可以是从 TI2 输入的 TI2FP1,我们这里选择直连(DIRECTTI),即 TI1FP1 映射到 IC1,在编
码器模式下这个成员只能设置为 DIRECTTI,其他可选值都是不起作用的。
最后是成员 IC1Prescaler 和成员 IC1Filter,我们需要对编码器的每个脉冲信号都进行捕获,所
以设置成不分频。根据 STM32 编码器接口 2 倍频或 4 倍频的原理,接口在倍频采样的过程中也
会对信号抖动进行补偿,所以输入滤波器也很少会用到。
配置完编码器接口结构体后清零计数器,然后开启定时器的更新事件中断,并把更新事件中断源
配置为定时器溢出,也就是仅当定时器溢出时才触发更新事件中断。然后配置定时器的中断优先
级并开启中断,最后启动编码器接口

在写回调函数

/**
  * @brief  定时器更新事件回调函数
  * @param  无
  * @retval 无
  */
/* 定时器溢出次数 */
__IO int16_t Encoder_Overflow_Count = 0;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  /* 判断当前计数器计数方向 */
  if(__HAL_TIM_IS_TIM_COUNTING_DOWN(&htim3))
    /* 下溢 */
    Encoder_Overflow_Count--;
  else
    /* 上溢 */
    Encoder_Overflow_Count++;
}

在 TIM_Encoder_Init 函 数 中 我 们 配 置 了 仅 当 定 时 器 计 数 溢 出 时 才 触 发 更 新 事 件 中
断, 然 后 在 中 断 回 调 函 数 中 记 录 定 时 器 溢 出 了 多 少 次。 首 先 定 义 一 个 全 局 变 量 Encoder_Overflow_Count,用来记录计数器的溢出次数。在定时器更新事件中断回调函数中,使
用 __HAL_TIM_IS_TIM_COUNTING_DOWN 函数判断当前的计数方向,是向上计数还是
向下计数,如果向下计数,Encoder_Overflow_Count 减 1,反之则加 1。这样在计算电机转速
和位置的时候就可以把溢出次数也参与在内。

后在写HAL_SYSTICK_Callback();因为我们需要它中断1ms计算一次

void SysTick_Handler(void)
{
  /* USER CODE BEGIN SysTick_IRQn 0 */

  /* USER CODE END SysTick_IRQn 0 */
  HAL_IncTick();
  /* USER CODE BEGIN SysTick_IRQn 1 */
  HAL_SYSTICK_Callback();
  /* USER CODE END SysTick_IRQn 1 */
}

这里使用m法计算

/**
  * @brief  SysTick中断回调函数
  * @param  无
  * @retval 无
  */
void HAL_SYSTICK_Callback(void)
{
  static uint16_t i = 0;

  i++;
  if(i == 100)/* 100ms计算一次 */
  {
    /* 电机旋转方向 = 计数器计数方向 */
    Motor_Direction = __HAL_TIM_IS_TIM_COUNTING_DOWN(&htim3);
    
    /* 当前时刻总计数值 = 计数器值 + 计数溢出次数 * ENCODER_TIM_PERIOD  */
    Capture_Count =__HAL_TIM_GET_COUNTER(&htim3) + (Encoder_Overflow_Count * 65535);
    
    /* 转轴转速 = 单位时间内的计数值 / 编码器总分辨率=(编码器物理分辨率/4) * 时间系数  */
    Shaft_Speed = (float)(Capture_Count - Last_Count) / (16/4) * 10 ;

    printf("电机方向:%d\r\n", Motor_Direction);
    printf("单位时间内有效计数值:%d\r\n", Capture_Count - Last_Count);/* 单位时间计数值 = 当前时刻总计数值 - 上一时刻总计数值 */
    printf("电机转轴处转速:%.2f 转/秒 \r\n", Shaft_Speed);
    printf("电机输出轴转速:%.2f 转/秒 \r\n", Shaft_Speed/30);/* 输出轴转速 = 转轴转速 / 减速比 */
    
    /* 记录当前总计数值,供下一时刻计算使用 */
    Last_Count = Capture_Count;
    i = 0;
  }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值