STM32笔记:PWM输入模式下脉宽和占空比测量原理详解

一、PWM 输入模式测量脉宽

1.1 测量脉宽简介

在测量占空比之前,我们先一步一步来,先让 STM32 可以测量脉宽。

TIM3_CH1(tim3 定时器通道 1)捕获模式测量脉宽步骤如下:

1.输入捕获到 PWM 上升沿触发

2.发送中断,通知用户此时被触发,用户获得当前计数器值

3.计数器清零,然后继续计数…

让 STM32 芯片一直重复这三步即可不断地测量出当前的 PWM 脉宽。

1.2 测量脉宽原理

首先我们可以使用 PWM 的复位 Reset 模式,它复合我们之前所要求的功能。具有捕捉上升沿和计数器复位的能力。

如果我们使用 TIM_CH1,可以产生分别是TI1FP1 与TI1FP2 这一对信号。他们的功能是分别是捕捉上升沿和下降沿。

其原理是:

二者都是来自同一 TI1 输入通道,经过输入滤波和边沿检测器后所产生的具有相同特征的信号,然后映射到不同的输入捕捉通道,本质上还是同一路信号。

TI1FP1,是来自于通道TI1,经过滤波器后将接到捕捉比较通道 IC1;

TI1FP2,是来自于通道TI1,经过滤波器后将接到捕捉比较通道 IC2;

由这张图得知,所谓 IC1 就是上升沿信号,TI1FP1会捕获到。IC2 是下降沿信号,TI1FP2 会捕捉到。

1.3 cubeMX 配置

 

①和②在上文已经详细介绍,不再赘述

③我们使用内部时钟

④重点来了!我们捕捉的通道是 TIM_CH1 如果我们走红色这条线,即可用后面的 TI1FP1 捕捉到上升沿。使用直接捕获模式(input capture direct mode)即可。如果需要捕获 TI1FP2 的下降沿则需要使用 重映射输入捕获(input capture direct from remap)。

 

⑤配置分频系数,我的系统时钟是 80mhz,分频 80 则为 1mhz,所以计数速度是 每秒1000000次。

⑥计数器最大值为 65535,所以测量最大的脉宽则为 65536/1000000 = 0.065536 秒。取倒数大约为 15.25hz 所以请不要测量超过这个值的脉宽,否则就会溢出清零,导致测量不准。

⑦默认值,配置为上升沿计数。

1.3 cubeMX 生成的代码解析

/*STM32cubeMX 生成的 TIM3 初始化代码:*/
/* TIM3 init function */
void PWM_TIM3_CHANNEL_1_Init(void)
{

  /* USER CODE BEGIN TIM3_Init 0 */

  /* USER CODE END TIM3_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_SlaveConfigTypeDef sSlaveConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_IC_InitTypeDef sConfigIC = {0};

  /* USER CODE BEGIN TIM3_Init 1 */

  /* USER CODE END TIM3_Init 1 */
  htim3.Instance = TIM3;		//指定需要配置的定时器
  htim3.Init.Prescaler = 79;	//定时器的预分频系数
  htim3.Init.CounterMode = TIM_COUNTERMODE_UP;		
  htim3.Init.Period = 65535;	//定时器计数周期值
  htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;	//定时器分频因子
  htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;	//计数达到指定值后,定时器是否自动重装载计数值
  if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;	//使用STM32单片机内部时钟
  if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_IC_Init(&htim3) != HAL_OK)	//进行初始化
  {
    Error_Handler();
  }
  sSlaveConfig.SlaveMode = TIM_SLAVEMODE_RESET;	//设置定时器模式 复位模式
  sSlaveConfig.InputTrigger = TIM_TS_TI1FP1;	//使用TI1FP1触发
  sSlaveConfig.TriggerPolarity = TIM_INPUTCHANNELPOLARITY_RISING; //上升沿触发
  sSlaveConfig.TriggerFilter = 0;//滤波
  if (HAL_TIM_SlaveConfigSynchro(&htim3, &sSlaveConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
  sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
  sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
  sConfigIC.ICFilter = 0;
  if (HAL_TIM_IC_ConfigChannel(&htim3, &sConfigIC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM3_Init 2 */

  /* USER CODE END TIM3_Init 2 */

}

输入GPIO口的配置:

大致是设置复用端口配置、时钟相关配置。比较简单就不全都注释了。

让我困惑的是为什么这个捕获 PWM 的引脚被配置成 GPIO_MODE_AF_PP 复用推挽输出,难道不应该是输入吗?

/*STM32cubeMX 生成的 TIM3 初始化代码:*/
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(tim_baseHandle->Instance==TIM3)
  {
  /* USER CODE BEGIN TIM3_MspInit 0 */

  /* USER CODE END TIM3_MspInit 0 */
    /* TIM3 clock enable */
    __HAL_RCC_TIM3_CLK_ENABLE();

    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**TIM3 GPIO Configuration
    PB4     ------> TIM3_CH1
    */
    GPIO_InitStruct.Pin = GPIO_PIN_4;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF2_TIM3;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    /* TIM3 interrupt Init */
    HAL_NVIC_SetPriority(TIM3_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(TIM3_IRQn);
  /* USER CODE BEGIN TIM3_MspInit 1 */

  /* USER CODE END TIM3_MspInit 1 */
  }
}

1.4 需要我们写的获取值的代码

经过下降沿后会自动触发中断,在回调函数中判断下是 TIM3通道1发出的,就可以调用HAL_TIM_ReadCapturedValue() 取值了。

HAL_TIM_Base_Start(&htim3);
/* 启动定时器通道输入捕获并开启中断 */
HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_1);	

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
	
	if(htim->Instance==TIM3)
	{
				if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
			{
				PWM1_T_Count =  HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1)+1;
			}
	}

}

二、测量占空比

2.1 测量占空比分析

基于之前测量脉宽的逻辑,如果我们把测量上升沿配置成主模式,测量下降沿配置成从模式。STM32将会是这样的逻辑:

1.在上升沿复位两个计数器

2.下降沿暂停下降沿计数器

3.再次上升沿复位两个计数器

不断重复….

在之前测量脉宽我们使用了 TI1FP1 线路测量上升沿,不过测量下降沿则需要 TI1FP2 辅助,将其信号类似“转发”到 TIM_CH2 线路中 (下图红色线路)。也就是说,当我们在 TIM_CH1 同时捕捉上升沿和下降沿,就会占用 TIM_CH2 线路。

2.2 cubeMX 配置

基于之前的配置,我们需要将①通道2配置为从模式;在②中,将这个配置为下降沿触发。

2.3 需要我们写的代码

节约篇幅不再解释 cubeMX 生成的代码,直接贴出我们需要写的代码:

//输入捕获中断回调函数
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
	
	  if(htim->Instance==TIM3)
  {
				if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
			{
				PWM1_T_Count =  HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1)+1; //捕获脉宽
				PWM1_Duty = (float)PWM1_D_Count/PWM1_T_Count; //捕获占空比
			}
				else if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
			{
				PWM1_D_Count =  HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_2)+1;//捕获下降沿
			}					
	
	}

}

物联沃分享整理
物联沃-IOTWORD物联网 » STM32笔记:PWM输入模式下脉宽和占空比测量原理详解

发表评论