CIU32 TIM — TIM3 PWM 输出

CIU32 CIU32F003_STDLib V1.0.3 TIM3 双通道 PWM 输出示例教学

TIM — TIM3 PWM 输出(TIM3_PWMOutput)

固件库: CIU32F003_STDLib V1.0.3 芯片: CIU32F003(Cortex-M0) 源文件: CIU32/CIU32F003_STDLib_V1.0.3/Projects/TIM/TIM3_PWMOutput/Source/


一、功能简介

本示例用 TIM3 输出 2 路 PWM 波形:通道 CH1 接 PA5、通道 CH2 接 PA4, 均工作在 16 位计数精度下。两路占空比分别设为约 50% 与 37.5%, 可直接用示波器观察,也可接 LED 看亮度差异、接蜂鸣器听音调。

二、硬件准备

  • CIU32F003 开发板
  • 示波器 / 逻辑分析仪(观察 PA4、PA5)
  • 或把 PA4/PA5 接 LED(串限流电阻)观察亮度
  • 引脚映射:
TIM3 信号 引脚 复用
CH1 PA5 AF3_TIM3
CH2 PA4 AF3_TIM3

三、完整代码

3.1 主流程 main.c

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#include "main.h"

int main(void)
{
    system_clock_config();   /* 系统时钟 RCH 48MHz */
    gpio_init();             /* PA4/PA5 映射为 TIM3 复用 */
    tim3_init();             /* 配置定时器与 PWM 通道 */
    std_tim_enable(TIM3);    /* 启动计数,开始输出 PWM */

    while (1) { }
}

3.2 引脚与定时器初始化 common.c

 1
 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
#define TIM_PERIOD_VALUE    (0xFFFFU)                    /* ARR = 65535,16 位精度 */
#define TIM_PRESCALER_VALUE (0x03U)                     /* 预分频值 */
#define TIM_PULSE1_VALUE    (uint32_t)(TIM_PERIOD_VALUE / 2)            /* CH1 比较值 ≈ 50% */
#define TIM_PULSE2_VALUE    (uint32_t)(TIM_PERIOD_VALUE * 37.5 / 100)   /* CH2 比较值 ≈ 37.5% */

/* GPIO:PA4/PA5 复用为 TIM3 通道 */
void gpio_init(void)
{
    std_gpio_init_t tim3_gpio_init = {0};
    std_rcc_gpio_clk_enable(RCC_PERIPH_CLK_GPIOA);

    tim3_gpio_init.pin       = GPIO_PIN_4 | GPIO_PIN_5;
    tim3_gpio_init.mode      = GPIO_MODE_ALTERNATE;
    tim3_gpio_init.pull      = GPIO_NOPULL;
    tim3_gpio_init.alternate = GPIO_AF3_TIM3;   /* 复用功能 3 = TIM3 */
    std_gpio_init(GPIOA, &tim3_gpio_init);
}

/* TIM3 初始化:基础参数 + 两路 PWM 输出 */
void tim3_init(void)
{
    std_tim_basic_init_t           basic_init_struct = {0};
    std_tim_output_compare_init_t  oc_config_struct = {0};

    std_rcc_apb1_clk_enable(RCC_PERIPH_CLK_TIM3);  /* 使能 TIM3 时钟(在 APB1) */

    /* ① 基础计数参数 */
    basic_init_struct.prescaler  = TIM_PRESCALER_VALUE;  /* 预分频:分频计数时钟 */
    basic_init_struct.period     = TIM_PERIOD_VALUE;     /* ARR:计数到 0xFFFF 溢出 */
    basic_init_struct.clock_div  = TIM_CLOCK_DTS_DIV1;   /* 时钟分频(死区滤波用) */
    std_tim_init(TIM3, &basic_init_struct);

    /* ② 通道 1:PWM1 模式,高电平有效,占空比 ≈ 50% */
    oc_config_struct.output_compare_mode = TIM_OUTPUT_MODE_PWM1;
    oc_config_struct.output_pol         = TIM_OUTPUT_POL_HIGH;
    oc_config_struct.pulse             = TIM_PULSE1_VALUE;
    oc_config_struct.output_state       = TIM_OUTPUT_ENABLE;
    std_tim_output_compare_init(TIM3, &oc_config_struct, TIM_CHANNEL_1);

    /* ③ 通道 2:同样 PWM1,占空比 ≈ 37.5% */
    oc_config_struct.pulse = TIM_PULSE2_VALUE;
    std_tim_output_compare_init(TIM3, &oc_config_struct, TIM_CHANNEL_2);
}

四、代码分段讲解

① 基础计数参数

  • period(ARR)= 0xFFFF = 65535:计数器从 0 累加到 65535 后归零,决定 PWM 周期;
  • prescaler:对 TIM3 的输入时钟做分频,得到“计数时钟”。Period 与 Prescaler 共同决定 PWM 频率: PWM 频率 = TIM3计数时钟 / (ARR + 1)。

② PWM 模式 本例用 PWM1 模式 + 高电平有效(POL_HIGH):

  • 计数器 < CCR(比较值)时,输出高;
  • 计数器 ≥ CCR 时,输出低。 因此 占空比 ≈ CCR / (ARR + 1)。

③ 两路占空比

  • CH1:pulse = 0xFFFF/2,占空比 ≈ 50%;
  • CH2:pulse = 0xFFFF * 37.5%,占空比 ≈ 37.5%。

想调占空比,只需改 pulse(比较值);想调频率,改 period 或 prescaler。

④ 启动输出 std_tim_enable(TIM3) 让计数器开始跑,PWM 随即从引脚输出,之后主循环空转即可。

五、实验现象

  • 用示波器看 PA5:占空比约 50% 的方波;
  • 看 PA4:占空比约 37.5% 的方波;
  • 两路频率相同,仅高电平时间不同;
  • 接 LED 时,PA5 比 PA4 更亮(占空比更大)。

六、常见问题

现象 可能原因 解决办法
引脚没波形 复用功能选错 确认 alternate = GPIO_AF3_TIM3(TIM3 对应 AF3)
频率与预期不符 没算清预分频 频率 = 计数时钟 /(ARR+1),计数时钟受 prescaler 影响
占空比反了 极性设反 把 output_pol 改为 TIM_OUTPUT_POL_LOW 反转
改占空比无效 没在使能后更新 运行中改 CCR 需配合影子寄存器/事件更新(本例初始化即定)

七、小结

PWM 输出三要素:ARR 定周期、CCR(pulse) 定占空比、极性定高低电平对应关系。 流程:开 TIM 时钟 → 配引脚为对应 AF → 配基础计数参数 → 配每路 OC 为 PWM → 使能定时器。 记住占空比公式 CCR/(ARR+1),调光调速都靠它。

八、拓展应用

  • LED 呼吸灯:在定时器中断/主循环里缓慢改变 pulse;
  • 电机调速:PWM 接 MOSFET/驱动芯片控制平均电压;
  • 测频率/占空比:用输入捕获(TIM3_InputCapture / TIM3_PWMInput);
  • 无刷电机:TIM1 互补输出 + 死区(TIM1_ComplementarySignals)。
世界是你们
使用 Hugo 构建
主题 Stack 由 Jimmy 设计