STM32CubeMX中TIM定时器配置输出PWM方法

AI助手已提取文章相关产品:

STM32定时器与PWM技术:从配置到实战的深度解析

在嵌入式开发的世界里,如果你曾试图让一个LED“呼吸”起来,或者控制电机转得快一点、慢一点——那几乎可以肯定,你已经和 PWM(脉宽调制) 打过交道了。💡 它不是魔法,但用起来真的很像。

而当我们把目光投向STM32这个庞大的家族时,你会发现:它不仅支持PWM,还把它玩出了花儿来。无论是点亮一盏灯、驱动一台电机,还是构建复杂的三相逆变系统,背后都离不开那个默默工作的“时间管家”—— 定时器(Timer)

今天,我们就一起走进STM32的内部世界,揭开定时器如何通过硬件自动产生精准PWM波形的秘密,并手把手带你完成从CubeMX配置到实际应用的全过程。准备好了吗?🚀


为什么是定时器?因为时间就是一切 ⏱️

很多人初学STM32时会问:“我能不能直接用GPIO翻转来生成方波?”
当然可以!但问题在于——你能保证每次翻转都是精确的1ms吗?尤其是在主循环里还有其他任务的时候?

答案往往是:不能。

这时候, 通用定时器(General-Purpose Timer) 就登场了。它是独立于CPU运行的外设模块,靠自己的计数器+比较逻辑,在不需要任何软件干预的情况下,就能持续输出频率稳定、占空比可调的PWM信号。

听起来是不是有点像“自动驾驶”的波形发生器?没错,就是这么酷!

核心机制一句话讲清楚:

当前计数值 < CCR → 输出高电平
当前计数值 ≥ CCR → 输出低电平

这里的 CCR 是捕获/比较寄存器,决定了高电平持续多久;而 ARR (自动重装载值)则定义了一个完整周期有多少个计数步。整个过程由硬件自动完成,CPU只负责设置参数和启动开关。

// 启动TIM2通道1的PWM输出
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);

这行代码执行后,PA0脚就开始源源不断地输出预设的PWM波了,哪怕你的主程序正在处理蓝牙通信或显示菜单,也不会影响它的节奏。这就是 实时性与稳定性 的体现。


图形化配置神器:STM32CubeMX,小白也能上手 🧰

过去写单片机程序,要查数据手册、手动配置寄存器、计算分频系数……稍有不慎就出错。但现在?我们有了 STM32CubeMX —— ST官方推出的图形化初始化工具,简直是新手福音,老手也爱不释手。

它不仅能帮你自动生成初始化代码,还能实时验证时钟树是否超频、引脚有没有冲突,甚至能告诉你某个功能该接哪个GPIO。

接下来,我们就以 STM32F407VG 这款经典芯片为例,一步步演示如何用CubeMX搭建一个完整的PWM工程。


第一步:创建项目并选择MCU

打开STM32CubeMX,点击“New Project”,进入芯片选择界面。

🔍 在搜索框输入 F407 ,你会看到一堆型号。我们要选的是 STM32F407VGTx ,LQFP-100封装,主频高达168MHz,拥有多个定时器资源,非常适合做PWM实验。

属性
内核 Cortex-M4 @ 168MHz
Flash 1MB
RAM 192KB
定时器数量 14个(含高级定时器TIM1/TIM8)
PWM能力 多通道、多模式、支持互补输出

📌 特别提醒:别看只是后缀差了个字母,比如选成VC而不是VG,Flash容量可能直接减半!所以一定要对照原理图确认型号,否则后期烧录失败哭都来不及 😭

选定之后,Pinout视图立刻弹出,所有引脚状态一览无余。灰色表示未使用,绿色代表已分配功能,橙色则是警告(比如时钟没开)。这些颜色反馈非常直观,极大降低了配置错误的风险。


第二步:配置时钟系统 —— 精准波形的前提 🔁

时钟是整个系统的命脉。PWM的频率精度,完全取决于你给定时器喂了多少赫兹的“粮食”。

默认情况下,系统时钟来自内部RC振荡器(HSI ≈ 16MHz),便宜但不准。对于要求高的PWM应用,建议启用外部晶振(HSE),通常为8MHz或12MHz。

假设我们使用 8MHz HSE ,目标是达到 168MHz 主频 ,就需要借助锁相环(PLL)进行倍频:

HSE = 8 MHz  
→ PLL_M = 8 (分频至1MHz)  
→ PLL_N = 336 (倍频至336MHz)  
→ PLL_P = 2 (输出系统时钟 = 336 / 2 = 168 MHz)

这一切都可以在 Clock Configuration 页面中可视化操作。CubeMX还会自动帮你计算各总线频率,并对超出规格的部分标红提示。

重点来了👇:

虽然TIM2挂在APB1总线上(PCLK1 = 42MHz),但由于HAL库的特殊处理,其实际工作频率会被 翻倍为84MHz !这是因为在检测到APB预分频 ≠ 1 时,硬件自动将定时器时钟乘以2。

uint32_t uwTimclock = HAL_RCC_GetPCLK1Freq();
if (__HAL_RCC_GET_TIMCLKPRESCALER() == RCC_TIMPRES_ACTIVATED)
    uwTimclock *= 2; // 实际为84MHz!

⚠️ 如果你不了解这一点,按42MHz去算PSC值,结果出来的频率就会差两倍!这种“隐藏规则”坑过不少人,务必牢记。


第三步:启用定时器并配置PWM输出 🛠️

现在回到 Pinout & Configuration 视图,找到 TIM2,展开看看有哪些可用通道。

我们的目标是在 PA0 上输出PWM信号。先查一下数据手册或CubeMX映射表:PA0 是否支持 TIM2_CH1?

✅ 支持!那就单击PA0引脚 → 弹出菜单 → 选择 TIM2_CH1

此时引脚变绿,TIM2也被激活。接着检查GPIO配置是否正确:

参数 设置
Mode Alternate Function Push-Pull
Pull-up/down No pull
Speed High
AF Mapping AF1 (对应TIM2)

AF编号很重要,不同复用功能对应不同的外设连接。如果配错了AF,即使写了代码也没信号。

再切回 Clock Configuration 页面,确认 TIM2 的时钟来源是不是 84MHz 。如果不是,说明APB1时钟没开,或者TIM2没被使能。

一切就绪后,双击左侧的 TIM2,进入详细参数设置页。


第四步:关键参数设定 —— 频率与占空比的灵魂所在 🎯

在 Parameter Settings 中,我们需要设置以下几个核心参数:

参数 推荐值 说明
Counter Mode Up-counting 最常用模式
Clock Division CKD=0 不额外分频
Auto-reload Preload Enable 防止突变
Prescaler (PSC) 83 得到1MHz计数频率
Counter Period (ARR) 999 对应1kHz PWM频率
计算公式来了:

我们希望得到 1kHz 的PWM信号 ,即每秒1000个周期,每个周期1ms。

若想让计数器每微秒走一步(便于计算),就需要把84MHz降到1MHz:

PSC = (84,000,000 / 1,000,000) - 1 = 83

减1是因为PSC=0表示不分频。

然后设置ARR = 999,这样总共走1000步就是一个周期:

f_pwm = 1,000,000 Hz / (999 + 1) = 1kHz

完美!

最后,在 Channel1 区域选择 “PWM Generation CH1”,并将 Pulse(即CCR初值)设为250,初始占空比就是:

duty = 250 / 1000 = 25%

生成的初始化结构体长这样:

htim2.Instance = TIM2;
htim2.Init.Prescaler = 83;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 999;
htim2.Init.ClockDivision = 0;
if (HAL_TIM_PWM_Init(&htim2) != HAL_OK) {
    Error_Handler();
}

这段代码由CubeMX自动生成,确保参数合法且一致,省去了大量调试时间。


第五步:生成代码,编译下载,见证奇迹 ✨

点击 Project Manager → 设置工具链为 MDK-ARM 或 STM32CubeIDE → 填写工程名和路径(注意不要有中文或空格)→ Generate Code!

几秒钟后,完整的工程框架出炉:

  • main.c :主函数入口
  • tim.c/gpio.c :外设初始化函数
  • stm32f4xx_hal_msp.c :底层时钟与NVIC配置
  • 所有必要的头文件和源文件组织有序

只需要在 main() 函数中添加一句启动命令:

/* USER CODE BEGIN 2 */
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
/* USER CODE END 2 */

然后编译、下载、复位……拿起示波器探头,贴上PA0,你就能看到清晰的1kHz、25%占空比的方波跳出来了!🎉


实战验证:用示波器说话 📈

理论说得再好,不如亲眼所见来得实在。

如何测量PWM特性?

  1. 探头接地夹接GND;
  2. 探针接触PA0;
  3. 示波器设置:
    - 垂直:1V/div(适配3.3V电平)
    - 水平:500μs/div(方便观察1ms周期)
    - 耦合方式:DC(查看真实电压偏移)
    - 触发源:PA0,上升沿触发

光标法测量两个上升沿之间的时间差,若为1.002ms,则实际频率约为998Hz,误差仅0.2%,完全可以接受。

造成微小偏差的原因可能是:
- 外部晶振本身存在±10ppm误差
- 寄存器取整导致非理想分频
- 示波器采样算法插值误差

只要在合理范围内,都没问题。


动态调节占空比:真正的“活”信号 💬

静态PWM只能算是入门,真正的高手会让它“动”起来。

试试在主循环中动态修改CCR值:

uint16_t pulse = 0;
uint8_t dir = 1;

while (1) {
    __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, pulse);

    if (dir) pulse += 10;
    else     pulse -= 10;

    if (pulse >= 1000) { dir = 0; }
    if (pulse == 0)    { dir = 1; }

    HAL_Delay(50); // 每50ms变化一次
}

你会在示波器上看到高电平宽度逐渐拉长又缩短,形成类似“呼吸灯”的效果。这正是PWM最迷人的地方: 用数字的方式模拟模拟行为

CCR值 占空比 高电平时间
100 10% 100 μs
500 50% 500 μs
900 90% 900 μs

💡 提示:开启示波器的“单次触发”模式,冻结某一帧波形,配合自动测量功能,能快速读取频率、占空比、峰峰值等参数。


控制LED亮度:人人都能做的第一个项目 💡

PWM最经典的用途之一就是调光。

人眼对光强的变化具有积分效应,只要PWM频率高于80Hz,就不会察觉闪烁。一般建议使用 1kHz~10kHz 范围内的频率来做LED调光。

继续刚才的例子,我们将 pulse 映射为亮度等级:

uint16_t brightness = 0;
uint8_t increasing = 1;

while (1) {
    __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, brightness);

    HAL_Delay(10); // 控制渐变速率

    if (increasing) {
        brightness += 5;
        if (brightness >= 1000) increasing = 0;
    } else {
        brightness -= 5;
        if (brightness == 0) increasing = 1;
    }
}

调整 HAL_Delay() 的时间即可改变渐变速度:

延迟 效果 CPU占用
1ms 极快闪烁
10ms 平滑过渡
50ms 明显阶跃

🔧 更优方案:使用另一个定时器中断来更新亮度,避免阻塞主循环。这样系统还能同时响应按键、串口等事件,真正做到多任务并行。


加入按键控制:让用户参与进来 👆

没有人喜欢“固定模式”。加个按键,让用户自己调节亮度,才像个正经产品。

选用PC13作为按键输入,配置为 GPIO_EXTI13 模式,下降沿触发中断。

CubeMX自动生成中断服务函数框架,我们在 main.c 中补充回调函数:

volatile uint16_t user_duty = 500; // 初始50%

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
    if (GPIO_Pin == GPIO_PIN_13) {
        HAL_Delay(20); // 软件消抖

        if (HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13) == GPIO_PIN_RESET) {
            user_duty += 50;
            if (user_duty > 1000) user_duty = 0;
            __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, user_duty);
        }
    }
}

每按一次,占空比增加5%,到100%后归零,循环往复。

想要更人性化的体验?那就再加一个“减”键(比如PB5):

else if (GPIO_Pin == GPIO_PIN_5) {
    HAL_Delay(20);
    if (!HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_5)) {
        user_duty = (user_duty <= 50) ? 0 : (user_duty - 50);
        __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, user_duty);
    }
}
按键 功能 步长
PC13 增加 +50
PB5 减少 -50
维持 ——

🛠️ 常见问题排查:
- 按键无反应?检查NVIC是否开启EXTI中断。
- 多次误触发?加强消抖(软硬结合更好)。
- 引脚冲突?确认SWD/JTAG未占用GPIO。


驱动直流电机:PWM的大舞台 🚗

如果说LED是PWM的小试牛刀,那么 电机控制 才是它的主战场。

我们以常见的 L298N H桥模块 为例,实现PWM调速。

接线方式:

L298N引脚 连接对象 说明
IN1 MCU GPIO 控制方向
IN2 MCU GPIO 控制方向
ENA PA0 (TIM2_CH1) 接PWM信号
VCC 5V 逻辑电源
VS 7–12V 电机电源
OUT1/OUT2 电机两端 ——
GND 共地 必须共地!

⚠️ 安全提示:电机电源与MCU电源建议分开供电,但必须共地,防止干扰导致复位。

控制逻辑:

  • IN1=1, IN2=0 → 正转
  • IN1=0, IN2=1 → 反转
  • IN1=IN2=0 → 刹车
  • ENA 输入PWM → 调节速度

编写一个简单的速度控制函数:

void set_motor_speed(uint8_t level) {
    uint16_t compare_val;
    switch(level) {
        case 1: compare_val = 100; break;  // 10%
        case 2: compare_val = 300; break;  // 30%
        case 3: compare_val = 500; break;  // 50%
        case 4: compare_val = 700; break;  // 70%
        case 5: compare_val = 900; break;  // 90%
        default: compare_val = 0; break;
    }
    __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, compare_val);
}

通过串口指令或按键切换level,即可实现五档调速。

📊 实测数据显示:

占空比 实测转速(RPM)
20% 120
40% 480
60% 920
80% 1360
100% 1600

趋势基本线性,但在低占空比区存在启动阈值(约15%),低于此值无法克服静摩擦力。因此实际控制中常采用“死区补偿”策略,最小有效占空比不低于20%。

✅ 安全提醒:
- 测试期间远离旋转部件;
- 断电后再改接线;
- 避免短路损坏驱动芯片。


高级玩法:多通道互补PWM与死区控制 ⚔️

当你开始涉足 三相无刷电机 逆变器设计 时,普通的PWM就不够用了,必须引入 互补PWM 死区时间(Dead Time)

想象一下:上下桥臂的MOSFET如果同时导通,会发生什么?💥 直接短路!轻则跳闸,重则冒烟。

解决方案:使用STM32的高级定时器(如TIM1、TIM8),配置一对互补通道(CHx 和 CHxN),并在切换时插入一段“空白期”——也就是 死区时间 ,确保上管关断后下管才开通。

在CubeMX中如何配置?

  1. 启用 TIM1_CH1 和 TIM1_CH1N;
  2. 设置GPIO为复用推挽输出,AF1;
  3. 开启 Break and Deadlock 功能;
  4. 在 BDTR 寄存器中设置 DTG 值,单位为定时器时钟周期。
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1); // 启动互补通道

死区时间计算公式:

$$
T_{dead} = \frac{DTG}{f_{TIM}}
$$

例如,若定时器时钟为168MHz,DTG=84,则死区时间为 0.5μs。

实际应用中建议用双通道示波器同时观测CH1和CH1N,确认两者没有交叠区域。


用DMA实现SPWM:打造正弦波逆变器 🔊

想生成近似正弦波的PWM?传统方法是不断进中断改CCR值,但太耗CPU。

聪明的做法是: DMA + 定时器联动

思路如下:
- 预先计算一个正弦表(spwm_duty[360]);
- 配置DMA,每当下溢事件发生时,自动将下一个值写入CCR;
- 定时器自己跑,DMA自己传,CPU彻底解放。

uint16_t spwm_duty[360];
for (int i = 0; i < 360; ++i) {
    spwm_duty[i] = (uint16_t)(500 + 500 * sin(i * M_PI / 180));
}

// 启动DMA传输
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
HAL_DMA_Start(&hdma_tim2_ch1, (uint32_t)spwm_duty, (uint32_t)&TIM2->CCR1, 360);
__HAL_TIM_ENABLE_DMA(&htim2, TIM_DMA_UPDATE);

这样每完成一个周期,DMA就送一个新的占空比,最终合成出接近正弦的输出波形。

应用场景包括:
- 数字电源
- UPS不间断电源
- 变频空调驱动

📈 表格参考:

角度 占空比(ARR=999)
500
90° 1000
180° 500
270° 0
360° 500

定时器同步与级联:多路PWM协同作战 🤝

有些场合需要多个PWM信号严格同步,比如交错式电源或多相电机驱动。

STM32提供了强大的 主从模式 机制:

  • 主定时器(TIM2)设置 TRGO = Update Event;
  • 从定时器(TIM3)设置 Trigger Source = ITR1(即TIM2);
  • 从定时器模式设为 Reset 或 Gated Mode;

这样一来,TIM3就会在TIM2更新时同步启动,实现多路PWM同相或错相输出。

还可以将TRGO接到ADC的触发输入,实现在PWM周期中的特定时刻采样电流,提升闭环控制精度。

典型应用:
- PFC功率因数校正
- FOC矢量控制
- 多相交错降压变换器


常见问题排查清单 🛠️

别慌!遇到问题很正常。以下是高频故障汇总:

现象 可能原因 解决方案
无输出 GPIO或TIM时钟未使能 检查RCC配置
频率错误 PSC/ARR计算基于错误时钟 确认定时器实际频率是否翻倍
占空比无效 直接赋值CCR而非用宏 使用 __HAL_TIM_SET_COMPARE()
波形抖动 电源噪声大 加去耦电容,优化PCB布局
互补通道不出波 未调 HAL_TIMEx_PWMN_Start() 补充启动函数
死区无效 BDTR未使能或DTG太小 检查BDTR寄存器设置
DMA停止传输 未启用Circular模式 CubeMX中勾选循环模式
PWM失步 中断优先级低 提高定时器中断优先级
多定时器不同步 未使用TRGO同步 配置主从模式
SPWM畸变 正弦表分辨率低 增加查表点数
HardFault崩溃 DMA缓冲越界 检查数组长度与传输数量匹配

📌 经验之谈:
- 尽量使用硬件机制(DMA、同步触发)减轻CPU负担;
- 关键任务关闭低优先级中断;
- 调试阶段多用逻辑分析仪或双通道示波器;
- 利用STM32CubeMonitor-Power分析功耗与波形质量。


结语:PWM不只是技术,更是艺术 🎨

你看,从最简单的LED调光,到复杂的SPWM逆变器,PWM贯穿了整个嵌入式控制系统的核心。

它教会我们一件事: 用有限的数字资源,去逼近无限的模拟世界

而STM32凭借其强大灵活的定时器架构,让我们能够以极低的成本实现高性能控制。再加上CubeMX这样的现代化工具加持,开发效率更是突飞猛进。

所以,下次当你看到一个平滑亮起的灯光,或是一台安静运转的风扇,请记住:那背后,很可能有一个小小的定时器,正一丝不苟地跳动着它的节拍。🎶

Keep coding, keep blinking. 😉

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

您可能感兴趣的与本文相关内容

### 配置 STM32CubeMX 中的定时器用于 PWM 输出STM32CubeMX配置定时器以生成 PWM 输出,需要设置定时器的通道模式、预分频系数、自动重装载值以及 PWM 模式。以下是一个完整的配置流程,适用于 STM32 系列微控制器。 #### 定时器基础配置STM32CubeMX 中选择定时器(如 TIM4),将相应的 GPIO 引脚配置为复用推挽输出模式。例如,可以将 PB8 和 PB9 配置TIM4 的通道 3 和通道 4 输出引脚。定时器的时钟源应选择内部时钟(Internal Clock),并设置为向上计数模式(Up Counting Mode)[^2]。 #### PWM 模式配置定时器通道配置PWM Generation 模式,并选择所需的通道(如 TIMx_CH1、TIMx_CH2 等)。STM32 支持两种 PWM 模式: - **PWM 模式 1**:当计数器值小于 CCR 值时,输出高电平;否则输出低电平。 - **PWM 模式 2**:当计数器值小于 CCR 值时,输出低电平;否则输出高电平[^4]。 同时,需要设置输出极性(CH Polarity),以决定 PWM 波形的起始电平。 #### 预分频系数与自动重装载值设置 定时器的频率由预分频系数(Prescaler)和自动重装载值(Counter Period)共同决定。公式为: $$ \text{PWM 频率} = \frac{\text{定时器时钟频率}}{\text{预分频系数} \times \text{自动重装载值}} $$ 例如,若系统时钟为 168MHz,预分频系数设为 72,自动重装载值设为 100,则 PWM 频率为: $$ \text{频率} = \frac{168000000}{72 \times 100} = 23333Hz $$ 在 STM32CubeMX 中,可设置 Prescaler 为 72-1,Counter Period 为 100-1(因为计数从 0 开始)[^3]。 #### 占空比设置 占空比通过设置 CCR(Capture/Compare Register)的值来实现。例如,若自动重装载值为 100,设置 CCR 为 50,则占空比为 50%。在代码中可以通过以下函数动态修改占空比: ```c __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1, 500); // 设置占空比为 500 ``` #### 启动 PWM 输出 在初始化完成后,使用以下函数启动 PWM 输出: ```c HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1); // 启动定时器 PWM 输出 ``` #### 示例代码 以下为初始化定时器并启动 PWM 输出的示例代码片段: ```c void MX_TIM2_Init(void) { htim2.Instance = TIM2; htim2.Init.Prescaler = 72 - 1; htim2.Init.CounterMode = TIM_COUNTERMODE_UP; htim2.Init.Period = 100 - 1; htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; if (HAL_TIM_PWM_Init(&htim2) != HAL_OK) { Error_Handler(); } TIM_OC_InitTypeDef sConfigOC; sConfigOC.OCMode = TIM_OCMODE_PWM1; sConfigOC.Pulse = 50; // 初始占空比 50% sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1) != HAL_OK) { Error_Handler(); } HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1); } ``` #### PWM 输出模式说明 定时器通道可配置为多种模式,包括: - **PWM Generation No output**:不输出 PWM - **PWM Generation CHx**:指定通道输出 PWM - **Output Compare**:比较输出模式 - **Input Capture**:输入捕获模式[^2] #### 配置注意事项 - 若使用外部时钟源,需在 RCC 设置中选择 High Speed Clock(HSE)为外部晶振模式。 - 在 Clock Configuration 页面中配置系统时钟频率。 - 选择合适的 PWM 模式和极性以匹配外部电路需求[^3]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值