14.3 高级定时器项目:PWM互补输出实验
# 14.3 高级定时器项目:PWM互补输出实验
本实验通过STM32的高级定时器TIM1生成带死区时间的互补PWM信号,结合示波器验证波形参数,并通过OLED实时显示中断计数。
核心功能:
- 互补PWM输出:TIM1_CH1(PA8)与TIM1_CH1N(PB13)输出互补信号。
- 死区时间控制:避免上下桥臂直通,确保电路安全。
- 频率与占空比调节:PWM频率150kHz,占空比可调。
# 14.3.1 STM32CubeMX配置
# 1. 建立新工程
- 芯片型号:STM32F103C8T6;
- 项目命名:14 TIM_PWMN ;
- 主频:72MHz ;
- 调试接口:SWD。
# 2. 配置TIM1
# 1. 使能TIM1互补输出通道
①点击“Pinout & Configuration”标签页→②在左侧导航栏中点击“Timers”→③双击“TIM1”进行配置→④选择“Clock Source”为“Internal Clock”→⑤选择“Channle1”为“PWM Generation CH1 CH1N”→⑥将自动配置的“TIM1_CH1N”配置为PB13引脚。

# 2. 配置TIM1工作参数
- PSC:0;
- Counter Mode:Up;
- ARR:480、Pulse:200;
- Internal Clcok Division:No Division;
- Repetition Counter:0;
- Auto-reload preload:Disable;
- 其他参数保持不变。

# 3. 配置死区时间管理参数
- BRK State(刹车输入状态):Disable;
- Automatic Output State(自动输出状态):Disable、OSSR:Disable;
- OSSI:Disable;
- lock configuratio(写保护配置)Off;
- Dead Time(死区时间):43。

# 4. 配置I2C1
# 5. 引脚分配与复用
- PA8自动配置为TIM1_CH1;
- PB13配置为TIM1_CH1N;
- PB9配置为I2C1_SDA;
- PB8配置为I2C1_SCL;
- 若引脚未自动分配或分配到其他引脚,需手动点击选择功能。

# 6. 生成代码
参考第4章,在“Project Manager”标签页中的“Code Generator”导航栏,勾选为每个外设生成单独的“.c”和“.h”文件的选项。 最后,点击“Project→Generate Code”或工具栏的齿轮图标,再或者按下“Ctrl+S”快捷键保存,生成工程代码。在弹出的对话框中勾选“Open project”选项,即可进入代码编辑界面。经过上述的操作,STM32CubeIDE软件配置基本完成。
# 14.3.2 高级定时器项目软件设计
# 1. 初始化函数(代码清单14‑2)
static void MX_TIM1_Init(void)
{
// 定义并初始化定时器时钟配置结构体
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
// 定义并初始化定时器主模式配置结构体
TIM_MasterConfigTypeDef sMasterConfig = {0};
// 定义并初始化定时器输出比较配置结构体
TIM_OC_InitTypeDef sConfigOC = {0};
// 定义并初始化定时器断路和死区时间配置结构体
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
htim1.Instance = TIM1; // 配置TIM1定时器的实例
htim1.Init.Prescaler = 0; // 设置预分频器为0,表示时钟频率不分频
// 设置计数器模式为向上计数
htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
htim1.Init.Period = 480; // 设置自动重装载寄存器的值为480
// 设置时钟分频为不分频
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
// 设置重复计数器的值为0(用于高级定时器)
htim1.Init.RepetitionCounter = 0;
// 禁用自动重装载预装载功能
htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim1) != HAL_OK)
{
Error_Handler();
}// 初始化定时器基础配置,如果初始化失败则调用错误处理函数
// 配置定时器时钟源为内部时钟
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}// 应用时钟源配置,如果配置失败则调用错误处理函数
if (HAL_TIM_PWM_Init(&htim1) != HAL_OK)
{
Error_Handler();
}// 初始化定时器的PWM模式,如果初始化失败则调用错误处理函数
// 配置定时器的主模式,设置主输出触发为复位
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
// 禁用主从模式
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if(HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}// 应用主模式配置,如果配置失败则调用错误处理函数
sConfigOC.OCMode = TIM_OCMODE_PWM1; // 配置PWM模式为PWM模式1
sConfigOC.Pulse = 200; // 设置PWM的脉冲宽度为200
// 设置输出极性为高电平有效
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
// 设置互补输出极性为高电平有效
sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
// 禁用输出比较快速模式
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();
}// 配置TIM1的通道1为PWM输出,如果配置失败则调用错误处理函数
// 配置断路和死区时间
sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
// 禁用运行模式下的关闭状态
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
// 禁用空闲模式下的关闭状态
sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
// 禁用锁定级别
sBreakDeadTimeConfig.DeadTime = 43; // 设置死区时间为43个时钟周期
sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
// 禁用断路功能
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH; // 设置断路极性为高电平有效
sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE; // 禁用自动输出功能
if(HAL_TIMEx_ConfigBreakDeadTime(&htim1,
&sBreakDeadTimeConfig) != HAL_OK)
{
Error_Handler();
}// 应用断路和死区时间配置,如果配置失败则调用错误处理函数
// 初始化定时器的MSP(MCU Specific Package)后处理
HAL_TIM_MspPostInit(&htim1);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# 2. 主函数代码(代码清单14‑3)
在main函数的while(1)主循环前,通过HAL_TIM_Base_Start_IT( )启动TIM1的定时器中断,使用HAL_TIM_PWM_Start( )和HAL_TIMEx_PWMN_Start( )启动TIM1的PWM和PWMN输出。主循环中,程序不断调用OLED_NewFrame( )、OLED_PrintString( )和OLED_ShowFrame( )刷新OLED屏幕,显示指定字符串。
#include "font.h"
#include <stdio.h>
#include <string.h>
#include "oled.h"
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
MX_TIM1_Init();
MX_I2C1_Init();
HAL_Delay(20);
OLED_Init();
HAL_TIM_Base_Start_IT(&htim1);
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);
HAL_TIMEx_PWMN_Start(&htim1,TIM_CHANNEL_1);
while (1)
{
OLED_NewFrame();
OLED_PrintString(1,1, message, &font16x16, OLED_COLOR_NORMAL);
OLED_ShowFrame();
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 3. 中断回调函数(代码清单14‑4)
在定时器更新中断回调函数中,变量counter为中断回调函数执行的次数,用于初步判断定时器频率是否正确,若每隔一秒发送一次,则定时器频率正确。由于int型是16为数据,最大值为65535,这里定义变量要用long int型,其为32位数据。
/* USER CODE BEGIN 0 */
long int counter=0; //1s计数变量
int i=0;
char message[20];
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim == &htim1) //6.666us 150k
{
counter++;
if(counter==150000) //1s
{
counter=0;
sprintf(message,"i:%d",i++);
}
}
}
/* USER CODE END 0 */
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 14.3.3 高级定时器项目下载验证
# 现象与步骤
- 烧录程序:通过ST-LINK下载代码至开发板。
- 示波器观测:
- PA8(TIM1_CH1):PWM波形,频率149.7kHz。
- PB13(TIM1_CH1N):互补PWM波形,死区时间约600ns。
- OLED显示:每秒更新中断计数(如
Count: 5
)。
#

关键说明:
- 频率计算:
$$ f_{\text{PWM}} = \frac{\text{CLK}}{(\text{PSC}+1) \times (\text{ARR}+1)} = \frac{72 \times 10^6}{(0+1) \times (480+1)} \approx 149.7 , \text{kHz} $$ - 死区时间:43个时钟周期对应约0.597ns(72MHz时钟)。
- 应用场景:适用于电机驱动、半桥/全桥电路等需避免直通的场景。