定时器&PWM应用编程

一、 任务

  1. 使用STM32F103的 Tim2~Tim5其一定时器的某一个通道pin(与GPIOx管脚复用,见下图),连接一个LED,用定时器计数方式,控制LED以2s的频率周期性地亮-灭。

  2. 接上,采用定时器pwm模式,让 LED 以呼吸灯方式渐亮渐灭,周期为1~2秒,自己调整到一个满意效果。使用Keil虚拟示波器,观察 pwm输出波形。

二、 原理

STM32-PWM介绍
STM32-PWM是STM32系列微控制器上的一种重要外设,用于生成脉宽调制(PWM)信号。脉宽调制技术在许多应用中都起着关键作用,如电机控制、LED亮度调节、音频处理等。STM32PWM模块提供了灵活的配置选项和高精度的PWM输出能力。

PWM工作原理
PWM是一种周期性的方波信号,通过调整方波的高电平时间(占空比)来控制输出信号的特性。PWM信号的频率和占空比可以根据应用需求进行配置。在STM32PWM模块中,通过设置定时器的计数周期和比较值,可以实现不同频率和占空比的PWM输出。
在这里插入图片描述
STM32PWM模块
STM32PWM模块通常由一个或多个通用定时器(TIM)和相关的GPIO引脚组成。通用定时器提供了灵活的PWM配置选项,可以根据需要进行定时器和GPIO引脚的映射、预分频设置、计数周期和比较值的设定等。

PWM参数配置
为了配置和控制STM32PWM模块,我们可以使用相应的库函数或直接操作寄存器。以下是一些常用的PWM参数和配置选项:

  • 频率设置:通过设置定时器的计数周期来控制PWM信号的频率。频率 = 定时器时钟频率 / (预分频系数 * 计数周期)
  • 占空比设置:通过设置比较值来控制PWM信号的占空比。占空比 = (比较值 / 计数周期) * 100%
  • 极性设置:可以选择正极性或反极性,以控制PWM信号的电平极性。
  • 中断使能:可以选择是否使能PWM定时器的中断功能,用于触发中断任务。

在这里插入图片描述

三、 实操

1. LED以2s的频率周期性地亮-灭

Ⅰ 创建工程

选择一个载有TIM2的管脚,此处选择A6
在这里插入图片描述
在RCC栏选择:
在这里插入图片描述
在SYS栏选择:
在这里插入图片描述
在TIM3勾选:
在这里插入图片描述
并在按下图进行配置:
在这里插入图片描述

原理:

PWM频率:

Fpwm =Tclk / ((arr+1)*(psc+1))(单位:Hz)

arr 是计数器值
psc 是预分频值
占空比:

duty circle = TIM3->CCR1 / arr(单位:%)
TIM3->CCR1 用户设定值
比如 定时器频率Tclk = 72Mhz arr=499 psc=71 那么PWM频率就是720000/500/72= 2000Hz,即2KHz

arr=499,TIM3->CCR1=250 则pwm的占空比为50%

改CCR1可以修改占空比,修改arr可以修改频率

在NVIC里面选择TIM中断:
在这里插入图片描述转到PROJECT MANAGER,勾选:
在这里插入图片描述
选择编译器
在这里插入图片描述
点击右上角GENERATE CODE生成项目

Ⅱ 编程

在 /* USER CODE BEGIN 2 */启动定时器和中断

  // 启动 PWM 和定时器
  HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);

  // 启动定时器并启用中断
  HAL_TIM_Base_Start_IT(&htim3);

重写中断:

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
  if (htim->Instance == TIM3) {
    static int toggle = 0;
    if (toggle == 0) {
      HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_RESET);
      toggle = 1;
    } else {
      HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET);
      toggle = 0;
    }
  }
}
Ⅲ 编译烧录

在这里插入图片描述

2. 渐亮渐灭呼吸灯

Ⅰ 创建项目

同上

Ⅱ 编程

在 /* USER CODE BEGIN 1 */里添加变量声明:

    uint16_t pwmVal=0;   
    uint8_t dir=1; 

在 /* USER CODE BEGIN 2*/里开启时钟

 HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_2);

在 /* USER CODE BEGIN 3 */里 添加:

 while (pwmVal< 500)
	  {
		  pwmVal++;
		  __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2, pwmVal);    
		  HAL_Delay(1);
	  }
	  while (pwmVal)
	  {
		  pwmVal--;
		  __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2, pwmVal);    
		  HAL_Delay(1);
	  }
	  HAL_Delay(200);
Ⅲ 编译烧录

在这里插入图片描述

3. 获取pwm周期和带宽由串口发送

Ⅰ 创建项目

在前面创建的基础上,增加关于串口通信的设置,按顺序勾选:
在这里插入图片描述
在这里插入图片描述
将用于获取带宽的管脚的tim设置为:
在这里插入图片描述
使能
在这里插入图片描述
将gpio设置为下降沿
点击GENERATE CODE
在这里插入图片描述

Ⅱ 编程

在原代码的基础上,增加中断回调函数

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
	
	HAL_UART_Transmit_DMA(&huart1, (uint8_t *)"light\n", strlen("light\n"));
  if (htim->Instance == TIM4)
  {
    static uint32_t captureTime = 0;
    static uint32_t lastCaptureTime = 0;
    uint32_t period = 0;
    uint32_t pulseWidth = 0;

    if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_3)
    {
      captureTime = HAL_TIM_ReadCapturedValue(&htim4, TIM_CHANNEL_3);
      if (captureTime > lastCaptureTime)
      {
        period = captureTime - lastCaptureTime;
        pulseWidth = lastCaptureTime;
      }
      else
      {
        period = (0xFFFF - lastCaptureTime) + captureTime;
        pulseWidth = (0xFFFF - captureTime);
      }

      lastCaptureTime = captureTime;

      char uartMsg[50];
snprintf(uartMsg, sizeof(uartMsg), "Period: %lu, Pulse Width: %lu\r\n", (unsigned long)period, (unsigned long)pulseWidth);

      HAL_UART_Transmit(&huart1, (uint8_t *)uartMsg, strlen(uartMsg), HAL_MAX_DELAY);
    }
  }
}

参考链接:

  1. https://blog.csdn.net/weixin_63019977/article/details/134150650
  2. https://blog.csdn.net/as480133937/article/details/99231677
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值