【STM32+HAL库】---- 通用定时器输入捕获PWM信号

硬件开发板:STM32G0B1RET6
软件平台:cubemax+keil+VScode

1 新建cubemax工程

1.1 配置系统时钟RCC

image

1.2 配置定时器

1.2.1 配置输入捕获

选择通用定时器TIM2-Channel 1为输入捕获引脚,对应IO口是PA0,时钟源选择内部时钟源Internal clock,工作模式选择直接输入捕获Input Capture direct mode,预分频系数选择63,定时器向上计数,重装载值选择最大值,减少溢出次数;输入捕获选择上升沿直接触发。
image

使能中断
image

1.2.2 配置PWM输出

选择通用定时器TIM3-Channel 1为PWM输出引脚,对应IO口是PA6,时钟源选择内部时钟源Internal clock,工作模式选择PWM输出PWM Generation CH1,预分频系数选择63,定时器向上计数,重装载值选择999,此时对应产生的PWM信号周期是\(T=\frac{64*1000}{64M}=1ms;频率为1KHz\),占空比设置为100,即高电平所占总周期的10%
image

1.3 配置串口

image

2 代码

2.1 printf重定向

usart.h中添加头文件和函数声明

# include "stdio.h"

int fgetc(FILE *f);
int fputc(int ch,FILE *f);

usart.c中重定向

//重定向scanf
int fgetc(FILE *f)
{
  uint8_t ch=0;
  HAL_UART_Receive(&huart2,&ch,1,0xffff);
  return ch;
}
 
//重定向printf
int fputc(int ch,FILE *f)
{
  uint8_t temp[1]={ch};
  HAL_UART_Transmit(&huart2,temp,1,2);
  return ch;
}

由于该实验并未使用到scanf函数,可不必重定向scanf

2.2 定义变量

uint32_t capture_value[3];    /*定义数组变量,存放捕获到的值*/
uint32_t diff_value1;    /*计数差值*/
uint32_t diff_value2;    /*计数差值*/

uint8_t capture_state=0;    /*捕获状态:0表示未开始捕获;1表示完成一次捕获;2表示完成两次捕获*/
uint8_t capture_flag=0;    /*捕获标志位:0表示未完成,1表示已完成*/

2.3 中断回调函数

/* USER CODE BEGIN 4 */
//回调函数
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
  if (htim==&htim2)
  {
    switch (capture_state)
    {
    case 0:
      {
        capture_value[0]=HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1);    /*读取捕获开始时间*/
        __HAL_TIM_SET_CAPTUREPOLARITY(htim,TIM_CHANNEL_1,TIM_INPUTCHANNELPOLARITY_FALLING);    /*切换为下降沿捕获*/
        capture_state=1;    /*标志完成第一次捕获*/
      }
      break;

    case 1:
    {
      capture_value[1]=HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1);    /*读取第二次捕获时间*/
      __HAL_TIM_SET_CAPTUREPOLARITY(htim,TIM_CHANNEL_1,TIM_INPUTCHANNELPOLARITY_RISING);    /*切换为上升沿捕获*/
      capture_state=2;    /*标志完成第二次捕获*/
    }
    break;

    case 2:
    {
      capture_value[2]=HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1);    /*读取捕获结束时间*/
      HAL_TIM_IC_Stop_IT(htim,TIM_CHANNEL_1);    /*停止捕获*/
      capture_state=0;    /*标志完成第三次捕获,重新置0,准备下一轮捕获*/
      capture_flag=1;    /*标志捕获完成*/
    }
    break;
    
    default:
      printf("running error!\n");
      break;
    }
  }
  
}
/* USER CODE END 4 */

2.4 main函数

int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_TIM2_Init();
  MX_TIM3_Init();
  MX_USART2_UART_Init();
  /* USER CODE BEGIN 2 */
  HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_1);    /*开启PWM输出*/
  HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_1);    /*开启输入捕获*/
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    if (capture_flag==1)    /* 捕获完成 */
    {
      printf("\n******capture start******\n");
      if (capture_value[2] >= capture_value[0])    /* 计时没有溢出 */
      {
        diff_value1=capture_value[2]-capture_value[0];    /* 取差值 */
      }
      else    /* 计时有溢出 */
      {
        diff_value1=(0xffffffff+1)+capture_value[2]-capture_value[0];    /* 取差值 */
      }
      printf("周期:%.2fms\n",diff_value1/1000.0);    /*周期=差值*单次计数时间*/
      printf("频率:%.2fKHz\n",1000.0/diff_value1);

      if (capture_value[1] >= capture_value[0])    /* 计时没有溢出 */
      {
        diff_value2=capture_value[1]-capture_value[0];    /* 取差值 */
      }
      else    /* 计时有溢出 */
      {
        diff_value2=(0xffffffff+1)+capture_value[1]-capture_value[0];    /* 取差值 */
      }
      printf("高电平:%.2fms\n",diff_value2/1000.0);    /*高电平时间=差值*单次计数时间*/
      printf("占空比:%d%%\n",diff_value2*100/diff_value1);

      printf("******capture over******\n");

      capture_flag=0;    /*清除标志位,准备下一轮捕获*/
      HAL_Delay(1000);
      HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_1);    /*开启下一轮捕获*/
    }
    
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

周期计算公式:\(T=计数差值*单次计数时间=计数差值*\frac{1}{计数频率}=计数差值*\frac{1}{时钟频率/预分频系数}=计数差值*\frac{预分频系数}{时钟频率}\)
比如该实验中,时钟频率为64MHz,预分频系数为63(64分频),得到的计数频率为1MHz,即单次计数时间为1us

3 实验现象

用杜邦线连接PA0PA6引脚,打开串口,观察打印情况
image

posted @ 2024-01-16 00:14  晚风也温柔  阅读(465)  评论(0编辑  收藏  举报