这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » STM32 » NUCLEO-U083RC学习历程16-定时器的输入捕获功能监测编码器

共9条 1/1 1 跳转至

NUCLEO-U083RC学习历程16-定时器的输入捕获功能监测编码器

助工
2024-12-25 20:29:59     打赏

今天和大家分享一下,定时器的输入捕获功能,用来检测编码器行走的圈数。

一:编码器知识:

编码器一般是正交编码器或者是拉线式编码器,通过两个信号线(A、B)的输出一定频率的脉冲输出来进行数据输出,编码器在转动时,利用2000r/rpm,意思就是编码器每转动一圈,会发出2000个脉冲,意味着编码器一个输出脉冲信号就意味着一个固定角度,单片机在通过读取单位时间脉冲信号的数量,通过定时器的执行时间就可以得到编码器行走的速度,间接的我们得到加载机构或者电机实际行走的距离。

编码器硬件介绍:

VCC :供电正极  一般是DC 5-24V

GND:供电负极 

A:脉冲输出A相

B:脉冲输出B相

Z:脉冲输出Z相

其中:编码器在工作时,A相、相输出的脉冲信号总是相差90°相位差。反之如果两个信号相位差为90度,则这两个信号称为正交。由于两个信号相差90度,因此可以根据两个信号哪个先哪个后来判断方向、并且可以根据AB相脉冲信号数量测得速度,位移等;

正转的时候信号线A先输出信号,信号线B后输出  A相超前B相90度  证明是正转

反转的时候信号线B先输出信号,信号线A后输出 B相超前A相90度 证明是反转

二:STM32定时器输入捕获知识:

1.png

输入捕获总结工作过程:通过检测TIMx_CHx上的边沿信号,在边沿信号发生跳变(比如上升沿/下降沿)的时候,将当前定时器的值(TIMx_CNT)存放到对应的捕获/比较寄存器(TIMx_CCRx)里面,完成一次捕获。我们只需要在其他定时器回调函数中,读取该定时器的计数值就可以,同时每次读取时将数据清零,否则会导致数据的溢出;

STM32的编码器模式共有三种:仅在TL1计数(A相),仅在TL2计数(B相),在TL1和TL2都计数(A相和B相都计数))

在使用三种定时器模式时的注意事项如下:

1.需要增加测量的精度时,可以采用4倍频方式,即分别在A、B相波形的上升沿和下降沿计数,分辨率可以提高4倍,

2.如果只是测速,不要求方向,那么只需要用单片机随意选择一个信号线就行了,,然后定时器边沿触发,检测脉冲计数即可

3.一般是定时器的通道1和2才能作为编码器输入口,对应编码器输出的两相。

4.GPIO配置为配置为上拉输入模式

5.一个定时器做一种工作,如果你配置了编码器模式,那么剩下的通道就不能配置其他模式  H! d7 N. c) u

6.两相计数模式下,  读出来数需要/4          一个脉冲信号对应四次计数 

三:STM32cube MX 软件配置

2.png

如上图所示:说明如何在编码器模式下配置 TIM1 外设以确定旋转方向。

为了模拟正交编码器,TIM3 配置为切换模式,以在 10KHz 的(PA6 和 PB5)上生成 2 个正交信号。每 1 秒,信号会改变相位 (+90°/-90°) 以模拟向前/向后旋转。

TIM1 在编码器模式接口中配置,依靠 TI1 和 TI2。计数方向对应于所连接传感器的旋转方向(由 TIM3 信号模拟)。可以通过在 Live Watch 窗口中放置 “uwDirection” 变量来监控旋转方向。当 uwDirection = 0 时,根据“计数方向与编码器信号”表,旋转方向为“向前”。当 uwDirection = 1 时,根据“计数方向与编码器信号”表,旋转方向为“向后”。同时在程序中读取定时器1的内部寄存器的计数值。

程序编写步骤:

① 初始化定时器和通道对应IO的时钟。

② 初始化IO口,模式为输入:

③初始化定时器ARR,PSC

④初始化输入捕获通道

⑤如果要开启捕获中断

⑥使能定时器

⑦编写中断服务函数:

四:部分代码分享:

4.1输入捕获定时器1 初始化部分:

/**
  * @brief TIM1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_TIM1_Init(void)
{

  /* USER CODE BEGIN TIM1_Init 0 */

  /* USER CODE END TIM1_Init 0 */

  TIM_Encoder_InitTypeDef sConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};

  /* USER CODE BEGIN TIM1_Init 1 */

  /* USER CODE END TIM1_Init 1 */
  htim1.Instance = TIM1;
  htim1.Init.Prescaler = 0;
  htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim1.Init.Period = 65535;
  htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim1.Init.RepetitionCounter = 0;
  htim1.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(&htim1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM1_Init 2 */

  /* USER CODE END TIM1_Init 2 */

}

4.2 定时器3 输出PWM配置参数:

static void MX_TIM3_Init(void)
{

  /* USER CODE BEGIN TIM3_Init 0 */

  /* USER CODE END TIM3_Init 0 */

  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};

  /* USER CODE BEGIN TIM3_Init 1 */

  /* USER CODE END TIM3_Init 1 */
  htim3.Instance = TIM3;
  htim3.Init.Prescaler = 0;
  htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim3.Init.Period = EMU_PERIOD;
  htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_OC_Init(&htim3) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_TOGGLE;
  sConfigOC.Pulse = PULSE1_VALUE;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_LOW;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  if (HAL_TIM_OC_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.Pulse = PULSE2_VALUE;
  if (HAL_TIM_OC_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM3_Init 2 */

  /* USER CODE END TIM3_Init 2 */
  HAL_TIM_MspPostInit(&htim3);

}

4.3 主程序如下:

  /* Start the encoder interface */
  HAL_TIM_Encoder_Start(&htim1, TIM_CHANNEL_ALL);

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {

   /* Step 1: */
    /* Emulate a Forward direction */
    Emulate_Forward_Direction(&htim3);
    /* Insert 1s delay */
    HAL_Delay(1000);
    /* Get the current direction */
    uwDirection = __HAL_TIM_DIRECTION_STATUS(&htim1);
    /* Step 2: */
    /* Emulate a Backward direction */
    Emulate_Backward_Direction(&htim3);
    /* Insert 1s delay */
    HAL_Delay(1000);
    /* Get the current direction */
    uwDirection = __HAL_TIM_DIRECTION_STATUS(&htim1);

		temp = __HAL_TIM_GET_COUNTER(&htim1);
		 __HAL_TIM_SET_COUNTER(&htim1,0);


    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */

  }
  /* USER CODE END 3 */
}

实物测试图如下:

3.png

如上图所示:在读取到定时器1中的计数值时,我们需要将定时器中的计数值清零,否则数据异常溢出时候,会导致数据不准确。




关键词: NUCLEO-U083RC     定时器     输入捕获功能    

专家
2024-12-25 22:14:43     打赏
2楼

感谢分享


专家
2024-12-25 22:18:17     打赏
3楼

感谢分享


工程师
2024-12-25 22:21:00     打赏
4楼

学习下


专家
2024-12-25 22:21:44     打赏
5楼

感谢分享


专家
2024-12-26 06:27:28     打赏
6楼

看看


高工
2024-12-26 07:27:47     打赏
7楼

感谢分享


专家
2024-12-26 08:01:47     打赏
8楼

感谢分享


院士
2024-12-26 10:08:29     打赏
9楼

原来编码器的检测对应Timer外设还有引脚的定义啊


共9条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]