[STM32F4] 基于STM32F407的定时器PWM输出实现与应用

[复制链接]
 楼主| Bblythe 发表于 2024-12-5 07:46 | 显示全部楼层 |阅读模式
在嵌入式系统中,PWM(脉宽调制)广泛应用于电机控制、LED调光等场景。本文将基于ST公司的STM32F407微控制器,通过定时器实现PWM输出功能,深入探讨实现过程与代码细节。
一、硬件和软件准备
  • 硬件
    • STM32F407开发板
    • LED模块或负载设备
    • 示波器(用于检测PWM波形)
  • 软件
    • STM32CubeIDE
    • STM32CubeMX
二、PWM输出的原理PWM信号是一种数字信号,通过调节高电平占空比来模拟连续变化的模拟量。STM32F407内部集成了多组高级定时器(如TIM1、TIM8),可以通过硬件直接生成稳定的PWM信号。
三、实现步骤
  • 配置定时器:通过STM32CubeMX初始化定时器,设置为PWM模式,并指定输出引脚。
  • 编写代码:设置占空比,控制输出信号的强弱。
  • 验证结果:使用LED灯或示波器验证PWM波形。
四、代码实现以下代码展示如何使用STM32F407生成一组50Hz、占空比可调的PWM信号。
  1. #include "stm32f4xx_hal.h"

  2. TIM_HandleTypeDef htim3;

  3. /* 定时器初始化 */
  4. void MX_TIM3_Init(void)
  5. {
  6.     TIM_OC_InitTypeDef sConfigOC = {0};

  7.     htim3.Instance = TIM3;
  8.     htim3.Init.Prescaler = 84 - 1;  // 预分频器,将84MHz分为1MHz
  9.     htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
  10.     htim3.Init.Period = 20000 - 1;  // 1MHz计数到20000对应50Hz
  11.     htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  12.     htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
  13.     if (HAL_TIM_PWM_Init(&htim3) != HAL_OK)
  14.     {
  15.         Error_Handler();
  16.     }

  17.     sConfigOC.OCMode = TIM_OCMODE_PWM1;
  18.     sConfigOC.Pulse = 1500;  // 初始占空比为7.5% (1500/20000)
  19.     sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  20.     sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  21.     if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  22.     {
  23.         Error_Handler();
  24.     }
  25. }

  26. /* 主函数 */
  27. int main(void)
  28. {
  29.     HAL_Init();
  30.     SystemClock_Config();
  31.     MX_TIM3_Init();

  32.     /* 开启PWM输出 */
  33.     if (HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1) != HAL_OK)
  34.     {
  35.         Error_Handler();
  36.     }

  37.     while (1)
  38.     {
  39.         for (int duty = 500; duty <= 2500; duty += 100) // 调整占空比
  40.         {
  41.             __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, duty);
  42.             HAL_Delay(500);  // 延时500ms
  43.         }
  44.     }
  45. }

  46. /* 系统时钟配置 */
  47. void SystemClock_Config(void)
  48. {
  49.     RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  50.     RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  51.     RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  52.     RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  53.     RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  54.     RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  55.     RCC_OscInitStruct.PLL.PLLM = 8;
  56.     RCC_OscInitStruct.PLL.PLLN = 336;
  57.     RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  58.     RCC_OscInitStruct.PLL.PLLQ = 7;
  59.     if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  60.     {
  61.         Error_Handler();
  62.     }

  63.     RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
  64.                                 | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
  65.     RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  66.     RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  67.     RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
  68.     RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
  69.     if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
  70.     {
  71.         Error_Handler();
  72.     }
  73. }

  74. /* 错误处理函数 */
  75. void Error_Handler(void)
  76. {
  77.     while (1)
  78.     {
  79.         // 错误状态循环处理
  80.     }
  81. }
五、实验结果通过示波器,我们可以观察到50Hz的PWM信号,并且通过代码动态调整占空比,负载(如LED)亮度随之变化。
六、总结STM32F407强大的定时器资源,使得生成精准的PWM信号变得非常方便。在实际项目中,我们可以扩展该功能,用于电机速度控制或信号调制。

公羊子丹 发表于 2024-12-5 07:46 | 显示全部楼层
这个代码真是解决了我的疑惑,学习到了新东西!
周半梅 发表于 2024-12-5 07:46 | 显示全部楼层
终于找到一篇详细的STM32 PWM教程,感谢!
帛灿灿 发表于 2024-12-5 07:47 | 显示全部楼层
我也用过F407的定时器,但没想到能这么灵活。
童雨竹 发表于 2024-12-5 07:47 | 显示全部楼层
能不能讲讲PWM输出如何与外部中断结合?
万图 发表于 2024-12-5 07:47 | 显示全部楼层
实验完了,波形很稳定,这代码一绝。
Wordsworth 发表于 2024-12-5 07:47 | 显示全部楼层
还可以加入DMA进一步优化性能,不知道楼主有没有研究?
Pulitzer 发表于 2024-12-5 07:48 | 显示全部楼层
真正实践起来才知道调试的难点,谢谢解答。
Uriah 发表于 2024-12-5 07:48 | 显示全部楼层
如果加多路输出,配置多个通道的话代码该怎么改?
Clyde011 发表于 2024-12-5 07:48 | 显示全部楼层
STM32的硬件真心强大,看完这篇又想买块板子了。
macpherson 发表于 2024-12-9 16:04 | 显示全部楼层
STM32F407系列微控制器提供了多种类型的定时器,包括基本定时器、通用定时器和高级定时器 。并非所有定时器都支持PWM输出,因此需要选择支持PWM功能的定时器,如TIM1、TIM8等高级定时器,或者TIM2、TIM3、TIM4、TIM5等通用定时器
fengm 发表于 2024-12-9 16:53 | 显示全部楼层
在实际应用中,使用示波器等工具测试PWM波形,确保其符合预期的频率和占空比。
alvpeg 发表于 2024-12-10 13:38 | 显示全部楼层
设置预分频器以降低定时器时钟频率,以达到所需的PWM频率。
everyrobin 发表于 2024-12-10 14:15 | 显示全部楼层
在配置PWM输出之前,需要确定PWM的频率和占空比。PWM频率取决于定时器的时钟频率和预分频系数,而占空比则取决于捕获/比较寄存器的值
belindagraham 发表于 2024-12-10 16:17 | 显示全部楼层
STM32F407 的定时器有多个通道(如 TIM1 有 4 个通道),每个通道可以独立输出 PWM 信号。需要根据具体应用确定使用哪些通道,并对通道进行配置,包括设置比较模式(如 PWM1 模式或 PWM2 模式)、输出极性(高电平有效或低电平有效)等。例如,在一些应用中,可能需要设置为高电平有效来驱动负载。
sesefadou 发表于 2024-12-12 10:36 | 显示全部楼层
在电源引脚附近放置去耦电容,以减少电源噪声。
adolphcocker 发表于 2024-12-12 11:04 | 显示全部楼层
高级定时器(TIM1和TIM8):可以同时产生多达7路的PWM输出,适用于需要多路PWM的应用。
通用定时器(TIM2、TIM3、TIM4、TIM5等):可以同时产生多达4路的PWM输出,适用于大多数常规应用。
基本定时器(TIM6和TIM7):不支持PWM输出,主要用于定时功能。
lzbf 发表于 2024-12-12 12:30 | 显示全部楼层
如果 PWM 信号用于驱动外部设备(如电机、LED 灯等),需要注意连接的稳定性和正确性。对于大功率设备(如电机),可能需要添加驱动电路(如 H 桥电路用于电机正反转控制),并且要考虑信号的隔离(如光耦隔离),以防止外部设备对 STM32F407 芯片造成损坏。
primojones 发表于 2024-12-12 14:19 | 显示全部楼层
在电机控制等应用中,可能需要配置死区时间以防止同时导通两个桥臂。
geraldbetty 发表于 2024-12-12 15:54 | 显示全部楼层
在设计PWM输出电路时,应注意电磁兼容性(EMC)问题,避免产生过多的电磁干扰。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

145

主题

5747

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部