84【无人机】003 六步换相 驱动无刷电机

1 引言

        本博客是为了记录自己在无人机行业中,所涉及的技术成长路线。既是记录自己的成长轨迹,亦是总结所学,便于后续持续学习进步。

        本blog记录了使用STM32F407 + EG2133三相独立半桥驱动芯片 + MT6701磁性角度编码器芯片 + 无刷电机(10对极)无刷电机,使用六步换向驱动电机转动实验过程。记录可能理解浅薄,请多包涵。

2 实验过程

2.1 机械角度和电角度

        机械角度:

转子实际旋转的角度。

如:转子正方向旋转一圈,那么机械角度是360°;正方向旋转两圈,则机械角度是720°。     

若:转子反方向旋转一圈,那么机械角度是-360°;反方向旋转两圈,则机械角度是-720°。

        电角度:

电角度是描述转子与磁场相关的角度。

(1)转子在磁场中旋转会产生正弦交变电流,一个完整的正弦波周期对应 360° 电角度。

(2)电角度本质上衡量的是“时间”和“相位”,而不是“空间位置”

        电角度和机械角度关系:

电角度 = 机械角度 x 电机磁极对数

若电机有N对磁极,转子旋转一圈,机械角度=360°,电角度=360° x 极对数N

2.2 死区产生

        来自deepseek回答:只要无刷电机(BLDC/PMSM)使用“三相全桥逆变器”驱动,且采用“PWM脉宽调制”方式,那么在每一个PWM周期中,都必然存在死区时间。

物理原因:MOSFET功率管的开通速度永远比关断速度

        如果没有死区时间,那么当程序命令“上桥开通”的同时命令“下桥关断”,由于下桥关断有延迟,而上桥瞬间就通了,这会导致上下桥臂瞬间直通(贯穿),相当于把电源正负极直接短路。结果就是:巨大的尖峰电流烧毁MOS管。

      死区时间是为了规避功率开关管固有的‘开通延迟小于关断延迟’特性,通过插入一段两管均截至的空白区间,以防止上下桥臂发生贯穿性短路。

        死区时间中,下桥臂的驱动信号全部被硬件强制拉低,保证上桥完全关闭后,再开通下桥。属于偷走共有的电压输出时间。

        死区时间是插入在PWM周期内部的,如下图示。

2.3 死区时间计算

        说是不同的芯片,死区的计算公式不一样。这里用了STM32F407单片机,故就一起看看STM32F407 的死区时间计算。

公式:死区时间 = DTG值 × t_DTS

           t_DTS = 1 / f_TIM = 1 / 168MHz ≈ 5.95ns

          STM32F4 参考手册完整公式(DTG 分段编码):

DTG[7:5]死区时间公式DTG 范围死区范围 @168MHz
0xxDT = DTG[7:0] × t_DTS0~1270~756ns
10xDT = (64 + DTG[5:0]) × 2 × t_DTS128~191760ns~1.5µs
110DT = (32 + DTG[4:0]) × 8 × t_DTS192~2231.5µs~3.0µs
111DT = (32 + DTG[4:0]) × 16 × t_DTS224~2553.0µs~4.5µs

        定时器设置的DeadTime会直接设置到OTG寄存器,如下示例。

DeadTimeDTG 二进制死区时间公式
170b00010001~101ns17 × 5.95ns
420b00101010~250ns42 × 5.95ns
840b01010100~500ns84 × 5.95ns

2.4 实验记录

记录1:换相表。

        换相表默认按电角度从 0° 到 360° 递增设计,当转子旋转电角度持续增加时,必须顺着步骤 0→1→2… 的换相表顺序切换通电状态,才能产生正向的旋转力矩,持续驱动电子转动的力矩。否则可能会出现转子原地震动等现象。

记录2:无刷电机无法转动且高频震动。

        按照换相表,电角度从0到360°方向增长驱动电机旋转时,若磁性编码器读出的电角度是递减的,此时与换相表递增设计是相反的。即故转子在物理上正转,可编码器测量电角度却在减小(反转),按代码实际照换向逻辑,此时会产生来回变化的反向力矩,让电机剧烈“原地”抖动。

记录3:机械角度0°其实等于电角度0°

        机械角度0°可通过 磁性传感器z相 输出信号定位。当转子旋转到z相0°时,此时z相输出高电平,单片机通过上升沿捕获,标记此时机械角度0度。

        电角度0°是描述电磁起始点。如果无刷电机有多对磁极,那么机械角度0°实际上是对应“其中某一对极”的电角度0°,而对于其它的对极电角度不是0度。

重要!!!

(1)当转子转到机械0度时,如果电机是2极(1对极),此时电角度直接就是0度;

(2)对于多对极电机,一般会将机械角度为0时,将此时的电角度直接定义为0度;

记录4:实际电角度计算时,要“手动” 减去 机械角度偏移,否则电角度计算有误差。

        简单测量机械角度的设备一般是霍尔传感器,如项目中使用了MT6701传感器测量转子位置。当转子转到z相输出高电平时,此时机械角度为“0”时(转子稳定位置),但霍尔传感器实测机械角度输出并不是0度,而由于转子稳定时,电角度是可定义成0度的。

        根据电角度和机械角度关系式:

理想状态:电角度 = 机械角度 x 电极对数

实际状态:电角度= (实测机械角度 - 偏移角度)x 电极对数

        此时,在软件算法中对于电角度的计算,是必须要减去当电角度为0时的机械角度,这样才能使用:电角度 = 机械角度 x 电极对数 这个公式。

电角度0度 = 0 x 电极对数              // 0 = (实测机械角度 - 偏移角度)

3 六步换相代码

        如下是六步换相电机控制代码。

/******************************************************************************/
/* file         : motorTsk.c                                                  */
/* description  : motor task                                                  */
/*                                                                            */
/* author       : justin                                                      */
/* version      : 1.0                                                         */
/* date         : 2024-01-15                                                  */
/******************************************************************************/

/****************************************************************************/
/* Head files                                                               */
/****************************************************************************/
#include <math.h>
#include "gpio.h"
#include "fc_main.h"
#include "fc_public.h"
#include "fc_mt6701.h"
#include "fc_EG2133.h"

#include "sysMngr.h"
#include "keyTsk.h"

#include "motorTsk.h"

/****************************************************************************/
/* Marco Define                                                             */
/****************************************************************************/
#define PWM_PERIOD                  8399    // TIM1 ARR值
#define PWM_HALF                    4199    // 50%占空比
#define PI                          3.14159265f
#define PIX2                        (2.0f * PI)

/****************************************************************************/
/* Type Definitions                                                         */
/****************************************************************************/

/****************************************************************************/
/* Global Variable Declarations                                             */
/****************************************************************************/
uint8_t                                         g_motor_run     = 0;        // 电机运行标志
float                                           g_motor_speed   = 5.0f;     // 目标电角度速度 (Hz)
float                                           g_motor_voltage = 0.5f;     // 电压幅值 (0.0~1.0)

/****************************************************************************/
/* static Variable Declarations                                             */
/****************************************************************************/
static fc_core_task_id_t                        s_motorTsk_id       = -1;
static uint8_t                                  s_last_step         = 0;       // 上一次换相步骤

static uint8_t                                  s_motor_pwr_enable      = 0;       // 0-off 1-enable
static uint8_t                                  s_has_calib             = 0;       // 0-编码器未校准 1-电角度已标定
static float                                    s_elec_zero_offset_deg  = 0.0f;    // A相对齐时编码器的机械角度(°),电角度零点偏置
static float                                    s_comm_adv_deg          = 0.0f;   // 换相提前角(°),需根据实际电机标定
static int8_t                                   s_comm_direction        = -1;       // +1正向 -1反向,若电机抖动可尝试改为-1

/****************************************************************************/
/* extern Variable Declarations                                             */
/****************************************************************************/

/****************************************************************************/
/* extern functions Declarations                                            */
/****************************************************************************/

/****************************************************************************/
/* Function Declarations                                                    */
/****************************************************************************/

/****************************************************************************/
/*                                                                          */
/* Function     : _motorTsk_keyCB_pwrCtl                                    */
/* description  : none                                                      */
/*                                                                          */
/* Parameters   :                                                           */
/*   void - none                                                            */
/*                                                                          */
/* Returns      : none                                                      */
/*                                                                          */
/* Author       : justin                                                    */
/* Created      : 2025-10-25                                                */
/* Modified     : 2025-10-25                                                */
/* Version      : 1.0.0                                                     */
/*                                                                          */
/****************************************************************************/
static void _motorTsk_keyCB_pwrCtl
(
    KEY_NO_X_VALUE                  keyValue,
    uint32_t                        occurTick
)
{

    s_motor_pwr_enable = (s_motor_pwr_enable==0)?(1):(0);

    if(s_motor_pwr_enable == 0)
    {
        // pwr off
        HAL_GPIO_WritePin(PWR_GPIO_Port, PWR_Pin, GPIO_PIN_RESET);
    }
    else
    {
        // pwr on
        HAL_GPIO_WritePin(PWR_GPIO_Port, PWR_Pin, GPIO_PIN_SET);
    }

    return;
}

/****************************************************************************/
/*                                                                          */
/* Function     : _motorTsk_keyCB_callbZero                                 */
/* description  : none                                                      */
/*                                                                          */
/* Parameters   :                                                           */
/*   void - none                                                            */
/*                                                                          */
/* Returns      : none                                                      */
/*                                                                          */
/* Author       : justin                                                    */
/* Created      : 2025-10-25                                                */
/* Modified     : 2025-10-25                                                */
/* Version      : 1.0.0                                                     */
/*                                                                          */
/****************************************************************************/
static void _motorTsk_keyCB_callbZero
(
    KEY_NO_X_VALUE                  keyValue,
    uint32_t                        occurTick
)
{
    motorTsk_fixAngle();
    return;
}

/****************************************************************************/
/*                                                                          */
/* Function     : _motorTsk_keyCB_moterRun                                  */
/* description  : none                                                      */
/*                                                                          */
/* Parameters   :                                                           */
/*   void - none                                                            */
/*                                                                          */
/* Returns      : none                                                      */
/*                                                                          */
/* Author       : justin                                                    */
/* Created      : 2025-10-25                                                */
/* Modified     : 2025-10-25                                                */
/* Version      : 1.0.0                                                     */
/*                                                                          */
/****************************************************************************/
static void _motorTsk_keyCB_moterRun
(
    KEY_NO_X_VALUE                  keyValue,
    uint32_t                        occurTick
)
{
    motorTsk_run();
    return;
}

/****************************************************************************/
/*                                                                          */
/* Function     : _motorTsk_keyCB_moterStop                                 */
/* description  : none                                                      */
/*                                                                          */
/* Parameters   :                                                           */
/*   void - none                                                            */
/*                                                                          */
/* Returns      : none                                                      */
/*                                                                          */
/* Author       : justin                                                    */
/* Created      : 2025-10-25                                                */
/* Modified     : 2025-10-25                                                */
/* Version      : 1.0.0                                                     */
/*                                                                          */
/****************************************************************************/
static void _motorTsk_keyCB_moterStop
(
    KEY_NO_X_VALUE                  keyValue,
    uint32_t                        occurTick
)
{
    motorTsk_stop();
    return;
}

/****************************************************************************/
/* 辅助函数:设置单相的工作状态(使能/浮空)并更新比较值                    */
/* phase : 0=A相, 1=B相, 2=C相                                             */
/* enable: 1=使能输出, 0=浮空(上下管均关断)                               */
/* ccr   : 比较值(当 enable=1 时有效)                                     */
/****************************************************************************/
static void Motor_SetPhaseState(uint8_t phase, uint8_t enable, uint32_t ccr)
{
    uint32_t ccer_mask;

    switch (phase)
    {
        case 0: /* A相 : CH1 & CH1N */
            ccer_mask = TIM_CCER_CC1E | TIM_CCER_CC1NE;
            if (enable)
            {
                TIM1->CCR1 = ccr;                 // 先更新比较值
                TIM1->CCER |= ccer_mask;          // 再使能输出
            }
            else
            {
                TIM1->CCER &= ~ccer_mask;         // 同时关闭 CH1 和 CH1N
            }
            break;

        case 1: /* B相 : CH2 & CH2N */
            ccer_mask = TIM_CCER_CC2E | TIM_CCER_CC2NE;
            if (enable)
            {
                TIM1->CCR2 = ccr;
                TIM1->CCER |= ccer_mask;
            }
            else
            {
                TIM1->CCER &= ~ccer_mask;
            }
            break;

        case 2: /* C相 : CH3 & CH3N */
            ccer_mask = TIM_CCER_CC3E | TIM_CCER_CC3NE;
            if (enable)
            {
                TIM1->CCR3 = ccr;
                TIM1->CCER |= ccer_mask;
            }
            else
            {
                TIM1->CCER &= ~ccer_mask;
            }
            break;

        default:
            break;
    }
}

/****************************************************************************/
/*                                                                          */
/* Function     : motorTsk_tim1_update                                      */
/* description  : TIM1更新中断回调 - 基于编码器电角度的六步换相              */
/*                使用fcMT6701_GetElcAngle()获取电角度进行闭环换相          */
/*                浮空相通过关闭PWM输出实现                                  */
/*                                                                          */
/****************************************************************************/
void motorTsk_tim1_update(void)
{
    float elc_angle_deg;                     // 当前电角度(度),0~360
    uint8_t current_step;                    // 当前换相步骤 (0~5)
    static uint8_t s_last_step = 0xFF;       // 上一次的步骤,0xFF强制首次更新

    if(fcMT6701_GetCalib() == false || s_has_calib == 0)
    {
        return;
    }
    // 六步换相表 (index 0~5 对应电角度 0°~60°, 60°~120°, ... 300°~360°)
    // 2: 高侧PWM(上管PWM调制,下管互补导通)
    // 1: 低侧导通(下管常通,上管关断)
    // 0: 浮空(上下管均关断)
    const uint8_t commutation_table[6][3] = {
        {2, 1, 0},  // 步骤0: A→B (  0°~ 60°)
        {2, 0, 1},  // 步骤1: A→C ( 60°~120°)
        {0, 2, 1},  // 步骤2: B→C (120°~180°)
        {1, 2, 0},  // 步骤3: B→A (180°~240°)
        {1, 0, 2},  // 步骤4: C→A (240°~300°)
        {0, 1, 2},  // 步骤5: C→B (300°~360°)
    };

    // 1. 计算修正后的电角度(°): 机械角度 - 偏置 → 转换为电角度
    float mech_deg = fcMT6701_GetAngle() - s_elec_zero_offset_deg;
    if (mech_deg < 0.0f) mech_deg += 360.0f;
    elc_angle_deg = mech_deg * 10.0f;   // MOTOR_POLE_PAIRS = 10
    while (elc_angle_deg >= 360.0f) elc_angle_deg -= 360.0f;

    // 2. 根据电角度+提前角确定换相步骤, 换相方向可调
    current_step = ((uint32_t)((elc_angle_deg + s_comm_adv_deg) / 60.0f)) % 6;
    if(s_comm_direction < 0) current_step = 5 - current_step;

    // 3. 计算当前电压指令对应的占空比
    uint32_t duty_on  = (uint32_t)(g_motor_voltage * PWM_HALF);
    uint32_t duty_low = 0;   // 低侧常通:CCR=0 → 下管常通(上管关断)

    // 4. 根据步骤是否发生变化,执行不同的更新策略
    if (current_step != s_last_step)
    {
        /* ---- 发生了换相:重新配置三相的使能状态与占空比 ---- */
        s_last_step = current_step;

        for (uint8_t phase = 0; phase < 3; phase++)
        {
            uint8_t mode = commutation_table[current_step][phase];

            if (mode == 2)          // 高侧PWM
            {
                Motor_SetPhaseState(phase, 1, duty_on);
            }
            else if (mode == 1)     // 低侧导通
            {
                Motor_SetPhaseState(phase, 1, duty_low);
            }
            else                    // mode == 0 → 浮空
            {
                Motor_SetPhaseState(phase, 0, 0);  // enable=0, ccr值无所谓
            }
        }
    }
    else
    {
        /* ---- 步骤未变:仅更新高侧PWM相的占空比,跟踪电压指令变化 ---- */
        for (uint8_t phase = 0; phase < 3; phase++)
        {
            if (commutation_table[current_step][phase] == 2)
            {
                // 直接更新该高侧相的CCR,低侧和浮空相保持不变
                switch (phase)
                {
                    case 0: TIM1->CCR1 = duty_on; break;
                    case 1: TIM1->CCR2 = duty_on; break;
                    case 2: TIM1->CCR3 = duty_on; break;
                }
                break;  // 每步只有一个高侧相
            }
        }
    }
}

/****************************************************************************/
/*                                                                          */
/* Function     : motorTsk_ReTOZero                                         */
/* description  : none                                                      */
/*                                                                          */
/* Parameters   :                                                           */
/*   void - none                                                            */
/*                                                                          */
/* Returns      : none                                                      */
/*                                                                          */
/* Author       : justin                                                    */
/* Created      : 2025-10-25                                                */
/* Modified     : 2025-10-25                                                */
/* Version      : 1.0.0                                                     */
/*                                                                          */
/****************************************************************************/
void motorTsk_ReTOZero
(
    void
)
{
    static uint8_t      step        = 0;
    const float         voltage     = 0.04f;   // 固定小电压

    // 使用你原换相表
    const uint8_t       table[6][3] =
    {
        {2, 1, 0},
        {2, 0, 1},
        {0, 2, 1},
        {1, 2, 0},
        {1, 0, 2},
        {0, 1, 2}
    };


    HAL_GPIO_WritePin(PWR_GPIO_Port, PWR_Pin, GPIO_PIN_SET);
    fc_delay_ms(20);
    fcEG2133_enablePWM();

    do
    {
        // 先全部浮空
        TIM1->CCER &= ~(TIM_CCER_CC1E | TIM_CCER_CC1NE |
                        TIM_CCER_CC2E | TIM_CCER_CC2NE |
                        TIM_CCER_CC3E | TIM_CCER_CC3NE);

        uint32_t duty_on  = (uint32_t)(PWM_HALF*voltage);
        uint32_t duty_low = 0;

        // 设置比较值
        uint32_t ccr_a = (table[step][0] == 2) ? duty_on : ((table[step][0] == 1) ? duty_low : 0);
        uint32_t ccr_b = (table[step][1] == 2) ? duty_on : ((table[step][1] == 1) ? duty_low : 0);
        uint32_t ccr_c = (table[step][2] == 2) ? duty_on : ((table[step][2] == 1) ? duty_low : 0);
        TIM1->CCR1 = ccr_a;
        TIM1->CCR2 = ccr_b;
        TIM1->CCR3 = ccr_c;

        // 只使能非浮空相
        uint32_t ccer = 0;
        if (table[step][0] != 0) ccer |= (TIM_CCER_CC1E | TIM_CCER_CC1NE);
        if (table[step][1] != 0) ccer |= (TIM_CCER_CC2E | TIM_CCER_CC2NE);
        if (table[step][2] != 0) ccer |= (TIM_CCER_CC3E | TIM_CCER_CC3NE);
        TIM1->CCER |= ccer;

        step = (step + 1) % 6;

        fc_delay_ms(100);
    }
    while(fcMT6701_GetCalib()== false);

    // Z相校准完成,关闭PWM,编码器归零
    fcEG2133_disablePWM();
    HAL_GPIO_WritePin(PWR_GPIO_Port, PWR_Pin, GPIO_PIN_RESET);

    fcMT6701_SetZero();

    printf("step =  %d\r\n", step);
    return;
}

/****************************************************************************/
/*                                                                          */
/* Function     : motorTsk_fixAnglee                                        */
/* description  : module init                                               */
/*                                                                          */
/* Parameters   :                                                           */
/*   void - none                                                            */
/*                                                                          */
/* Returns      : none                                                      */
/*                                                                          */
/* Author       : justin                                                    */
/* Created      : 2025-10-25                                                */
/* Modified     : 2025-10-25                                                */
/* Version      : 1.0.0                                                     */
/*                                                                          */
/****************************************************************************/
void motorTsk_fixAngle
(
    void
)
{
    // Step1: 找Z相并归零编码器
    s_has_calib = 0;
    fcMT6701_ResetCalibFlag();
    motorTsk_ReTOZero();

    // Step2: 给A相通电,转子自动对齐到A相磁极的电角度0°位置
    fcEG2133_setPWM(400, 0, 0);
    fcEG2133_enablePWM();
    fc_delay_ms(1000);
    fcEG2133_disablePWM();

    // 此时编码器的读数就是电角度零点的机械角度偏置
    s_elec_zero_offset_deg = fcMT6701_GetAngle();

    // 标记电角度标定完成,ISR可以开始换相
    s_has_calib = 1;

    printf("ElecOffset = %.1f\r\n", s_elec_zero_offset_deg);
    return;
}

/****************************************************************************/
/*                                                                          */
/* Function     : motorTsk_run                                              */
/* description  : module init                                               */
/*                                                                          */
/* Parameters   :                                                           */
/*   void - none                                                            */
/*                                                                          */
/* Returns      : none                                                      */
/*                                                                          */
/* Author       : justin                                                    */
/* Created      : 2025-10-25                                                */
/* Modified     : 2025-10-25                                                */
/* Version      : 1.0.0                                                     */
/*                                                                          */
/****************************************************************************/
void motorTsk_run
(
    void
)
{
    if(fcMT6701_GetCalib() == true && s_has_calib == 1)
    {
        fcEG2133_enablePWM();
    }

    return;
}

/****************************************************************************/
/*                                                                          */
/* Function     : motorTsk_stop                                             */
/* description  : module init                                               */
/*                                                                          */
/* Parameters   :                                                           */
/*   void - none                                                            */
/*                                                                          */
/* Returns      : none                                                      */
/*                                                                          */
/* Author       : justin                                                    */
/* Created      : 2025-10-25                                                */
/* Modified     : 2025-10-25                                                */
/* Version      : 1.0.0                                                     */
/*                                                                          */
/****************************************************************************/
void motorTsk_stop
(
    void
)
{
    fcEG2133_disablePWM();

    return;
}

/****************************************************************************/
/*                                                                          */
/* Function     : motorTsk_task                                             */
/* description  : none                                                      */
/*                                                                          */
/* Parameters   :                                                           */
/*   void - none                                                            */
/*                                                                          */
/* Returns      : none                                                      */
/*                                                                          */
/* Author       : justin                                                    */
/* Created      : 2025-10-25                                                */
/* Modified     : 2025-10-25                                                */
/* Version      : 1.0.0                                                     */
/*                                                                          */
/****************************************************************************/
void motorTsk_task
(
    void                            *user_params
)
{
    static uint8_t  has_init    = 0;

    // attention:
    // task can not be blocked!!!!!
    // this is 100ms task
    do
    {
        if(has_init == 0)
        {
            has_init = 1;
            motorTsk_ReTOZero();
        }

        // 电机控制任务:可以在这里添加速度调节、模式切换等逻辑

        // 打印编码器信息(电角度以°显示,便于调试)
         printf("pos:%d ang:%.1f eAng:%.1f off:%.1f adv:%.0f dir:%d cal:%d\r\n",
                fcMT6701_GetPosition(), fcMT6701_GetAngle(),
                fcMT6701_GetElcAngle() * 180.0f / PI,
                s_elec_zero_offset_deg, s_comm_adv_deg,
                s_comm_direction, s_has_calib);

    } while(0);

    return;
}

/****************************************************************************/
/*                                                                          */
/* Function     : motorTsk_Init                                             */
/* description  : module init                                               */
/*                                                                          */
/* Parameters   :                                                           */
/*   void - none                                                            */
/*                                                                          */
/* Returns      : none                                                      */
/*                                                                          */
/* Author       : justin                                                    */
/* Created      : 2025-10-25                                                */
/* Modified     : 2025-10-25                                                */
/* Version      : 1.0.0                                                     */
/*                                                                          */
/****************************************************************************/
void motorTsk_Init
(
    void
)
{
    keyTsk_register_callback(KEY_NO_1_SHORT_PRESSED, _motorTsk_keyCB_callbZero);
    keyTsk_register_callback(KEY_NO_2_SHORT_PRESSED, _motorTsk_keyCB_moterRun);
    keyTsk_register_callback(KEY_NO_3_SHORT_PRESSED, _motorTsk_keyCB_moterStop);
    keyTsk_register_callback(KEY_NO_4_SHORT_PRESSED, _motorTsk_keyCB_pwrCtl);

    // 注册电机任务(100ms周期)
    s_motorTsk_id = fc_core_task_register(motorTsk_task, 100, NULL);
    s_motorTsk_id = s_motorTsk_id;

    return;
}

实验设备图:

over!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值