超全面的GD32F4XX的ADC配置

网上ADC相关的文章主要是STM32 ADC,而GD32 ADC较少;虽然两者基本一致,但是使用GD32 ADC时参考GD32 ADC的资料最方便。因此本文介绍GF32 ADC常用功能 以及 代码实现,包括:

  • ADC 采样
  • ADC DMA采样

 代码示例包括以上两种实现的 软件/硬件触发 多通道/单通道  连续转换/单次转换等

GD32F4xx MCU ADC 介绍

1、GD32F4xx ADC

MCU 片上集成了 12 位逐次逼近式模数转换器模块(ADC),可以采样来自于 16 个外部通道和 2 个内部通道和一个电池电压(VBAT)通道的模拟信号。

1.1 主要特征

  1. 可配置12位、10位、8位、6位分辨率;
  2. ADC采样率:12位分辨率为2.6MSPs,10位分辨率为3.0 MSPs。分辨率越低,转换越快;
    (Million Samples per Second)
  3. 自校准时间:131个ADC时钟周期;(每次采样为一个ADC时钟周期,比如40MHz时钟,校准时间约3.275us
  4. 可编程采样时间
  5. 可配置数据对齐方式;
  6. 支持规则通道数据转换的DMA请求;(有些文档/程序中 规则组 又叫 常规组)
  7. 模拟输入通道:
    1) 16个外部输入通道;
    2) 1个内部温度传感器通道;
    3) 1个内部参考电压输入通道;
    4) 1个外部监测电池Vbat供电引脚输入通道;
  8. 转换触发: 软件触发 和 硬件触发

1.2 ADC框图

1.3 ADC校准

ADC带有一个前置校准功能。在校准期间,ADC计算一个校准系数,这个系数直到ADC下次掉电才无效。在校准期间,不能使用ADC必须等到校准完成。在AD转换之前应执行校准操作,一般放在初始化里执行。

当ADC运行条件改变(如,VDDA、VREFP、温度等条件变化,建议重新执行一次校准操作。)

1.4 ADC时钟

ADC CLK 与 CK_AHB、PLCK2 时钟保持同步。ADC最大时钟频率为40MHz。ADC 时钟可以在 RCU 时钟控制器中进行分配和配置。

ADC CLK 分频前 CK_AHB、PLCK2 如何设置,可以参考超全面GD32F4XX 系统时钟与AHB/APB1/APB2时钟配置_gd32 apb1和系统时钟的关系-CSDN博客

1.5 规则组和注入组

规则组又称作:常规组、常规序列

ADC转换可以组织成2组: 一个规则组通道和一个注入组通道。
1)规则组最多由16个转换组成。而注入组最多由4个转换组成。
2)注入组通道可以打断规则组通道
注入通道有两种模式:
① 触发注入模式: 在规则组通道转换期间如果软件触发或外部触发发生,ADC取消当前转换,启动触发注入转换,注入通道序列被以单次扫描方式进行转换。注入通道转换结束后,规则组转换从上次被取消的转换处重新开始。
② 自动注入模式:在规则通道之后,注入通道被自动转换。

1.6 转换模式

假设配置了5个通道 ch0、1、2、3、4

  1. 单次转换
    1. 开启扫描 : 每触发一次,转换一次 ch0、1、2、3、4
    2. 不开启扫描 :每触发一次,转换一次ch0
  2. 连续转换
    1. 开启扫描 :触发后持续转换 ch0、1、2、3、4
    2. 不开启扫描: 触发后持续转换 ch0

1.7 采样时间

ADC 使用多个 CK_ADC 周期对输入电压采样。每个通道可以用不同的采样时间。在 12 位分辨率 的情况下,总转换时间=采样时间+12 个 CK_ADC 周期。 例如: CK_ADC = 40MHz ,采样时间为 3 个周期,那么总的转换时间为:“3+12”个 CK_ADC 周期, 即 0.375us。

1.8 ADC使能

ADC 使 能后需等待T SU 时间后才能采样,T SU 数值详见芯片数据手册。 实际使用一般延时 1ms 。

1.9 触发方式

可以实时修改外部触发选择,在修改期间不会出现触发事件。后文会依次实现软件触发与外部触发。

  • 软件触发
    • 使用库函数/寄存器使能触发
  • 外部触发(硬件触发)
    • 触发模式
      • 双边沿触发
      • 下降沿触发
      • 上升沿触发
      • 失能
    • 触发源
      • 定时器触发
      • 外部中断触发

2.0 对齐方式

常用的12位分辨率,分为左对齐右对齐;

参考GD32F4XX用户手册的图片如下:

其他分辨率的存储如下:

6 位分辨率的数据存储模式不同于 12 位/10 位/8 位分辨率数据存储模式

2.1 DMA请求

DMA 请求用于常规序列多个通道的转换结果。ADC 在常规序列一个通道转换结束后产生一个 DMA 请求,DMA 接受到请求后可 以将转换的数据从 ADC_RDATA 寄存器传输到用户指定的目的地址。

2.1 其他

ADC同步模式、间断转换、溢出检测、模拟看门狗、内部通道用的比较,之后会补充更新。

代码

0、前言

1.头文件

//芯片头文件
#include "gd32f4xx.h"
//延时函数头文件
#include "systick.h"

不管是哪种ADC的配置,都需要包含以上头文件

  1. gd32f4xx.h 芯片的头文件,包含内核、芯片时钟、各种外设的标准库等的头文件,芯片宏定义等等。
  2. systick.h 包含毫秒级的延时函数,ADC的配置过程需要毫秒延时,可以替换为自己工程的延时文件,比如操作系统的头文件。
  3. 这两个就够了,如果有其它需求,比如stdio.h等,根据自己需求添加。

2、标准库

大家到这一步的时候,相信都已经有搭建好的工程,所以系统文件、启动文件等默认已经搭建好了。除此之外在写ADC驱动之前,需要先添加ADC的标注库文件,所涉及的如下:

  1. gd32f4xx_adc.c
  2. gd32f4xx_gpio.c
  3. gd32f4xx_rcu.c
  4. gd32f4xx_dma.c
  5. gd32f4xx_timer.c
  6. gd32f4xx_misc.c
  7. gd32f4xx_exti.c

前三个文件是所以ADC配置都需要添加的文件,4-7是使用到外设时才添加。

1、ADC + DMA 多通道 常规组 扫描 采样 单词转换/连续转换

软件触发

RCU、GPIO、DMA初始化


static uint32_t S_uAdcData[ADC_CHANNEL_ALL];

/*
 * 函数名:ADC0_RCU_Config
 * 描述
 * 输入  :无
 * 输出  :无
 * 调用  :内部调用
 */
static void ADC0_RCU_Config(void)
{
    /* enable GPIOC clock */
    rcu_periph_clock_enable(ADC_VOLT_RCU);
    rcu_periph_clock_enable(ADC_X_RCU);
    rcu_periph_clock_enable(ADC_Y_RCU);
    /* enable ADC clock */
    rcu_periph_clock_enable(RCU_ADC0);
    /* enable DMA clock */
    rcu_periph_clock_enable(RCU_DMA1);
    /* config ADC clock */
    adc_clock_config(ADC_ADCCK_PCLK2_DIV8);
}


/*
 * 函数名:ADC0_GPIO_Config
 * 描述
 * 输入  :无
 * 输出  :无
 * 调用  :内部调用
 */
static void ADC0_GPIO_Config(void)
{
    gpio_mode_set(ADC_VOLT_PORT, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, ADC_VOLT_PIN);
    gpio_mode_set(ADC_X_PORT, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, ADC_X_PIN);
    gpio_mode_set(ADC_Y_PORT, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, ADC_Y_PIN);
}


/*
 * 函数名:ADC0_DMA_Config
 * 描述
 * 输入  :无
 * 输出  :无
 * 调用  :内部调用
 */
static void ADC0_DMA_Config(void)
{
    /* ADC_DMA_channel configuration */
    dma_single_data_parameter_struct dma_single_data_parameter;

    /* ADC DMA_channel configuration */
    dma_deinit(DMA1, DMA_CH0);

    /* initialiLe DMA single data mode */
    dma_single_data_parameter.periph_addr = (uint32_t)(&ADC_RDATA(ADC0));
    dma_single_data_parameter.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_single_data_parameter.memory0_addr = (uint32_t)(S_uAdcData);
    dma_single_data_parameter.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_single_data_parameter.periph_memory_width = DMA_PERIPH_WIDTH_16BIT;
    dma_single_data_parameter.direction = DMA_PERIPH_TO_MEMORY;
    dma_single_data_parameter.number = ADC_CHANNEL_ALL;
    dma_single_data_parameter.priority = DMA_PRIORITY_HIGH;
    dma_single_data_mode_init(DMA1, DMA_CH0, &dma_single_data_parameter);
    dma_channel_subperipheral_select(DMA1, DMA_CH0, DMA_SUBPERI0);

    /* enable DMA circulation mode */
    dma_circulation_enable(DMA1, DMA_CH0);

    /* enable DMA channel */
    dma_channel_enable(DMA1, DMA_CH0);
}

ADC 单次转换的的配置


/*
 * 函数名:ADC0_Config
 * 描述
 * 输入  :无
 * 输出  :无
 * 调用  :内部调用
 */
static void ADC0_Config( void )
{
    /* ADC mode config */
    adc_sync_mode_config(ADC_SYNC_MODE_INDEPENDENT);
    /* ADC contineous function disable */
    adc_special_function_config(ADC0, ADC_CONTINUOUS_MODE, DISABLE);
    /* ADC scan mode disable */
    adc_special_function_config(ADC0, ADC_SCAN_MODE, ENABLE);
    /* ADC data alignment config */
    adc_data_alignment_config(ADC0, ADC_DATAALIGN_RIGHT);

    /* ADC channel length config */
    adc_channel_length_config(ADC0, ADC_REGULAR_CHANNEL, ADC_CHANNEL_ALL);

    /* ADC trigger config */
    adc_external_trigger_source_config(ADC0, ADC_REGULAR_CHANNEL, ADC_EXTTRIG_REGULAR_T0_CH0);
    adc_external_trigger_config(ADC0, ADC_REGULAR_CHANNEL, EXTERNAL_TRIGGER_DISABLE);

    /* ADC DMA function enable */
    adc_dma_request_after_last_enable(ADC0);
    adc_dma_mode_enable(ADC0);

    /* enable ADC interface */
    adc_enable(ADC0);
    /* wait for ADC stability */
    delay_1ms(1);
    /* ADC calibration and reset calibration */
    adc_calibration_enable(ADC0);

}


/*
 * 函数名:ADC0_Init
 * 描述
 * 输入  :无
 * 输出  :无
 * 调用  :内部调用
 */
static void ADC0_Init(void)
{
    ADC0_RCU_Config();
    ADC0_GPIO_Config();
    ADC0_DMA_Config();
    ADC0_Config();
}

/*
 * 函数名:ADC0_Init
 * 描述
 * 输入  :无
 * 输出  :无
 * 调用  :内部调用
 */
static void  ADC0_CannelSample()
{
    /* ADC routine channel config */
    adc_regular_channel_config(ADC0, 0, ADC_VOLT_CHANNEL, ADC_SAMPLETIME_15);
    adc_regular_channel_config(ADC0, 1, ADC_X_CHANNEL, ADC_SAMPLETIME_15);
    adc_regular_channel_config(ADC0, 2, ADC_Y_CHANNEL, ADC_SAMPLETIME_15);

    /* ADC software trigger enable */
    adc_software_trigger_enable(ADC0, ADC_REGULAR_CHANNEL); // ADC软件触发使能
}


ADC 连续转换的的配置


/*
 * 函数名:ADC0_Config
 * 描述
 * 输入  :无
 * 输出  :无
 * 调用  :内部调用
 */
static void ADC0_Config( void )
{
    /* ADC mode config */
    adc_sync_mode_config(ADC_SYNC_MODE_INDEPENDENT);
    /* ADC contineous function disable */
    adc_special_function_config(ADC0, ADC_CONTINUOUS_MODE, ENABLE);
    /* ADC scan mode disable */
    adc_special_function_config(ADC0, ADC_SCAN_MODE, ENABLE);
    /* ADC data alignment config */
    adc_data_alignment_config(ADC0, ADC_DATAALIGN_RIGHT);

    /* ADC channel length config */
    adc_channel_length_config(ADC0, ADC_REGULAR_CHANNEL, ADC_CHANNEL_ALL);

    /* ADC routine channel config */
    adc_routine_channel_config(ADC0, 0, ADC_VOLT_CHANNEL, ADC_SAMPLETIME_15);
    adc_routine_channel_config(ADC0, 1, ADC_X_CHANNEL, ADC_SAMPLETIME_15);
    adc_routine_channel_config(ADC0, 2, ADC_Y_CHANNEL, ADC_SAMPLETIME_15);

    /* ADC trigger config */
    adc_external_trigger_source_config(ADC0, ADC_REGULAR_CHANNEL, ADC_EXTTRIG_REGULAR_T0_CH0);
    adc_external_trigger_config(ADC0, ADC_REGULAR_CHANNEL, EXTERNAL_TRIGGER_DISABLE);

    /* ADC DMA function enable */
    adc_dma_request_after_last_enable(ADC0);
    adc_dma_mode_enable(ADC0);

    /* enable ADC interface */
    adc_enable(ADC0);
    /* wait for ADC stability */
    delay_1ms(1);
    /* ADC calibration and reset calibration */
    adc_calibration_enable(ADC0);

    /* enable ADC software trigger */
    adc_software_trigger_enable(ADC0, ADC_ROUTINE_CHANNEL);

}


/*
 * 函数名:ADC0_Init
 * 描述
 * 输入  :无
 * 输出  :无
 * 调用  :内部调用
 */
static void ADC0_Init(void)
{
    ADC0_RCU_Config();
    ADC0_GPIO_Config();
    ADC0_DMA_Config();
    ADC0_Config();
}

ADC DMA 多通道采样 对外接口

/*  对外接口  */

/*
*@brief ADC初始化
*@retval 初始化状态
*/
void ADC_Init(void)
{
    ADC0_Init();
    for(int8_t i=0;i< ADC_CHANNEL_ALL;i++)
    {
        S_uAdcData[i] = 0;
    }
}


/*
*@brief ADC值读取  单次转换/连续转化
*@retval ADC值
*/
uint16_t ADC_GetValue(uint16_t Chn)
{
    //单次转换保留该行,连续转化注释该行代码
    ADC0_CannelSample();
    
    return S_uAdcData[Chn];
}


以上配置所使用的相关宏定义如下,将其添加到头文件,替换为自己芯片的资源,即可使用以上ADC DMA 多通道 单次转换/连续转换 采样的配置。

/* --------------- ADC0 DMA 定时器触发 --------------- */
//电源电压
/* PC1 PA1  ADC01_IN15*/
#define ADC_VOLT_RCU       RCU_GPIOC
#define ADC_VOLT_PORT      GPIOC
#define ADC_VOLT_PIN       GPIO_PIN_5

#define ADC_VOLT_ADC_RCU   RCU_ADC0
#define ADC_VOLT_ADC       ADC0
#define ADC_VOLT_CHANNEL   ADC_CHANNEL_15


//遥杆
/* PC1 ADC012_IN11*/
#define ADC_X_RCU          RCU_GPIOC
#define ADC_X_PORT         GPIOC
#define ADC_X_PIN          GPIO_PIN_1

#define ADC_X_ADC_RCU      RCU_ADC0
#define ADC_X_ADC          ADC0
#define ADC_X_CHANNEL      ADC_CHANNEL_11


/*PA1  ADC012_IN1*/
#define ADC_Y_RCU          RCU_GPIOA
#define ADC_Y_PORT         GPIOA
#define ADC_Y_PIN          GPIO_PIN_1

#define ADC_Y_ADC_RCU      RCU_ADC0
#define ADC_Y_ADC          ADC0
#define ADC_Y_CHANNEL      ADC_CHANNEL_1

/* --------------- ADC0 DMA 定时器触发 --------------- */

//ADC通道定义
#define CMD_ADC_VOLT        0  //电源采集ADC
#define CMD_ADC_X           1  //遥感X
#define CMD_ADC_Y           2  //遥感Y

#define ADC_CHANNEL_ALL       (3)

2、ADC 多通道 常规组 不扫描 采样 单次转换/连续转换

软件触发

RCU GPIO的初始化时,根据自己芯片的资源,替换对应时钟与引脚,多余的通道数量也删除。

/*!
    \brief      configure the different system clocks
    \param[in]  none
    \param[out] none
    \retval     none
*/
void rcu_config(void)
{
    /* enable GPIOA clock */
    rcu_periph_clock_enable(RCU_GPIOA);
    /* enable ADC clock */
    rcu_periph_clock_enable(RCU_ADC0);
    /* config ADC clock */
    adc_clock_config(ADC_ADCCK_PCLK2_DIV8);
}

/*!
    \brief      configure the GPIO peripheral
    \param[in]  none
    \param[out] none
    \retval     none
*/
void gpio_config(void)
{
    /* config the GPIO as analog mode */
    gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_1);
    gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_2);
    gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_3);
    gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_4);
}

ADC配置

  1. 因为是软件触发 一般是把 连续转换 失能,每次采集时触发一次采样
    1. adc_special_function_config(ADC0, ADC_CONTINUOUS_MODE, DISABLE);
  2. 前面的示例在ADC初始化后立刻使能,一直采样,是因为使用DMA搬运数据;而这里在需要采集的时候,才使能ADC采样,这里采样的频率,可以根据需求来设置,怎么样都可以,提供几种情况供大家参考,比如:
    1. 只在需要的时候采样一次
    2. 通过RTOS任务、裸机的while循环等,来连续采集,并且进行算法滤波。(ADC的各种滤波算法,找时间我也会整理一篇文章,希望大家多多关注哈~)
  3. 示例是多通道采集,但是每次只采集一个通道,所以扫描模式也配置为失能
    1. adc_special_function_config(ADC0, ADC_SCAN_MODE, DISABLE);
/*!
    \brief      configure the ADC peripheral
    \param[in]  none
    \param[out] none
    \retval     none
*/
void adc_config(void)
{
    /* reset ADC */
    adc_deinit();
    /* ADC mode config */
    adc_sync_mode_config(ADC_SYNC_MODE_INDEPENDENT);
    /* ADC contineous function disable */
    adc_special_function_config(ADC0, ADC_CONTINUOUS_MODE, DISABLE);
    /* ADC scan mode disable */
    adc_special_function_config(ADC0, ADC_SCAN_MODE, DISABLE);
    /* ADC data alignment config */
    adc_data_alignment_config(ADC0, ADC_DATAALIGN_RIGHT);
    /* ADC channel length config */
    adc_channel_length_config(ADC0, ADC_ROUTINE_CHANNEL, 1U);

    /* ADC trigger config */
    adc_external_trigger_source_config(ADC0, ADC_ROUTINE_CHANNEL, ADC_EXTTRIG_ROUTINE_T0_CH0); 
    adc_external_trigger_config(ADC0, ADC_ROUTINE_CHANNEL, EXTERNAL_TRIGGER_DISABLE);

    /* enable ADC interface */
    adc_enable(ADC0);
    delay_1ms(1U);
    /* ADC calibration and reset calibration */
    adc_calibration_enable(ADC0);
}

对外接口

每次采样时输入采样通道,通过这个函数的定义就能查看到

/* ADC routine channel config */

adc_routine_channel_config(ADC0, 0U, channel, ADC_SAMPLETIME_15);

形式如下所示,如果为了减少耦合、输入方便等,可以在uint16_t adc_channel_sample(uint8_t channel)外再定义一个新的接口函数,新接口函数的通道由自己定义,函数内完成自定义通道到芯片通道的映射,再输入到uint16_t adc_channel_sample(uint8_t channel)中。

/* ADC channel definitions */
#define ADC_CHANNEL_0                   ((uint8_t)0x00U)                  /*!< ADC channel 0 */
#define ADC_CHANNEL_1                   ((uint8_t)0x01U)                  /*!< ADC channel 1 */
#define ADC_CHANNEL_2                   ((uint8_t)0x02U)                  /*!< ADC channel 2 */
#define ADC_CHANNEL_3                   ((uint8_t)0x03U)                  /*!< ADC channel 3 */
//...
/*!
    \brief      adc_init
    \param[in]  none
    \param[out] none
    \retval     none
*/

void adc_init(void)
{
    /* system clocks configuration */
    rcu_config();
    /* GPIO configuration */
    gpio_config();
    /* ADC configuration */
    adc_config();
}


/*!
    \brief      ADC channel sample
    \param[in]  none
    \param[out] none
    \retval     none
*/
uint16_t adc_channel_sample(uint8_t channel)
{
    /* ADC routine channel config */
    adc_routine_channel_config(ADC0, 0U, channel, ADC_SAMPLETIME_15);
    /* ADC software trigger enable */
    adc_software_trigger_enable(ADC0, ADC_ROUTINE_CHANNEL);

    /* wait the end of conversion flag */
    while(!adc_flag_get(ADC0, ADC_FLAG_EOC));
    /* clear the end of conversion flag */
    adc_flag_clear(ADC0, ADC_FLAG_EOC);
    /* return regular channel sample value */
    return (adc_routine_data_read(ADC0));
}

采样示例

adc的头文件中只需要声明对外接口中的两个函数,在需要的地方调用即可,以下为简单的示例

#include "drv_adc.h"  //包含自己写的adc驱动头文件

uint16_t adc_value[4];

int main(void)
{
    /* 其他系统配置 */
    
    /* ADC 初始化 */
    adc_init();

    while(1)
    {
        adc_value[0]=adc_channel_sample(ADC_CHANNEL_1);
        adc_value[1]=adc_channel_sample(ADC_CHANNEL_2);
        adc_value[2]=adc_channel_sample(ADC_CHANNEL_3);
        adc_value[3]=adc_channel_sample(ADC_CHANNEL_4);
    }
}

定时器触发

待添加...

  • 26
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
gd32f4xx adc (GigaDevice gd32f4xx系列的模拟数位转换器) 是一种广泛应用于电子设备中的模拟信号转换为数字信号的芯片。它具有以下特点与功能。 首先,gd32f4xx adc具有高分辨率和高速率的特点。它能够以较高的精度转换模拟信号为数字信号,并且具有较快的转换速率。这使得gd32f4xx adc在需要精确且快速采样的应用中非常受欢迎,比如工业自动化控制、传感器数据采集等。 其次,gd32f4xx adc具备多通道选择功能。它可以同时转换多个不同通道的模拟信号,从而能够满足多种传感器信号采集的需求。这种多通道选择功能使得gd32f4xx adc在复杂信号采集及处理领域具有广泛应用,比如医疗设备、仪器仪表等。 另外,gd32f4xx adc还具备DMA传输及触发功能。它能够通过DMA进行数据传输,从而减轻主处理器的负担,提高整个系统的效率。同时,gd32f4xx adc还支持多种触发方式,比如软件触发、外部触发等,使得系统能够根据实际需要进行灵活的数据采集控制。 此外,gd32f4xx adc还拥有丰富的中断与事件功能。它能够通过中断及事件进行及时的数据处理和响应,提高系统的实时性和稳定性。这些中断与事件功能使得gd32f4xx adc在实时监控、自动控制等领域具有重要应用,比如智能家居、车载电子等。 总结来说,gd32f4xx adc具有高分辨率、高速率、多通道选择、DMA传输及触发、中断与事件功能等特点与功能。这些特点与功能使得gd32f4xx adc成为一种广泛应用于各种电子设备中的模拟数位转换器,满足实时监控、自动控制等领域的需求。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值