news 2026/10/16 3:08:22

【STM32C5教程】(7)TIM1 互补 PWM 输出实验

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【STM32C5教程】(7)TIM1 互补 PWM 输出实验

欢迎关注 youcans@xidian【嵌入式软件AI编程】专栏
【STM32C5教程】(2)STM32CubeMX2 安装与STM32C5闪灯
【STM32C5教程】(4)GPIO 外部中断实验
【STM32C5教程】(5)定时器周期中断实验
【STM32C5教程】(6)定时器 PWM 输出实验
【STM32C5教程】(7)TIM1 互补 PWM 输出实验


1. 项目简介

1.1 实验目标

本实验在 NUCLEO-C542RC 开发板上,使用 STM32C542RCT6 的高级定时器 TIM1 的 CH1/CH1N 通道,通过 PA8 和 PB13 输出频率为 10 kHz、占空比为 50%、死区时间约为 500 ns 的互补 PWM 信号。

功能需求:

  • 使用 TIM1 的 CH1(PA8)和 CH1N(PB13)输出互补 PWM 信号
  • PWM 频率 10 kHz
  • 占空比 50%
  • 死区时间约 500 ns

开发板和 MCU 型号:NUCLEO-C542RC 开发板,搭载 STM32C542RCT6 MCU。

什互补 PWM?两路信号呈互补关系:一路为高电平时,另一路为低电平。这种信号常用于半桥/全桥电机驱动电路,互补的两路分别驱动上下两个开关管。在切换边沿插入“死区时间”——两路都保持低电平的一小段空白——可以确保上下管不会同时导通,避免直通短路。


1.2 实验条件

硬件:

  • NUCLEO-C542RC 开发板
  • 支持数据传输的 USB Type-C 线(用于连接 ST-LINK 接口)
  • 示波器(用于观测 PA8 与 PB13 的输出波形)

软件:

  • STM32CubeMX2(用于引脚、时钟配置与代码生成)
  • VS Code + STM32Cube 插件(用于编译、烧录、调试)

2. 硬件说明

2.1 NUCLEO-C542RC 开发板

NUCLEO-C542RC 是 ST 基于 STM32C542RCT6 推出的 Nucleo-64 开发板。主要特性:

  • MCU:STM32C542RCT6,Arm Cortex-M33 内核,最高主频 144 MHz,256 KB Flash,64 KB RAM
  • 调试器:板载 STLINK-V3EC,支持大容量存储、虚拟串口和调试端口三种功能
  • 用户 LED:LD1,连接 PA5
  • 用户按键:B1,连接 PC13
  • 复位按键:B2
  • 扩展接口:Arduino Uno V3 和 ST morpho 连接器

本实验使用 PA8 和 PB13 输出 PWM,通过示波器观测,不使用板载 LED 或按键。


2.2 引脚说明

引脚复用功能说明
PA8TIM1_CH1互补 PWM 的主通道
PB13TIM1_CH1N互补 PWM 的互补通道

PA8(TIM1_CH1):配置为复用功能(AF1)、推挽输出,由 TIM1 通道 1 输出 PWM 波形。

PB13(TIM1_CH1N):配置为复用功能(AF1)、推挽输出,由 TIM1 通道 1 的互补通道输出互补 PWM 波形。


3. STM32CubeMX2 工程配置

3.1 新建工程

本实验采用 MCU 方式创建工程,即以芯片型号 STM32C542RC 为起点,而非开发板方式。

  1. 进入 MCU 选择界面
    启动 STM32CubeMX2,在首页点击 MCU,进入芯片型号选择列表。

  2. 搜索并选中芯片
    在 MCU name 输入框中输入 STM32C542RC(或完整型号 STM32C542RCT6),从筛选出的列表中选择对应型号。

  1. 填写项目信息
    输入项目名称 TIM1_PWM_Comp 和项目保存路径。项目名称避免使用特殊字符,路径建议使用纯英文目录。

3.2 基础配置

工程创建后,软件自动进入 Pinout 视图。

时钟配置:本工程系统时钟配置为144 MHz,APB1 分频系数为 1,TIM1 输入时钟为144 MHz。


3.3 TIM1 配置

(1)配置 TIM1 通道 1 为 PWM Generation

在左侧外设列表中找到Timers→TIM1,点击展开。在Mode区域中,将Channel1设置为PWM Generation CH1 CH1N。

设置完成后,Pinout 视图中PA8自动分配为TIM1_CH1,PB13自动分配为TIM1_CH1N。

(2)配置定时参数

在 TIM1 的Parameter Settings中设置:

参数值说明
Prescaler (PSC)11144 MHz ÷ 12 = 12 MHz
Counter ModeUp向上计数
Counter Period (ARR)119912 MHz ÷ 1200 = 10 kHz
auto-reload preloadEnable建议启用

PWM 频率计算:

PWM 频率=TIM1时钟 /((PSC+1)×(ARR+1))=144,000,000 /((11+1)×(1199+1))=144,000,000 /(12×1200)=10,000Hz=10kHz

(3)配置 PWM 通道

在Channel1的配置区域中:

参数值说明
ModePWM1PWM 模式 1
Pulse (CCR1)600占空比 50%
Output compare preloadEnable使能比较预装载
CH PolarityHigh通道极性为高
CHN PolarityHigh互补通道极性为高

占空比计算:

占空比=Pulse /(ARR +1)=Pulse /100

占空比 = Pulse / (ARR + 1) = 600 / 1200 = 50%

(4)配置死区时间

切换到Break and Dead Time management标签页,配置死区:

参数值说明
Dead Time72死区计数
Automatic Output StateDisableMOE 由软件启动
Off State Run ModeDisable—
Off State Idle ModeDisable—

死区时间计算:

DTS 时钟=TIM1 时钟 / DTS 分频=144MHz /1=144MHz 死区时间=Dead Time 值 / DTS=72/144MHz=0.5µs=500ns

(5)确认引脚配置

回到 Pinout 视图,PA8 应显示为TIM1_CH1,PB13 应显示为TIM1_CH1N。


3.4 项目配置

  1. 点击Project Settings,进入工程设置页面。
  2. 在IDE Format下拉选项中选择CMake。
  3. 在CMake Toolchain下拉选项中选择GCC。
  4. 确认配置无误后,点击Generate Code。CubeMX2 会执行配置检查,如果没有错误,开始在指定路径下生成 CMake 工程文件。
  5. 生成完成后,项目路径下会出现标准 CMake 工程结构,包含Core/、Drivers/、CMakeLists.txt等。


4. 编程实现

4.1 实现思路

采用“TIM1 硬件互补 PWM + 软件启动通道和计数器”的方案:

mx_tim1_init()// CubeMX2 生成:10 kHz 时基、PWM1 模式、CH1/CH1N、│// PA8/PB13 复用、死区 500 ns│ ▼HAL_TIM_OC_StartChannel(htim1,HAL_TIM_CHANNEL_1)// 启动 CH1,使能 CC1 和 MOE│ ▼HAL_TIM_OC_StartChannel(htim1,HAL_TIM_CHANNEL_1N)// 启动 CH1N│ ▼HAL_TIM_Start(htim1)// 启动计数器,PWM 开始输出│ ▼ 主循环空闲:PWM 由硬件持续输出

两步启动CubeMX2 中Automatic Output State 设为 Disable,意味着主输出使能位(MOE)不会自动开启。MOE 必须由软件显式使能,否则 PA8 和 PB13 引脚一直无波形输出。HAL_TIM_OC_StartChannel()在启动通道的同时会打开 MOE,HAL_TIM_Start()则启动计数器。两者缺一不可。

先启动通道、后启动计数器的原因:让 MOE 先就位,计数器一开始走就能输出稳定波形,避免启动瞬间多出一个毛刺脉冲。

HAL2 与 HAL1 的差异:经典 HAL1 中使用单个函数HAL_TIM_PWM_Start()启动 PWM;CubeMX2 的 HAL2 改为两个函数分开操作——HAL_TIM_OC_StartChannel()启动输出通道,HAL_TIM_Start()启动计数器。

各步骤使用的 HAL 函数:

步骤HAL 函数作用
获取 TIM1 句柄mx_tim1_gethandle()返回 CubeMX 生成的 TIM1 句柄
启动输出通道HAL_TIM_OC_StartChannel()使能通道并开启 MOE
启动计数器HAL_TIM_Start()启动 TIM1 计数,PWM 开始输出

4.2 关键代码

在 VS Code 中打开生成的 CMake 工程,找到Core/Src/main.c,添加以下代码。

(1)文件头部添加头文件

#include"main.h"#include"mx_tim1.h"

(2)主函数

intmain(void){if(mx_system_init()!=SYSTEM_OK){return(-1);}else{/* * You can start your application code here *//* TIM1_CH1 (PA8) and TIM1_CH1N (PB13) complementary PWM, deadtime * already configured by mx_tim1_init() (500 ns). The timer is * initialized but the counter and the output channels are not yet started. */hal_tim_handle_t*htim1=mx_tim1_gethandle();/* Start the output channels: enables CC1/CC1N and the main output MOE. */if(HAL_TIM_OC_StartChannel(htim1,HAL_TIM_CHANNEL_1)!=HAL_OK){return(-1);}if(HAL_TIM_OC_StartChannel(htim1,HAL_TIM_CHANNEL_1N)!=HAL_OK){return(-1);}/* Start the TIM1 counter to generate the PWM at 10 kHz/50% duty. */if(HAL_TIM_Start(htim1)!=HAL_OK){return(-1);}while(1){}}}

代码说明:

  • mx_tim1_gethandle() 返回 CubeMX2 生成的 TIM1 句柄。
  • HAL_TIM_OC_StartChannel(htim1, HAL_TIM_CHANNEL_1) 启动主通道 CH1(PA8),同时使能主输出 MOE。
  • HAL_TIM_OC_StartChannel(htim1, HAL_TIM_CHANNEL_1N) 启动互补通道 CH1N(PB13)。
  • HAL_TIM_Start(htim1) 启动 TIM1 计数器。前两步只使能输出,不启动计数;第三步才真正开始产生 PWM。
  • 频率、占空比、死区等参数已在 mx_tim1_init() 中配置完成,main.c 无需重新设置。。


5. 编译烧录与运行测试

5.1 编译与烧录

  1. 打开工程:用 VS Code 打开 CubeMX2 生成的 CMake 工程文件夹(如 TIM1_PWM_Comp_cmake)。
  2. 编译:点击 VS Code 底部状态栏的Build按钮,或使用命令面板执行 CMake 构建。编译完成后,终端应输出Build finished with exit code 0,无 error。
  3. 连接开发板:用支持数据传输的 USB Type-C 线连接 NUCLEO-C542RC 的 ST-LINK USB 口(CN1)。
  4. 确认设备识别:打开设备管理器,在“端口 (COM 和 LPT)”下应能看到STLink COMx。
  5. 烧录:点击 VS Code 中的运行按钮,将固件下载到开发板。


5.2 运行与测试

烧录完成后,程序自动开始运行。用示波器两通道分别测量 PA8 和 PB13,观察波形:

  • 测试 1:频率
    两路信号频率均为 10 kHz,周期 100 µs。

  • 测试 2:互补关系
    CH1(PA8)与 CH1N(PB13)呈互补关系:当 PA8 为高电平时,PB13 为低电平;反之亦然。

  • 测试 3:占空比
    两路信号的占空比均约 50%。

  • 测试 4:死区时间
    在两路信号切换边沿处,可以观察到明显的死区间隔——两路同时为低电平的一段空白时间,约 500 ns。

测试结果:
☑ 编译通过,无错误
☑ 烧录成功
☑ 两路 PWM 频率均为 10 kHz
☑ 两路呈互补关系
☑ 两路占空比均约 50%
☑ 切换边沿处死区时间约 500 ns
功能正常。


6. 小结

本实验通过 TIM1 的互补 PWM 输出实现了两路 10 kHz、50% 占空比、500 ns 死区的互补信号输出,掌握了 STM32C5 系列高级定时器互补 PWM 与死区时间的配置与使用方法。

核心逻辑可以概括为:“TIM1 硬件产生互补 PWM → 软件启动通道与计数器 → 输出带死区的互补波形”。

有两点需要注意:

第一,主输出 MOE 必须由软件使能。 CubeMX2 中 Automatic Output State 设为 Disable,意味着不会自动开启 MOE。必须调用 HAL_TIM_OC_StartChannel() 才能打开主输出,否则 PA8 和 PB13 一直无波形。

第二,启动 PWM 分两步。 先调用两次 HAL_TIM_OC_StartChannel() 启动 CH1 和 CH1N 两个通道,再调用 HAL_TIM_Start() 启动计数器。两步都完成后 PWM 才真正输出。

死区时间是互补 PWM 的核心参数,由 DTS 采样时钟和 Dead Time 寄存器的值共同决定。本实验取 DTS = 144 MHz、Dead Time = 72,得到 500 ns 的死区。如需调整,可按公式 死区 = Dead Time / DTS 反推。


版权声明:

欢迎关注 youcans@xidian【嵌入式软件AI编程】专栏
转发必须注明原文链接:
【STM32C5教程】(7)TIM1 互补 PWM 输出实验
Copyright by ai4mcu@qq.com 2026
Crated:2026-10

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/16 3:08:06

C++互斥锁学习

使用目的:保护共享资源,防止多线程并发读写造成数据错乱基础概念:临界区:多线程会访问共享变量的那段代码竞态:多个线程并发访问共享数据,至少有一个线程是写操作;最终结果取决于线程调度的先后…

作者头像 李华
网站建设 2026/10/16 3:08:04

第 6 篇 IOMMU 的基本职能:地址翻译与设备隔离

本文属于第二册“IOMMU:地址翻译与隔离的硬件机制及内核管理”,回答第 0 篇提出的问题 6:IOMMU 如何同时解决物理连续性、寻址范围与设备隔离三个问题?其内部的地址翻译过程是怎样的? 第 5 篇第 6 节指出,…

作者头像 李华
网站建设 2026/10/16 3:07:23

Halcon 数组操作(Tuple)详解与算子说明

Halcon 数组操作(Tuple)详解与算子说明 适用版本:Halcon 17.12(算子名、签名、默认值、取值范围均严格对照本地官方文档 D:/Soft/WorkSoft/Halcon17/doc/html/reference/operators/) 本文档覆盖 Halcon 17.12 Tuple / 数组操作全部 121 个官方算子,共 13 个官方分类。 一…

作者头像 李华
网站建设 2026/10/16 3:06:01

Git本地开发操作指南

目录 一,预备 1.1 Git 介绍 1.2 Git 下载安装 二,Git基本操作 2.1 创建并配置本地仓库 2.2 工作区、暂存区、版本库 2.3 添加文件 2.4 修改文件 2.5 版本回退 2.6 撤销修改 2.7 删除文件 三,分支管理 3.1 关于分支 3.2 分支操作…

作者头像 李华