【动手学STM32G4】(1)STM32G431之创建项目
【动手学STM32G4】(4)STM32G431之PWM输出
【动手学STM32G4】(15)三路互补带死区 PWM 输出
【动手学电机驱动】(15)三路互补带死区 PWM 输出
-
- [1. 项目介绍](#1. 项目介绍)
-
- [1.1 项目内容](#1.1 项目内容)
- [1.2 互补PWM与死区时间](#1.2 互补PWM与死区时间)
- [1.3 硬件需求与引脚分配](#1.3 硬件需求与引脚分配)
- [2. CubeMX工程配置](#2. CubeMX工程配置)
-
- [2.1 创建新项目](#2.1 创建新项目)
- [2.2 TIM 配置](#2.2 TIM 配置)
- [2.3 生成代码](#2.3 生成代码)
- [3. CubeIDE 编程与调试](#3. CubeIDE 编程与调试)
- [4. 实验结果](#4. 实验结果)
- [5. 小结](#5. 小结)
1. 项目介绍
1.1 项目内容
在电机控制中通常使用三相逆变桥来驱动电机,每个桥臂需要一对互补的PWM信号来控制上下桥臂的MOSFET,并且为了避免上下桥臂同时导通(直通),必须插入死区时间。
- 三相系统:需要U、V、W三个独立的PWM通道
- 双向驱动:每相需要高侧(推)和低侧(拉)两个开关管
- 互补控制:高侧和低侧必须严格互补导通
- 安全间隙:切换瞬间必须留出"死区时间"防止直通
我们在前文 【动手学STM32G4】(4)STM32G431之PWM输出 中已经介绍了 PWM 输出的基本方法。本文在此基础上,实现三路互补带死区的 PWM 输出。
- 配置STM32G431的高级定时器TIM1
- 生成三路带死区的互补PWM信号
- 掌握 PWM 的计算与配置方法
1.2 互补PWM与死区时间
脉冲宽度调制(PWM)利用MCU 的数字输出来对模拟电路进行控制,采用一系列形状不同但面积相等的矩形脉冲代替正弦信号,具有与正弦波输入近似的输出响应。
一类 PWM 输出的应用是由 MOS、IGBT 等功率器件组成的 H 桥或三相桥 ,每路桥壁的上半桥和下半桥互补输出。"互补"意味着:当上桥臂导通时,下桥臂必须关断;当下桥臂导通时,上桥臂必须关断。
在电机控制中,通过控制开关管的导通和关断,来在电机三相绕组上产生所需的电压。每一相不能同时打开高侧和低侧开关管,否则会造成电源"直通"(Shoot-through),短路到地会瞬间产生大电流,烧毁开关管。
为了避免直通,同时又能控制电流的方向,需要采用"互补PWM"的控制方式。所谓互补,就是指同一相的高侧和低侧开关管的控制信号是互补的:当高侧打开时,低侧必须关闭;当低侧打开时,高侧必须关闭。
由于开关管从导通到关断,以及从关断到导通,都需要一定时间(开关时间)。如果在高侧关断后立即打开低侧,高侧可能还没有完全关断而导致直通。因此,需要在控制信号中插入一段"死区时间"(Dead Time),在半桥关断后延迟一段时间再打开互补半桥,防止上下半桥同时导通而导致器件烧毁。
1.3 硬件需求与引脚分配
-
硬件平台:NUCLEO-G431RB 开发板
-
引脚分配
本实验使用 TIM1 定时器,PWM 输出的引脚分配如下。
bash
TIM1:
CH1: PA8, CH1N:PB13
CH2: PA9, CH2N:PB14
CH3: PA10, CH3N:PB15
- 中断频率与 PWM 占空比计算
根据业务需要,本实验生成频率 10kHz、占空比为 50% 的 PWM。
(1)配置系统时钟 SysCLK 为 160MHz,选择 PSC = 0(不分频),ARR = 8000-1。
系统时钟频率为 168MHz,将计数周期 Counter Period 设为 16000/2(除2是因为三角波分为上升和下降两段),则 PWM 频率为 160MHz/16000 = 10KHz。
(2)计算 PWM 频率与占空比:
f P W M = f s y s ( P S C + 1 ) ∗ ( A R R + 1 ) = 160 M H z 8000 = 20 k H z p u l s e = d u t y ∗ A R R = 0.5 ∗ 7999 = 4000 \begin{matrix} f_{PWM} &=&\frac{f_{sys}}{(PSC+1)*(ARR+1)} &=&\frac{160 MHz}{8000}&= 20 kHz \\ pulse &=& duty *ARR &=& 0.5 * 7999 &= 4000 \end{matrix} fPWMpulse==(PSC+1)∗(ARR+1)fsysduty∗ARR==8000160MHz0.5∗7999=20kHz=4000
(3)设置 Prescaler(PSC)为 0,设置 Counter Period(ARR)为 8000。在 "PWM Generation Channel 1" 下,设置 Pulse 为 4000,则可以得到频率为 10kHz,占空比为 50% 的 PWM。
- 死区时间的计算:
(1)IHM16M1 驱动板使用 STSPIN830,典型开关延迟:50ns,上升/下降时间:30ns。按照 50% 安全余量设计:最坏情况延迟 = 50ns + 30ns =80ns,安全死区时间 = 80ns * 1.5 = 120ns。
(2)在 STM32G431 上,死区时间以定时器时钟周期为单位:TIM1 时钟 160 MHz,时钟周期 = 1/160MHz = 6.25ns,由此计算:死区时钟计数 = 120ns/6.25ns = 19.2。
于是,死区时间计数取为 20。
2. CubeMX工程配置
2.1 创建新项目
-
新建工程。
启动 STM32CubeMX,点击 "Start New Project" (或Ctrl-N快捷键)新建工程,进入 New Project 界面。
选择MCU为 STM32G431RBT6(参考开发板的 MCU 型号选择)。
选择开发板为 NUCLEO-G431RB 开发板。
点击右上角 "Start Project" 创建项目。
-
配置系统时钟树。
(1)点击顶部 "Clock Configuration" 选项卡,进入时钟树配置。
(2)设置输入频率 Input frequency=24 MHz,SysCLK frequency=160 MHz。
配置完成后,System Clock 显示为160MHz,HCLK、PCLK1、PCLK2 均为160MHz。

-
系统配置:在引脚配置(Pinout & Configuration)中,选择 "System Core -- SYS" 。
(1)设置调试器类型,将 Debug 模式设为 "Serial Wire"。
(2)设置基础时钟源(Timebase Source),可以选择默认设置 "SysTick"。
(3)时钟配置:在引脚配置(Pinout & Configuration)中,选择 "System Core -- RCC" 配置时钟模式。
设置高速时钟为外部晶振,将 High Speed Clock (HSE) 设为 "Crystal/Ceramic Resonator"。
Low Speed Clock (LSE) 设为 "Disable"(本实验不需要)。
-
GPIO 配置。
(1)将 LD2(PA5)配置为输出模式 "GPIO_Output"。
(2)将用户按键(PC13)配置为外部中断 "GPIO_EXTI13"。
2.2 TIM 配置
配置定时器 TIM1 中断频率为 10kHz。
- 配置 TIM1 输出管脚。
在右侧 Pinout View 图中,
bash
将 TIM1_CH1 映射到 PA8 管脚
将 TIM1_CH2 映射到 PA9 管脚
将 TIM1_CH3 映射到 PA10 管脚
将 TIM1_CH1N 映射到 PB13 管脚
将 TIM1_CH2N 映射到 PB14 管脚
将 TIM1_CH3N 映射到 PB15 管脚
- 启用并配置TIM1 :
(1)选择 "引脚配置(Pinout & Configuration)",从左侧下拉列表中选择 "Timers -- TIM1 -- TIM1 Mode and Configuration ",配置 TIM1 Mode 如下:
bash
Clock Source 配置为: Internal Clock
Channel-1 配置为: PWM Generation CH1 CH1N(PWM 互补输出)
Channel-2 配置为: PWM Generation CH2 CH2N(PWM 互补输出)
Channel-3 配置为: PWM Generation CH3 CH3N(PWM 互补输出)
Channel-4 配置为: PWM Generation No Output(备用,用于 触发ADC采样)

(2)TIM1 计数器参数配置:
预分频 Prescaler(PSC)设为 0,不分频;
计数器模式 Counter Mode 选择中心对齐的三角波:Center Aligned model 1 ;
计数周期 Counter Period 设为 PWM 频率:8000-1;
允许重新加载:auto-reload preload 设为 Enable;
更新时触发一个事件:Trigger Event Selection TRGO 设为 Update Event。
bash
Counter Settings:
Prescaler (PSC-16 bits value): 0
Counter Mode: Center Aligned mode 1
Counter Period (ARR): 7999
Internal Clock Division (CKD): No Division
Repetition Counter (RCR): 0
auto-reloaded preload: Enable
Trigger Output (TRGO) Parameters:
Trigger Event Selection TRGO: Update Event
(3)死区时间参数配置:
在 "Break And Dead Time management - Output Configuration" 选项中:
bash
Break And Dead Time management - Output Configuration:
Automatic Output State: Enable
DeadTime Preload: Enable
Dead Time: 20(计数周期)
(4)PWM 发生器参数配置:
互补 PWM 的极性配置要根据硬件选择,例如上管 PMOS、下管 NMOS,需要将极性配置相反;如果上下桥都是 NMOS,则需要将极性配置相同。
bash
PWM Generation Channel 1 and 1N
Mode: PWM mode 1
Pulse: 4000 (占空比为 50%)
Output compare preload: Enable
PWM Generation Channel 2 and 2N
Mode: PWM mode 1
Pulse: 4000 (占空比为 50%)
Output compare preload: Enable
PWM Generation Channel 3 and 3N
Mode: PWM mode 1
Pulse: 4000 (占空比为 50%)
Output compare preload: Enable

2.3 生成代码
- 点击 "Project Manager" 菜单按钮,进入工程配置界面。
- 输入项目名称为 "STM32G431_PWM04",选择项目的保存路径。
- 将Toolchain / IDE 设为 STM32CubeIDE(根据用户安装和使用的 IDE 选择,也可以选择 EWARM、MDK-ARM、MakeFile、CMake 等IDE工具)
- 点击右上角 "GENERATE CODE" 生成代码
- 加载完毕后,弹出代码生成提示窗口,点击" OPEN PROJECT",进入 STM32CubeIDE。

3. CubeIDE 编程与调试
-
在 STM32CubeIDE 打开代码文件 main.c。
代码生成后,已经自动进入 STM32CubeIDE,并打开创建的 STM32G431_DAC01 项目。在 "Core\Src" 目录中,已经生成了 dac.c 和 main.c 等基础程序。
-
程序 main.c 的架构如下:
-
编写程序代码。
(1)在程序开头部分,添加参数定义和 生成 PWM 输出的函数如下。
c
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#define TIM_CLK_MHz 160
#define PWM_FREQ 10000
#define PWM_PERIOD 1000000*TIM_CLK_MHz/PWM_FREQ/2
/* USER CODE END Includes */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
void generate_PWM(void)
{
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1); // Start PWM CH1
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_3);
HAL_TIMEx_PWMN_Start(&htim1,TIM_CHANNEL_1); // Set PWM CH1N
HAL_TIMEx_PWMN_Start(&htim1,TIM_CHANNEL_2);
HAL_TIMEx_PWMN_Start(&htim1,TIM_CHANNEL_3);
__HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_1, 0.5*PWM_PERIOD); // Set PWM1-CH1 duty: 50%
__HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_2, 0.4*PWM_PERIOD);
__HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_3, 0.3*PWM_PERIOD);
}
/* USER CODE END 0 */
(2)在主程序 main() 初始化完成后,添加 生成 PWM 输出的程序代码:
c
/* USER CODE BEGIN 2 */
generate_PWM();
/* USER CODE END 2 */
/* Infinite loop */
while (1)
{
HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
HAL_Delay(100); // Insert delay 100 ms
}
(3)将鼠标移动到 HAL_TIM_PWM_Start,按 F3 可以打开 HAL_TIM_PWM_Start() 的程序代码如下。该程序用于启动 PWM 信号发生器。(该步骤非必须,只是介绍查看的方法)
c
/**
* @brief Starts the PWM signal generation.
* @param htim TIM handle
* @param Channel TIM Channels to be enabled
* This parameter can be one of the following values:
* @arg TIM_CHANNEL_1: TIM Channel 1 selected
* @arg TIM_CHANNEL_2: TIM Channel 2 selected
* @arg TIM_CHANNEL_3: TIM Channel 3 selected
* @arg TIM_CHANNEL_4: TIM Channel 4 selected
* @arg TIM_CHANNEL_5: TIM Channel 5 selected
* @arg TIM_CHANNEL_6: TIM Channel 6 selected
* @retval HAL status
*/
HAL_StatusTypeDef HAL_TIM_PWM_Start(TIM_HandleTypeDef *htim, uint32_t Channel)
- 程序编译与调试
- 用 USB连接线,连接 PC 与 NUCLEO-G431RB 开发板。
- 点击工具栏中 "Build Debug" 按键对程序代码进行编译。
- 点击工具栏中 "Debug" 按键,将程序下载烧录到目标板 NUCLEO-G431RB 。
- 点击工具栏中 "Resume" 按键 或 F8 快捷键,运行程序。
4. 实验结果
运行程序,NUCLEO-G431RB 开发板上的 LD2 指示灯以 10Hz 频率闪烁。
使用示波器观察引脚 PA8 和 PB13 输出的波形。
(1)示波器通道1 → U相高侧驱动信号UH(对应 PA8 引脚)
(2)示波器通道2 → U相低侧驱动信号UL(对应 PB13 引脚)
注:UH和UL是互补信号,用于驱动同一相的上、下桥臂MOSFET。
如下图所示,可以看到在每次电平切换时,UH和UL信号存在短暂的时间同时保持低电平,这就是死区时间。

5. 小结
本文详细介绍基于STM32G431的三路互补PWM输出,重点配置了死区时间保护和中央对齐模式,为电机FOC控制搭建了可靠的基础设施。通过理论计算与示波器验证,确保了PWM信号的精确性和安全性。下一讲将在此基础上,实现与PWM同步的电流采样,向完整的电机控制系统迈出关键一步。
版权声明:
youcans@qq 原创作品,转载必须标注原文链接:(https://blog.csdn.net/youcans/article/details/157326354)
Copyright@youcans 2026
Crated:2026-1