STM32定时器编码器模式实现直流有刷电机测速(HAL库)

这篇具有很好参考价值的文章主要介绍了STM32定时器编码器模式实现直流有刷电机测速(HAL库)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

最近在做一个单片机大作业,要用到直流有刷,在这里把学习编码器的知识记录一下,学习参考资料:

正点原子DMF407电机控制专题教程_V1.0

编码器测速原理

我所使用的编码器是市面上常见的磁电增量式编码器,其有AB两相,用于输出电机转动时的脉冲数,AB两相的先后顺序决定了电机的转动方向

STM32定时器编码器模式实现直流有刷电机测速(HAL库)

这其实就是单片机的外部计数器模式,51中也带有同样的功能

信号从通道被采样后的处理过程如下

STM32定时器编码器模式实现直流有刷电机测速(HAL库)

编码器的计数接口是利用脉冲的边沿来计数的,我们知道AB两相都有脉冲且相位差为90度,那么一次检测最多可以得到四个边沿,此时我们可以通过配置计数的方式来实现不同的边沿计数

STM32定时器编码器模式实现直流有刷电机测速(HAL库)

由图可以看出,总共有三种计数方式供我们选择,不同的模式对应了不同的计数形式,这里我选用的是第三种,因此会产生四个边沿,相当于对信号进行了四倍频,即一个脉冲信号会计数4次,在计算时要注意

寄存器部分

在编码过程中有几个重要的寄存器要简单介绍一下

TIMx_CR1控制寄存器

STM32定时器编码器模式实现直流有刷电机测速(HAL库)

 我们要关注这里的DIR位,通过判断DIR来判断计数器所处的模式是递增还是递减,流程大致为:配置好定时器的装载值为65536,不分频,那么每一次接收到65536个脉冲后定时器就会溢出进入定时器中断,此时通过判断DIR是0还是1来判断是正转还是反转,进而将得到的脉冲数累积到总脉冲数中进行速度计算

同时还要注意 CEN位,该位用于使能计数器的工作,也就是相当于选择模式,对应硬件就是内部的开关,用于判断是外部定时器模式还是内部定时器模式,当该位置1为外部定时器模式

TIMx_CCMR1捕获/比较模式寄存器1

STM32定时器编码器模式实现直流有刷电机测速(HAL库)

在这里IC1F为滤波器,其实现方法为通过配置寄存器来设定滤波系数,例如在一个采样周期下,当N=2时代表要两个相同的事件(比如两个相同电位的高电平信号)才能视为一个有效边沿,这个过程基于数字滤波器实现,寄存器配置如下

STM32定时器编码器模式实现直流有刷电机测速(HAL库)

IC1PSC是输入捕获预分频器,和上述原理类似,这里我和教程一样,选择一个边沿就触发一次计数

CC1S用于配置定时器通道,这里不做多要求,IC1映射到TI1就可以了

TIMx_SMCR从模式控制器

STM32定时器编码器模式实现直流有刷电机测速(HAL库)

 SMS代表的三位用于配置编码器模式123,具体对应关系如下

STM32定时器编码器模式实现直流有刷电机测速(HAL库)

 至此要用到的所有寄存器就介绍完了,接下来我们来进行CUBEMX工程的创建

硬件信息

主控芯片我选择的是STM32F103C8T6,电机用的是常见的自带编码器的直流有刷减速电机,编码器线数为11,电机驱动选用L298N,同时用OLED屏幕显示电机转速信息

工程创建

首先配置时钟树,直接拉满,再初始化几个IO口用于驱动电机

STM32定时器编码器模式实现直流有刷电机测速(HAL库)

STM32定时器编码器模式实现直流有刷电机测速(HAL库)

STM32定时器编码器模式实现直流有刷电机测速(HAL库)

STM32定时器编码器模式实现直流有刷电机测速(HAL库)

STM32定时器编码器模式实现直流有刷电机测速(HAL库)

STM32定时器编码器模式实现直流有刷电机测速(HAL库)

 剩下的流程就是选择对应的IDE生成工程即可

代码部分

初始化外设

/* USER CODE BEGIN 2 */
  run_left_motor(50,1); //左轮电机启动
  OLED_Init();  //OLED初始化
  OLED_Clear();
  HAL_TIM_Encoder_Start(&htim1, TIM_CHANNEL_ALL); //开启定时器编码器通道
  HAL_TIM_Base_Start_IT(&htim4);  //开启定时中断通道
  /* USER CODE END 2 */

 初始化电机以及编码器

#define ROTO_RATIO 44 //编码器线数11*分频系数4
#define REDUTATION_RATIO 30 //电机减速比30

//编码器结构体
typedef struct
{
    int encode_old;
    int encode_new;
    float speed;
}ENCODE_TypeDef;
//电机结构体
typedef  struct
{
    float speed;
}Motor_TypeDef;

extern ENCODE_TypeDef g_encode_left;
extern Motor_TypeDef g_motor_left;

 电机转动

void run_left_motor(uint8_t speed,unsigned char dir)
{
  uint32_t arr;
  HAL_TIM_Encoder_Start(&htim1, TIM_CHANNEL_ALL);
  if(dir == 1)
  {
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_SET);
  }
  else
  {
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET);
  }
  HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_1);
  arr = __HAL_TIM_GET_AUTORELOAD(&htim2);
  __HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_1,(1.0*speed/100)*arr);
}

电机速度计算

//encoder_now为定时器编码器模式下的计数值,ms代表每隔多少ms进入一次计算公式
void left_speed_compute(int32_t encode_now,uint8_t ms)
{
  uint8_t i=0,j=0;
  float temp = 0.0; //用于后续冒泡排序
  static uint8_t sp_count=0,k=0;  //用于判断隔多长时间进一次计算,静态变量,不会随着函数调用被刷新
  static float speed_array[10]={0.0}; //上面的k为数组的索引值
  if(sp_count == ms)  //当调用函数次数超过50次即每间隔50ms进入一次计数
  {
    g_encode_left.encode_new = encode_now;  //编码器值更新
    g_encode_left.speed = (g_encode_left.encode_new - g_encode_left.encode_old);  //脉冲变化数计算
    //通过脉冲计算速度,公式:(50ms内记录的脉冲数/50ms*60)/减速比/编码器线数/分频系数 = 每分钟的脉冲数/已知常量
    speed_array[k++] = (float)(g_encode_left.speed*((1000/ms)*60.0)/(REDUTATION_RATIO*ROTO_RATIO));
    g_encode_left.encode_old = g_encode_left.encode_new;  //更新编码器计数值
    //冒泡排序法
    if(k==10)
    {
      for(i=10;i>=1;i--)
      {
        for(j=0;j<(i-1);j++) {
          if (speed_array[j] > speed_array[j + 1]) {
            temp = speed_array[j];
            speed_array[j] = speed_array[j + 1];
            speed_array[j + 1] = temp;
          }
        }
      }
      temp = 0.0; //初始化temp
      //去除两边高低数据
      for(i=2;i<8;i++)
      {
        temp += speed_array[i];
      }
      temp = (float)(temp/6);
      /*
       * 一阶低通滤波 Y(n)= qX(n) + (1-q)Y(n-1)
       * 其中 X(n)为本次采样值;Y(n-1)为上次滤波输出值;Y(n)为本次滤波输出值,
       * q 为滤波系数
      */
      g_motor_left.speed = (float)((g_motor_left.speed)*(float)0.52)+((float)0.48*temp);
      //显示当前速度
      unsigned char Tx_Buf[20];
      sprintf((char *)Tx_Buf,"Left: %.2f",g_motor_left.speed);
      OLED_ShowString(1,2,Tx_Buf,5);
      k = 0;
    }
    sp_count = 0;
  }
  sp_count++;
}

溢出计数统计以及调用计算

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  //判断编码器的溢出方向
  if(htim->Instance == TIM1)
  {
    if(__HAL_TIM_IS_TIM_COUNTING_DOWN(&htim1))
    {
      g_tim1_encode_count--;
    }
    else
    {
      g_tim1_encode_count++;
    }
  }
  //每间隔1ms更新一次脉冲数
  if(htim->Instance == TIM4)
  {
    int Left_encode_now = gtim_get_encode();
    left_speed_compute(Left_encode_now,50);
  }
}
//更新脉冲数
int gtim_get_encode(void)
{
  return ( int32_t )__HAL_TIM_GET_COUNTER(&htim1) + g_tim1_encode_count * 65536;       /* 当前计数值+之前累计编码器的值=总的编码器值 */
}

实验现象验证

转动时转速为20r/min 

STM32定时器编码器模式实现直流有刷电机测速(HAL库)

不转动时转速为0

STM32定时器编码器模式实现直流有刷电机测速(HAL库)文章来源地址https://www.toymoban.com/news/detail-423297.html

到了这里,关于STM32定时器编码器模式实现直流有刷电机测速(HAL库)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 初出茅庐的小李博客之STM32CubeMx配置定时器的编码器模式

    上次文章写了编码器是如何工作的,今天就来用STM32F103C8T6的TIM3的通道1跟通道2编写一个编码器识别程序。 话不多说,上教程! 选择外部高速时钟源HSE 选择中断模式触发下降沿有效 默认是上拉输入 添加用户标签为SWITCH 使能NVIC配置 选择编码器模式 分频值设置为2-1 计数值设

    2024年02月12日
    浏览(33)
  • STM32一个定时器同时配置编码器和PWM输出时PWM无法正常输出的原因【避坑】

             最近我在做写代码的时候,因为定时器的资源紧张,就在一个定时器上同时配置了编码器和PWM,发现PWM无法正常输出,查了很久发现网上资料不多,在仔细翻阅手册研究后才发现是 时钟信号 的问题。 具体原因 定时器在设置编码器模式后,计数的时钟源就会变成编

    2024年02月04日
    浏览(44)
  • STM32(HAL)--使用定时器TIM的Encoder Mode来读取旋钮编码器的脉冲数

    目录 一 旋钮编码器相关知识 二 STM32CubeMx配置 三 程序编写 3.1 相关函数介绍 3.2 程序编写 四 实验结果 旋转编码器是一种位置传感器,输出脉冲信号可以用来确定编码器的旋转角度和旋转方向。 编码器中有两个开关,当旋钮旋转后,开关会依次导通,开关结构图如下图所示

    2024年02月15日
    浏览(43)
  • (四) timer+pit(定时器中断)+encoder(编码器)-逐飞TC264库学习(对比STM32 HAL库)

    PIT , 是programmable interval timer 可编程间隔定时器 DSC中的器件 的缩写,所以就是定时器中断,有点像32里的timer(TIMx) 目前看来一共能用通道的有四个 typedef enum // 枚举通道号 {     CCU60_CH0,     CCU60_CH1,     CCU61_CH0,     CCU61_CH1, }pit_index_enum; 因为涉及到中断,为方便设定中断优

    2024年03月15日
    浏览(63)
  • 【嵌入式】STM32计时器编码器接口模式使用

    使用STM32调试电机或传感器时经常会使用到计数器的编码器接口模式,本文主要记录该模式的固件库配置方法,并给出使用该模式获取光栅测距值的实例。 硬件: STM32F103C8T6 光栅测距传感器 编码器接口模式为STM32计时器的一种特殊使用模式,该模式下可对编码器输出的脉冲信

    2024年02月20日
    浏览(39)
  • STM32编码器模式(带方向/正交编码)

    看前说明 :这里重点介绍的时STM32的定时器编码器模式,是根据STMF10x参考手册,如果有使用过编码器或编码器不一样的可以直接跳过前面的编码器介绍,直接看理论分析与程序部分。 这里需要注意的参数 输出脉冲线数:1024线: 编码器每旋转一周输出的脉冲的个数 ,这个数

    2023年04月24日
    浏览(47)
  • STM32 ABZ编码器模式详解

            本文旨在记录和说明STM32CubeIde中ABZ编码器的配置。本人作为STM32新手,在使用STM32时,太多的意义不明的配置项让我摸不着头脑,查阅资料并在这里记录,如果有不对的,欢迎各位大佬指正。         本文硬件使用ST官方提供的NUCLEO-G474RE+X-NUCLEO-IHM16M1,记录ABZ的配

    2024年02月19日
    浏览(55)
  • 【STM32】定时器PWM模式详解

    PWM模式: PWM模式1,向上计数时,PWM信号从 有效电平 变为 无效电平 PWM模式2,向上计数时,PWM信号从 无效电平 变为 有效电平 PWM极性: 极性为高时, 高电平为有效电平 ,低电平为无效电平 极性为低时, 低电平为有效电平 ,高电平为无效电平 中心对齐模式(先向上再向下

    2024年02月09日
    浏览(33)
  • STM32——高级定时器输出比较模式实验

    1,配置定时器基础工作参数 HAL_TIM_OC_Init() 2,定时器PWM输出MSP初始化 HAL_TIM_OC_MspInit() 配置NVIC、CLOCK、GPIO等 3,配置PWM模式/比较值等 HAL_TIM_OC_ConfigChannel() 4,使能通道预装载 __HAL_TIM_ENABLE_OCxPRELOAD() 5,使能输出、主输出、计数器 HAL_TIM_OC_Start() 6,修改捕获/比较寄存器的值 _HAL

    2024年02月02日
    浏览(43)
  • STM32 CubeMX 定时器(普通模式和PWM模式)

    定时器打开与关闭 开启PWM通道 设置PWM,占空比 方式1 方式2 值越大灯越亮

    2024年02月15日
    浏览(28)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包