PWM实验理论部分
135.5.7PWM实验理论部分
/*
* 整体目的:配置 TIM3 的两个硬件 PWM 通道,为后续呼吸灯和电机调速实验提供相同频率的波形。
* 参数依据:TIM3CLK=72 MHz,PSC=7199、ARR=99,因此 PWM 频率为
* 72 MHz / [(7199+1)×(99+1)] = 100 Hz,占空比分辨率约为 1%。
* 引脚依据:TIM3 部分重映射后,CH1 位于 PB4、CH2 位于 PB5;
* PB4 原本还承担 JTAG/NJTRST,工程需释放 JTAG 并保留 SWD。
* 代码范围:摘自 CubeIDE/07PWM 的 tim.c,HAL PWM 库函数内部不逐行展开。
*/
#include "tim.h" /* 引入 TIM 句柄、配置结构体、通道宏及初始化函数声明。 */
TIM_HandleTypeDef htim3; /* 定义 TIM3 句柄,两个 PWM 通道共享同一计数器时基。 */
void MX_TIM3_Init(void) /* 配置 TIM3 的时基、PWM 模式和两个输出通道。 */
{ /* TIM3 初始化函数体开始。 */
TIM_ClockConfigTypeDef sClockSourceConfig = {0}; /* 清零时钟源配置结构体。 */
TIM_MasterConfigTypeDef sMasterConfig = {0}; /* 清零主模式配置结构体。 */
TIM_OC_InitTypeDef sConfigOC = {0}; /* 清零输出比较/PWM 通道配置结构体。 */
htim3.Instance = TIM3; /* 让句柄指向 APB1 上的 TIM3 寄存器块。 */
htim3.Init.Prescaler = 7199U; /* 实际 7200 分频,将 72 MHz 变为 10 kHz 计数时钟。 */
htim3.Init.CounterMode = TIM_COUNTERMODE_UP; /* 让 CNT 从 0 向 ARR 递增。 */
htim3.Init.Period = 99U; /* ARR=99,一个 PWM 周期包含 100 个计数节拍。 */
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; /* 不额外分频数字滤波采样时钟。 */
htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; /* ARR 在更新边界装载。 */
if (HAL_TIM_Base_Init(&htim3) != HAL_OK) /* 配置 TIM3 基础时基并准备底层时钟。 */
{ /* 基础初始化失败分支开始。 */
Error_Handler(); /* 失败时进入统一错误处理。 */
} /* 基础初始化结果判断结束。 */
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; /* 选择芯片内部时钟树作为计数源。 */
if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK) /* 应用内部时钟源。 */
{ /* 时钟源配置失败分支开始。 */
Error_Handler(); /* 配置失败时停止正常业务。 */
} /* 时钟源配置结果判断结束。 */
if (HAL_TIM_PWM_Init(&htim3) != HAL_OK) /* 初始化 TIM3 的 PWM 功能状态。 */
{ /* PWM 初始化失败分支开始。 */
Error_Handler(); /* 失败时进入错误处理。 */
} /* PWM 初始化结果判断结束。 */
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; /* 不输出 TRGO 去触发其他外设。 */
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; /* 不使用定时器主从同步。 */
if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK) /* 应用主模式配置。 */
{ /* 主模式配置失败分支开始。 */
Error_Handler(); /* 失败时停止运行。 */
} /* 主模式配置结果判断结束。 */
sConfigOC.OCMode = TIM_OCMODE_PWM1; /* 选择 PWM 模式 1:向上计数时 CNT<CCR 为有效。 */
sConfigOC.Pulse = 0U; /* 初始 CCR 为 0,启动后先输出 0% 高有效占空比。 */
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; /* 通道参考有效时输出高电平。 */
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; /* 关闭快速模式,使用常规比较更新行为。 */
if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1) != HAL_OK) /* 配置 CH1。 */
{ /* 通道 1 配置失败分支开始。 */
Error_Handler(); /* 配置失败时进入错误处理。 */
} /* 通道 1 配置结果判断结束。 */
if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_2) != HAL_OK) /* 同参数配置 CH2。 */
{ /* 通道 2 配置失败分支开始。 */
Error_Handler(); /* 配置失败时进入错误处理。 */
} /* 通道 2 配置结果判断结束。 */
HAL_TIM_MspPostInit(&htim3); /* 最后配置 PWM 通道实际使用的 GPIO 复用功能。 */
} /* TIM3 初始化函数结束;此时通道尚未启动。 */
void HAL_TIM_MspPostInit( /* CubeMX 生成的定时器通道 GPIO 后初始化。 */
TIM_HandleTypeDef *timHandle) /* 参数指出需要配置哪一个定时器的引脚。 */
{ /* GPIO 后初始化函数体开始。 */
GPIO_InitTypeDef GPIO_InitStruct = {0}; /* 清零 GPIO 配置结构体。 */
if (timHandle->Instance == TIM3) /* 只在处理 TIM3 时配置 PB4、PB5。 */
{ /* TIM3 GPIO 分支开始。 */
__HAL_RCC_GPIOB_CLK_ENABLE(); /* 开启 GPIOB 时钟。 */
GPIO_InitStruct.Pin = GPIO_PIN_4 | GPIO_PIN_5; /* 同时选择 PB4 和 PB5。 */
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; /* 设置为由定时器驱动的复用推挽输出。 */
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; /* 100 Hz PWM 不需要高速 GPIO 边沿。 */
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); /* 将配置写入 PB4、PB5。 */
__HAL_AFIO_REMAP_TIM3_PARTIAL(); /* 启用 TIM3 部分重映射:CH1→PB4、CH2→PB5。 */
} /* TIM3 GPIO 分支结束。 */
} /* GPIO 后初始化函数结束。 */
一、PWM实验理论部分
1.1 实验演示
实验用同一类 PWM 信号控制 LED 亮度和直流电机转速。示波器上看到的是高低电平快速切换;负载由于视觉暂留、机械惯性或电路滤波,表现为与平均能量有关的连续效果。
PWM 要同时看两个独立参数:
- 频率决定一个周期有多快;
- 占空比决定一个周期内有效电平持续多久。
改变占空比不等于改变频率。电机是否安静、舵机能否识别、LED 是否闪烁,都可能受频率影响。
1.2 什么是PWM
1.2.1 脉宽调制技术
PWM 即脉宽调制。周期为 T,频率为 f=1/T,高电平时间为 tH,高电平占空比为:
D = tH / T × 100%
例如 100 Hz 的 PWM 周期是 10 ms;若高电平持续 3 ms,则高电平占空比为 30%。对高电平有效的负载,理想平均电压近似为 D×VCC,但电机电流、转矩和转速还会受到线圈电感、反电动势、负载与驱动器压降影响,不能把占空比直接等同于实际转速百分比。
1.2.2 单片机PWM信号的生成
1.2.2.1 新建工程
工程选用 STM32F103ZET6,并把系统时钟配置为 72 MHz。TIM3 用于两路 PWM,TIM4 的一路 PWM 后续用于舵机。生成工程前应确认时钟树,因为定时器输入时钟会直接影响 PWM 频率。
资源较少的 51 单片机也能用定时中断配合 GPIO 翻转生成 PWM,但中断延迟和其他任务会影响波形。STM32 的定时器含硬件输出比较单元,CPU 配置 PSC、ARR、CCR 和输出模式后,外设可持续生成 PWM,主循环不必在每个边沿手动翻转引脚。
1.2.2.2 设备配置
本实验把 TIM3_CH1、TIM3_CH2 配到 PB4、PB5。STM32F1 并不是任意引脚都能连接任意定时器通道;TIM3 使用部分重映射后才得到:
TIM3_CH1 ──部分重映射──> PB4
TIM3_CH2 ──部分重映射──> PB5
PB4 还与 JTAG 的 NJTRST 功能复用。需要使用 PB4 时,应关闭 JTAG、保留 SWD,以免引脚冲突,同时仍能通过 SWD 调试。
1.2.2.3 STM32原理图
开发板 LED 的典型连接是 3.3 V 经 LED 和 1 kΩ 限流电阻接到 PB5,因此它是低电平点亮:
3.3 V ──>|── 1 kΩ ── PB5
LED
PB5输出低电平:电流从3.3 V流向PB5,LED亮
PB5输出高电平:两端压差很小,LED灭
这会造成一个容易忽略的“反相”现象:TIM3 PWM1、有效高电平时,CCR 越大,高电平比例越大,但 LED 的导通低电平比例反而越小,所以 LED 会变暗。
直流电机绝不能直接接 GPIO。GPIO 既不能提供足够电流,也承受不了电机线圈断流产生的感应电压。常见驱动连接如下:
STM32 PWM ──> ENA/ENB 外部电机电源
STM32 GPIO ─> IN1/IN2 │
STM32 GND ───────────────┐ ┌───┴────┐
└───┤ H桥模块├── 电机
└────────┘
ENA/ENB 接 PWM 调速,IN1/IN2 决定电流方向。STM32、驱动模块与电机电源必须共地。H 桥模块负责大电流开关和感性电流续流;实际使用还要检查驱动芯片电流能力、散热和导通压降。
1.2.2.4 定时器的配置
TIM3 配置为 PSC=7199、ARR=99。在 72 MHz 定时器时钟下:
计数频率 fCNT = 72 MHz / (7199+1) = 10 kHz
计数分辨率 = 1 / 10 kHz = 100 μs
PWM频率 = 10 kHz / (99+1) = 100 Hz
PWM周期 = 10 ms
ARR 为 99 表示计数器共有 0~99 这 100 个计数状态,因此占空比可按 1% 步进调整。
1.2.3 定时器的理论
向上计数、PWM 模式 1、输出高电平有效时,可以近似理解为:
CNT < CCR → 有效
CNT ≥ CCR → 无效
高电平占空比 ≈ CCR / (ARR+1)
OCPolarity 还能反转通道引脚的有效电平,因此分析实际负载时,要按“比较模式 → 输出极性 → 外部电路是否反相”三层逐步判断。
1.2.3.1 比较值举例
当 ARR=99、CCR=30 时,计数值 0~29 共 30 个计数为有效状态,所以高电平占空比是 30%,不是 29%。
CNT: 0 ........ 29 | 30 ................ 99
PWM: ─── 有效 ────┘└────── 无效 ─────────
<---30格---> <---------70格---------->
若该信号直接送入高电平有效的电机驱动使能端,驱动占空比约为 30%;若送到板载低电平点亮 LED,LED 导通占空比约为 70%。同一个波形面对不同外部电路,会呈现相反的控制方向。