欢迎光临
我们一直在努力

三相逆变器驱动:STM32G4高级定时器,互补PWM生成实战

文章目录

    • 一、项目背景与原理概述
      • 1.1 核心原理
    • 二、硬件准备与环境搭建
      • 2.1 硬件清单
      • 2.2 软件环境
    • 三、开发流程总览
    • 四、STM32CubeMX详细配置步骤
      • 4.1 新建工程
      • 4.2 时钟配置
      • 4.3 高级定时器TIM1配置
      • 4.4 死区时间配置
      • 4.5 GPIO配置
      • 4.6 生成代码
    • 五、代码编写与实现
      • 5.1 核心代码文件说明
      • 5.2 代码实现
        • 文件名:tim.h
        • 文件名:tim.c
        • 文件名:main.c
    • 六、工程编译与调试
      • 6.1 编译工程
      • 6.2 下载程序
      • 6.3 波形调试
    • 七、常见问题与解决方案
      • 7.1 PWM无输出
      • 7.2 互补通道波形异常
      • 7.3 占空比调整无效果
    • 八、功能扩展建议
      • 总结

一、项目背景与原理概述

三相逆变器是新能源发电、电机驱动等领域的核心功率变换单元,其核心控制需求是生成6路互补且带死区保护的PWM信号。STM32G4系列MCU的高级定时器(TIM1/TIM8)原生支持互补PWM输出、死区插入、刹车保护等功能,是实现三相逆变器驱动的理想选择。

1.1 核心原理

  • 互补PWM:每一路主PWM通道对应一路互补PWM通道(如CH1对应CH1N),用于驱动逆变器上下桥臂,避免桥臂直通
  • 死区时间:在上下桥臂切换时插入固定延时,防止同一桥臂上下开关管同时导通
  • 高级定时器特性:STM32G4的TIM1/TIM8为高级控制定时器,支持中心对齐/边沿对齐模式、死区生成、刹车功能,满足逆变器驱动的严苛要求

二、硬件准备与环境搭建

2.1 硬件清单

  • 主控:STM32G431RBT6开发板
  • 功率器件:三相逆变器桥(如IR2104驱动的MOS管/H桥)
  • 辅助工具:示波器(用于观测PWM波形)、USB-TTL模块(调试)、5V/12V电源

2.2 软件环境

  • IDE:STM32CubeIDE 1.15.0
  • 固件库:STM32CubeG4 1.6.0
  • 调试工具:ST-Link V2

三、开发流程总览

#mermaid-svg-NJ9tC80DsoaV7knB{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-NJ9tC80DsoaV7knB .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-NJ9tC80DsoaV7knB .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-NJ9tC80DsoaV7knB .error-icon{fill:#552222;}#mermaid-svg-NJ9tC80DsoaV7knB .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-NJ9tC80DsoaV7knB .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-NJ9tC80DsoaV7knB .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-NJ9tC80DsoaV7knB .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-NJ9tC80DsoaV7knB .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-NJ9tC80DsoaV7knB .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-NJ9tC80DsoaV7knB .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-NJ9tC80DsoaV7knB .marker{fill:#333333;stroke:#333333;}#mermaid-svg-NJ9tC80DsoaV7knB .marker.cross{stroke:#333333;}#mermaid-svg-NJ9tC80DsoaV7knB svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-NJ9tC80DsoaV7knB p{margin:0;}#mermaid-svg-NJ9tC80DsoaV7knB .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-NJ9tC80DsoaV7knB .cluster-label text{fill:#333;}#mermaid-svg-NJ9tC80DsoaV7knB .cluster-label span{color:#333;}#mermaid-svg-NJ9tC80DsoaV7knB .cluster-label span p{background-color:transparent;}#mermaid-svg-NJ9tC80DsoaV7knB .label text,#mermaid-svg-NJ9tC80DsoaV7knB span{fill:#333;color:#333;}#mermaid-svg-NJ9tC80DsoaV7knB .node rect,#mermaid-svg-NJ9tC80DsoaV7knB .node circle,#mermaid-svg-NJ9tC80DsoaV7knB .node ellipse,#mermaid-svg-NJ9tC80DsoaV7knB .node polygon,#mermaid-svg-NJ9tC80DsoaV7knB .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-NJ9tC80DsoaV7knB .rough-node .label text,#mermaid-svg-NJ9tC80DsoaV7knB .node .label text,#mermaid-svg-NJ9tC80DsoaV7knB .image-shape .label,#mermaid-svg-NJ9tC80DsoaV7knB .icon-shape .label{text-anchor:middle;}#mermaid-svg-NJ9tC80DsoaV7knB .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-NJ9tC80DsoaV7knB .rough-node .label,#mermaid-svg-NJ9tC80DsoaV7knB .node .label,#mermaid-svg-NJ9tC80DsoaV7knB .image-shape .label,#mermaid-svg-NJ9tC80DsoaV7knB .icon-shape .label{text-align:center;}#mermaid-svg-NJ9tC80DsoaV7knB .node.clickable{cursor:pointer;}#mermaid-svg-NJ9tC80DsoaV7knB .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-NJ9tC80DsoaV7knB .arrowheadPath{fill:#333333;}#mermaid-svg-NJ9tC80DsoaV7knB .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-NJ9tC80DsoaV7knB .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-NJ9tC80DsoaV7knB .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-NJ9tC80DsoaV7knB .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-NJ9tC80DsoaV7knB .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-NJ9tC80DsoaV7knB .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-NJ9tC80DsoaV7knB .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-NJ9tC80DsoaV7knB .cluster text{fill:#333;}#mermaid-svg-NJ9tC80DsoaV7knB .cluster span{color:#333;}#mermaid-svg-NJ9tC80DsoaV7knB div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-NJ9tC80DsoaV7knB .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-NJ9tC80DsoaV7knB rect.text{fill:none;stroke-width:0;}#mermaid-svg-NJ9tC80DsoaV7knB .icon-shape,#mermaid-svg-NJ9tC80DsoaV7knB .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-NJ9tC80DsoaV7knB .icon-shape p,#mermaid-svg-NJ9tC80DsoaV7knB .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-NJ9tC80DsoaV7knB .icon-shape rect,#mermaid-svg-NJ9tC80DsoaV7knB .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-NJ9tC80DsoaV7knB .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-NJ9tC80DsoaV7knB .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-NJ9tC80DsoaV7knB :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

环境搭建

CubeMX配置

时钟与GPIO配置

高级定时器TIM1配置

互补PWM参数设置

死区时间配置

代码生成与移植

工程编译与下载

PWM波形调试验证

功能优化与定型

四、STM32CubeMX详细配置步骤

4.1 新建工程

  • 打开STM32CubeMX,点击New Project
  • 在搜索框输入STM32G431RBT6,选择对应型号后点击Start Project
  • 弹出的Pinout & Configuration界面保持默认,进入下一步
  • 4.2 时钟配置

  • 点击左侧Clock Configuration标签
  • 选择外部高速时钟(HSE)为Crystal/Ceramic Resonator
  • 将系统时钟(SYSCLK)配置为170MHz:
    • PLL源选择HSE(8MHz)
    • PLLM=4,PLLN=85,PLLP=2,PLLQ=2,PLLR=2
    • 点击Apply保存时钟配置
  • 4.3 高级定时器TIM1配置

  • 点击左侧Pinout & Configuration标签,展开Timers选择TIM1
  • 模式配置:
    • Timer Mode:选择PWM Generation CH1, CH2, CH3
    • Counter Mode:选择Up Counter(边沿对齐模式)
    • Clock Source:选择Internal Clock
  • 通道配置:
    • CH1: PWM Generation CH1
    • CH1N: PWM Generation CH1N
    • CH2: PWM Generation CH2
    • CH2N: PWM Generation CH2N
    • CH3: PWM Generation CH3
    • CH3N: PWM Generation CH3N
  • 参数配置:
    • Prescaler (PSC):169(分频后定时器时钟为1MHz)
    • Counter Period (ARR):999(PWM周期为1ms,频率1kHz)
    • CHx Pulse (CCRx):500(占空比50%,可后期代码动态调整)
    • Polarity:High(高电平有效)
    • Complementary Polarity:Low(互补通道低电平有效)
  • 4.4 死区时间配置

  • 在TIM1配置界面,展开Break and Dead-Time
  • Dead Time:输入100(死区时间=100/(定时器时钟)=100us,可根据功率器件调整)
  • Lock Level:选择Level 1(锁定配置防止误修改)
  • Automatic Output Enable:勾选(自动使能输出)
  • 4.5 GPIO配置

    TIM1的PWM通道对应GPIO引脚(STM32G431RBT6):

    • CH1: PA8
    • CH1N: PB13
    • CH2: PA9
    • CH2N: PB14
    • CH3: PA10
    • CH3N: PB15

    确认上述引脚已被自动配置为Alternate Function Mode,无需手动修改。

    4.6 生成代码

  • 点击右上角Project Manager
  • 配置项目信息:
    • Project Name:STM32G4_Inverter_PWM
    • Project Location:选择自定义路径
    • Toolchain/IDE:选择STM32CubeIDE
  • 点击Code Generator,勾选Generate peripheral initialization as a pair of '.c/.h' files per peripheral
  • 点击Generate Code,等待代码生成完成后打开工程
  • 五、代码编写与实现

    5.1 核心代码文件说明

    文件名功能说明
    main.c 主函数,包含定时器初始化、PWM启动、主循环
    tim.c 定时器底层驱动,包含TIM1初始化、PWM参数配置
    tim.h 定时器宏定义、函数声明

    5.2 代码实现

    文件名:tim.h

    #ifndef __TIM_H
    #define __TIM_H

    #include "main.h"

    /* TIM1 相关宏定义 */
    #define TIM1_PWM_FREQ 1000 // PWM频率1kHz
    #define TIM1_PRESCALER 169 // 预分频值
    #define TIM1_ARR 999 // 自动重装载值
    #define TIM1_DEAD_TIME 100 // 死区时间

    /* 函数声明 */
    void MX_TIM1_Init(void);
    void TIM1_Set_PWM_DutyCycle(uint32_t channel, uint16_t duty);
    void TIM1_Start_PWM(void);

    #endif /* __TIM_H */

    文件名:tim.c

    #include "tim.h"

    TIM_HandleTypeDef htim1;
    TIM_OC_InitTypeDef sConfigOC = {0};
    TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};

    /**
    * @brief TIM1 Initialization Function
    * @param None
    * @retval None
    */

    void MX_TIM1_Init(void)
    {
    /* TIM1 基础配置 */
    htim1.Instance = TIM1;
    htim1.Init.Prescaler = TIM1_PRESCALER; // 预分频
    htim1.Init.CounterMode = TIM_COUNTERMODE_UP; // 向上计数模式
    htim1.Init.Period = TIM1_ARR; // 自动重装载值
    htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // 时钟分频
    htim1.Init.RepetitionCounter = 0; // 重复计数器
    htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; // 使能ARR预装载
    if (HAL_TIM_PWM_Init(&htim1) != HAL_OK)
    {
    Error_Handler();
    }

    /* CH1 配置 */
    sConfigOC.OCMode = TIM_OCMODE_PWM1; // PWM模式1
    sConfigOC.Pulse = TIM1_ARR / 2; // 初始占空比50%
    sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; // 通道极性高
    sConfigOC.OCNPolarity = TIM_OCNPOLARITY_LOW; // 互补通道极性低
    sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; // 关闭快速模式
    sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET; // 空闲状态复位
    sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET; // 互补通道空闲状态复位
    if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
    {
    Error_Handler();
    }

    /* CH2 配置 */
    if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
    {
    Error_Handler();
    }

    /* CH3 配置 */
    if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
    {
    Error_Handler();
    }

    /* 死区配置 */
    sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
    sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
    sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_1;
    sBreakDeadTimeConfig.DeadTime = TIM1_DEAD_TIME; // 死区时间设置
    sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
    sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
    sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_ENABLE; // 自动输出使能
    if (HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig) != HAL_OK)
    {
    Error_Handler();
    }
    }

    /**
    * @brief 设置PWM占空比
    * @param channel: 通道号(TIM_CHANNEL_1/2/3)
    * @param duty: 占空比(0~TIM1_ARR)
    * @retval None
    */

    void TIM1_Set_PWM_DutyCycle(uint32_t channel, uint16_t duty)
    {
    // 边界检查,防止占空比超出范围
    if(duty > TIM1_ARR)
    {
    duty = TIM1_ARR;
    }

    TIM_OC_InitTypeDef sConfigOC = {0};
    sConfigOC.OCMode = TIM_OCMODE_PWM1;
    sConfigOC.Pulse = duty;
    sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
    sConfigOC.OCNPolarity = TIM_OCNPOLARITY_LOW;
    sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
    sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
    sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;

    if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, channel) != HAL_OK)
    {
    Error_Handler();
    }

    // 重新使能通道输出
    HAL_TIM_PWM_Start(&htim1, channel);
    HAL_TIMEx_PWMN_Start(&htim1, channel);
    }

    /**
    * @brief 启动TIM1所有PWM通道
    * @param None
    * @retval None
    */

    void TIM1_Start_PWM(void)
    {
    // 启动主通道PWM输出
    HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
    HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);
    HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3);

    // 启动互补通道PWM输出
    HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1);
    HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_2);
    HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_3);
    }

    /**
    * @brief 定时器底层初始化(GPIO、时钟)
    * @param htim: 定时器句柄
    * @retval None
    */

    void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef* htim_pwm)
    {
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    if(htim_pwm->Instance==TIM1)
    {
    /* TIM1 时钟使能 */
    __HAL_RCC_TIM1_CLK_ENABLE();

    /* GPIO 时钟使能 */
    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_GPIOB_CLK_ENABLE();

    /* TIM1_CH1 (PA8) 配置 */
    GPIO_InitStruct.Pin = GPIO_PIN_8;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF6_TIM1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* TIM1_CH2 (PA9) 配置 */
    GPIO_InitStruct.Pin = GPIO_PIN_9;
    GPIO_InitStruct.Alternate = GPIO_AF6_TIM1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* TIM1_CH3 (PA10) 配置 */
    GPIO_InitStruct.Pin = GPIO_PIN_10;
    GPIO_InitStruct.Alternate = GPIO_AF6_TIM1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* TIM1_CH1N (PB13) 配置 */
    GPIO_InitStruct.Pin = GPIO_PIN_13;
    GPIO_InitStruct.Alternate = GPIO_AF6_TIM1;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    /* TIM1_CH2N (PB14) 配置 */
    GPIO_InitStruct.Pin = GPIO_PIN_14;
    GPIO_InitStruct.Alternate = GPIO_AF6_TIM1;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    /* TIM1_CH3N (PB15) 配置 */
    GPIO_InitStruct.Pin = GPIO_PIN_15;
    GPIO_InitStruct.Alternate = GPIO_AF6_TIM1;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
    }
    }

    /**
    * @brief 定时器底层反初始化
    * @param htim: 定时器句柄
    * @retval None
    */

    void HAL_TIM_PWM_MspDeInit(TIM_HandleTypeDef* htim_pwm)
    {
    if(htim_pwm->Instance==TIM1)
    {
    /* TIM1 时钟禁用 */
    __HAL_RCC_TIM1_CLK_DISABLE();

    /* GPIO 引脚反初始化 */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10);
    HAL_GPIO_DeInit(GPIOB, GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15);
    }
    }

    /**
    * @brief 错误处理函数
    * @param None
    * @retval None
    */

    void Error_Handler(void)
    {
    /* 用户可自定义错误处理逻辑,如LED闪烁 */
    __disable_irq();
    while(1)
    {
    // 空循环,方便调试
    }
    }

    文件名:main.c

    /* Includes ——————————————————————*/
    #include "main.h"
    #include "tim.h"

    /* Private function prototypes ———————————————–*/
    void SystemClock_Config(void);
    static void MX_GPIO_Init(void);

    /**
    * @brief The application entry point.
    * @retval int
    */

    int main(void)
    {
    /* 初始化HAL库 */
    HAL_Init();

    /* 配置系统时钟 */
    SystemClock_Config();

    /* 初始化所有配置的外设 */
    MX_GPIO_Init();
    MX_TIM1_Init();

    /* 启动TIM1的6路PWM输出(3路主通道+3路互补通道) */
    TIM1_Start_PWM();

    /* 主循环 */
    while (1)
    {
    /* 动态调整占空比示例:循环改变CH1占空比(0~100%) */
    static uint16_t duty = 0;
    static uint8_t dir = 1; // 1:占空比增加,0:占空比减少

    // 调整占空比
    TIM1_Set_PWM_DutyCycle(TIM_CHANNEL_1, duty);
    TIM1_Set_PWM_DutyCycle(TIM_CHANNEL_2, 300); // CH2固定30%占空比
    TIM1_Set_PWM_DutyCycle(TIM_CHANNEL_3, 700); // CH3固定70%占空比

    // 占空比方向控制
    if(dir)
    {
    duty += 10;
    if(duty >= TIM1_ARR)
    {
    dir = 0;
    }
    }
    else
    {
    duty -= 10;
    if(duty <= 0)
    {
    dir = 1;
    }
    }

    /* 延时50ms,控制占空比变化速度 */
    HAL_Delay(50);
    }
    }

    /**
    * @brief System Clock Configuration
    * @retval None
    */

    void SystemClock_Config(void)
    {
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

    /* 配置电源电压缩放 */
    HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);

    /* 配置振荡器 */
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV4;
    RCC_OscInitStruct.PLL.PLLN = 85;
    RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
    RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
    RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
    {
    Error_Handler();
    }

    /* 配置系统时钟 */
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
    |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
    {
    Error_Handler();
    }
    }

    /**
    * @brief GPIO Initialization Function
    * @param None
    * @retval None
    */

    static void MX_GPIO_Init(void)
    {
    /* GPIO初始化已在tim.c的HAL_TIM_PWM_MspInit中完成,此处留空 */
    }

    #ifdef USE_FULL_ASSERT
    /**
    * @brief Reports the name of the source file and the source line number
    * where the assert_param error has occurred.
    * @param file: pointer to the source file name
    * @param line: assert_param error line source number
    * @retval None
    */

    void assert_failed(uint8_t *file, uint32_t line)
    {
    /* 用户可自定义打印错误信息 */
    }
    #endif /* USE_FULL_ASSERT */

    六、工程编译与调试

    6.1 编译工程

  • 在STM32CubeIDE中打开生成的工程
  • 点击菜单栏Project -> Build Project
  • 等待编译完成,确保无错误(Errors)和警告(Warnings)
  • 6.2 下载程序

  • 连接ST-Link到开发板,确保硬件连接正确
  • 点击菜单栏Run -> Debug
  • 在弹出的Debug Configurations中选择STM32 Debug,点击Debug
  • 程序自动下载到STM32G431并开始运行
  • 6.3 波形调试

  • 将示波器探头分别连接到PA8(CH1)、PB13(CH1N)、PA9(CH2)、PB14(CH2N)、PA10(CH3)、PB15(CH3N)
  • 观测波形特征:
    • 主通道与互补通道波形互补(主通道高电平时互补通道低电平)
    • 上下桥臂切换处有明显的死区时间(100us)
    • CH1占空比循环变化(0~100%),CH2固定30%,CH3固定70%
    • PWM频率稳定在1kHz
  • 七、常见问题与解决方案

    7.1 PWM无输出

    • 原因1:TIM1输出未使能 → 解决方案:确认TIM1_Start_PWM()函数已调用,且HAL_TIMEx_PWMN_Start已执行
    • 原因2:GPIO引脚配置错误 → 解决方案:检查GPIO的Alternate Function是否为AF6_TIM1
    • 原因3:死区配置导致输出被禁用 → 解决方案:确认Automatic Output已使能

    7.2 互补通道波形异常

    • 原因1:极性配置错误 → 解决方案:主通道设为TIM_OCPOLARITY_HIGH,互补通道设为TIM_OCNPOLARITY_LOW
    • 原因2:死区时间设置过大/过小 → 解决方案:根据功率器件的开关时间调整DeadTime值

    7.3 占空比调整无效果

    • 原因:未重新配置通道参数 → 解决方案:调用HAL_TIM_PWM_ConfigChannel后需重新启动PWM输出

    八、功能扩展建议

  • 刹车保护功能:添加故障检测(如过流、过压),触发TIM1的Break功能,快速关闭PWM输出
  • 中心对齐PWM:修改CounterMode为TIM_COUNTERMODE_CENTERALIGNED1,优化电机驱动波形
  • DMA传输:使用DMA自动更新CCR寄存器值,实现无中断的占空比调整
  • 闭环控制:结合ADC采样(如电流、电压),实现基于PID算法的PWM占空比动态调节
  • 总结

  • STM32G4的高级定时器TIM1/TIM8是实现三相逆变器互补PWM输出的核心外设,需重点配置PWM通道、死区时间和GPIO复用功能。
  • 完整的开发流程包括CubeMX配置、代码编写、编译下载和波形调试,其中死区时间配置和互补通道极性设置是保证逆变器安全运行的关键。
  • 基础代码实现了6路互补PWM的生成和占空比动态调整,可通过扩展刹车保护、闭环控制等功能满足实际工程需求。
  • 赞(0)
    未经允许不得转载:171主机测评 » 三相逆变器驱动:STM32G4高级定时器,互补PWM生成实战
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址