TMS320C5402 DSP驱动LCD显示系统设计与实现

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:本文深入探讨了如何基于数字信号处理器TMS320C5402实现LCD驱动程序,涵盖了初始化、数据传输、控制时序、显示更新和错误处理等核心组件。提供了一个实践案例,分析了名为“dsp_lcdfile.c”的源代码,以及可能包含相关头文件的“lcd”目录,为嵌入式系统工程师提供了一个宝贵的实践机会。

1. 数字信号处理器TMS320C5402基础

数字信号处理器(DSP)是执行快速数学运算,特别是离散时间信号处理的微处理器。TMS320C5402是德州仪器(Texas Instruments)公司生产的一款高性能数字信号处理器,广泛应用于数字通信、消费电子等领域。

TMS320C5402的特性

TMS320C5402提供了一个灵活的外部接口,可通过标准编程模型进行配置,包括一个高速的8/16位外部总线,能够与多种外围设备无缝集成。它拥有独特的指令集,支持乘加(MAC)操作在单个周期内完成,使得其在音频处理、信号分析等应用中表现出色。

TMS320C5402的应用场景

由于其在数字信号处理方面的高性能特性,TMS320C5402通常被用于语音编解码器、数字调制解调器、图形信号处理器等领域。其灵活的内存映射和专用的硬件加速功能使得它在实时系统中具有广泛的应用潜力。

在接下来的章节中,我们将深入探讨TMS320C5402的硬件架构,并介绍如何在不同的应用场景中有效地利用这款DSP芯片。

2. LCD驱动程序的构成和功能

2.1 LCD驱动程序的主要组成部分

2.1.1 驱动程序的硬件接口层

硬件接口层是LCD驱动程序与硬件通信的桥梁,确保了驱动程序能够正确地向LCD发送指令与数据。在这一层中,通常包含了与硬件紧密相关的操作,如引脚控制、时序产生、缓冲区管理等。

// 硬件接口层代码示例(伪代码)
void LCD_Hardware_Init() {
    // 初始化LCD的引脚
    GPIO_Init(LCD_RESET_PIN);
    GPIO_Init(LCD_CS_PIN);
    GPIO_Init(LCD_DATA_PINS);

    // 设置引脚模式为输出
    GPIO_SetMode(LCD_RESET_PIN, OUTPUT);
    GPIO_SetMode(LCD_CS_PIN, OUTPUT);
    for (int i = 0; i < NUM_DATA_PINS; i++) {
        GPIO_SetMode(LCD_DATA_PINS[i], OUTPUT);
    }

    // 硬件复位LCD
    LCD_Reset();
}

void LCD_WriteCommand(uint8_t cmd) {
    // 选择LCD芯片
    LCD_ChipSelect();
    // 发送命令字节
    for (int i = 0; i < 8; i++) {
        GPIO_WritePin(LCD_DATA_PINS[i], (cmd & 0x01) ? HIGH : LOW);
        cmd >>= 1;
    }
    // 取消选择
    LCD_ChipDeselect();
}

在此段代码中,初始化函数负责将LCD相关的引脚设置为输出模式,并执行复位操作。写命令函数 LCD_WriteCommand 则负责将命令字节发送给LCD。代码注释详细解释了每一行代码的作用,确保开发者能够理解硬件接口层的控制逻辑。

2.1.2 驱动程序的逻辑层

逻辑层通常包括数据处理、显示模式管理、颜色处理等功能。它对应用程序隐藏了硬件接口层的细节,并提供了易于使用和理解的接口。

// 逻辑层代码示例(伪代码)
void LCD_SetColor(uint8_t red, uint8_t green, uint8_t blue) {
    uint16_t color = RGB(red, green, blue);
    LCD_WriteCommand(CMD_SET_COLOR);
    LCD_WriteData(color >> 8);
    LCD_WriteData(color & 0xFF);
}

void LCD_DrawPixel(uint16_t x, uint16_t y, uint16_t color) {
    // 计算像素在屏幕上的位置
    uint32_t position = x + y * LCD_WIDTH;
    LCD_SetCursor(position);
    LCD_WriteData(color >> 8);
    LCD_WriteData(color & 0xFF);
}

在以上示例代码中, LCD_SetColor 函数用于设置当前显示颜色,它首先将颜色值组合成一个16位的数值,然后通过LCD的写命令和写数据函数将颜色值发送到LCD。 LCD_DrawPixel 函数用于绘制一个像素点,它计算了像素在屏幕上的位置,并调用 LCD_SetCursor 函数设置光标位置,最后写入颜色值。

2.2 LCD驱动程序的功能特性

2.2.1 显示模式的配置与切换

LCD驱动程序需要支持不同的显示模式,以便在不同的应用场景中切换。显示模式包括了像素格式、色彩深度、显示区域等设置。

// 显示模式配置代码示例(伪代码)
void LCD_SetDisplayMode(LCD_Mode mode) {
    // 根据mode的值配置显示参数
    switch (mode) {
        case MODE_16BIT_COLOR:
            LCD_WriteCommand(CMD_SET_PIXEL_FORMAT, 0x55);
            break;
        case MODE_8BIT_COLOR:
            LCD_WriteCommand(CMD_SET_PIXEL_FORMAT, 0x33);
            break;
        // ... 其他模式的配置
        default:
            // 处理错误或默认模式
            break;
    }
}

在代码中, LCD_SetDisplayMode 函数根据提供的模式配置显示参数。这通常涉及到发送特定的命令到LCD,如设置像素格式、色彩深度等。代码使用 switch 语句来决定发送哪种命令给LCD,以匹配不同的显示模式。

2.2.2 颜色管理和分辨率设置

颜色管理对于保证显示效果至关重要。驱动程序提供了丰富的API来设置和管理色彩深度、色域映射等。此外,分辨率设置需确保屏幕的显示内容符合用户的期望。

// 颜色管理与分辨率设置代码示例(伪代码)
void LCD_SetColorManagement(LCD_ColorSpace colorSpace) {
    // 设置颜色空间参数
    switch (colorSpace) {
        case COLORSPACE_RGB:
            // 设置RGB相关参数
            break;
        case COLORSPACE_BGR:
            // 设置BGR相关参数
            break;
        // ... 其他颜色空间设置
        default:
            // 处理错误或默认设置
            break;
    }
}

void LCD_SetResolution(uint16_t width, uint16_t height) {
    // 设置显示分辨率
    LCD_WriteCommand(CMD_SET_DISPLAY_RESOLUTION);
    LCD_WriteData(width >> 8);
    LCD_WriteData(width & 0xFF);
    LCD_WriteData(height >> 8);
    LCD_WriteData(height & 0xFF);
}

在色彩管理函数 LCD_SetColorManagement 中,通过 switch 语句匹配不同的颜色空间,并根据需要设置相应的参数。分辨率设置函数 LCD_SetResolution 将新的分辨率参数写入LCD,这通常涉及到写入宽度和高度的高8位和低8位值。

在本章的介绍中,我们详细解析了LCD驱动程序的基础构成和功能特性,从硬件接口层到逻辑层,再到显示模式配置与切换、颜色管理和分辨率设置等关键功能。在接下来的章节中,我们会继续探讨LCD驱动程序的其他关键方面,例如硬件初始化过程与配置、数据传输机制与方法、时序控制的策略和实践技巧,以及显示内容的更新策略和错误处理方法。

3. 硬件初始化过程与配置

硬件初始化是确保数字信号处理器能够正确读取、执行程序并对外设进行管理的基石。在初始化过程中,处理器会按照既定的顺序检查各个模块的状态,配置系统关键参数,并验证系统的稳定性。本章节将详细探讨硬件初始化流程,并解析配置策略及接口兼容性问题。

3.1 硬件初始化流程解析

3.1.1 上电自检与初始化序列

当数字信号处理器TMS320C5402加电启动时,首先执行的是上电自检(Power-On Self-Test, POST),这一过程确保处理器的各个核心模块在开始执行用户代码前处于就绪状态。上电自检的流程通常包括:

  1. 内部寄存器的复位和检查;
  2. 内存单元的测试;
  3. 外设接口的检测。

每个步骤都可能包含对错误的检测,如果发现问题,处理器可能会停止启动过程或进入故障处理状态。在POST完成后,处理器将根据存储在非易失性存储器(如Flash)中的信息,进行系统初始化序列,包括:

  1. 处理器时钟的配置;
  2. 存储器控制寄存器的设置;
  3. 外设模块(如GPIO,Timer,ADC等)的初始化。

这一步骤对系统稳定性至关重要,错误的配置可能导致系统无法正常工作。

// 示例:TMS320C5402初始化代码片段
void InitSystem() {
    // 初始化处理器时钟
    CLKCTL = 0x000F; // 设置时钟源和分频

    // 设置存储器控制寄存器
    MEMCTL = 0x000A; // 配置外部存储器接口

    // 初始化外设模块
    GPIO_DIR |= 0x00FF; // 设置GPIO方向为输出
    ...
}

3.1.2 关键参数配置与校验

在硬件初始化过程中,关键参数的配置与校验是确保硬件功能正常运行的关键。对于TMS320C5402,这部分工作通常涉及对其内部模块的详细设置,例如:

  1. 中断向量表的配置;
  2. 外部存储器接口的参数设置;
  3. 时钟管理模块的参数校准。

参数配置不正确可能会引起系统性能下降甚至故障。校验步骤往往采用写入预设值后读取的方式,确保配置成功且稳定。如果校验失败,系统将采取错误处理措施。

3.2 配置策略和接口兼容性

3.2.1 多种接口类型的兼容策略

随着技术的发展,数字信号处理器往往需要支持多种接口类型,以确保与不同外设的兼容。TMS320C5402需要根据设计需求,支持如SPI, I2C, UART等常见通信协议。为了实现这些接口的兼容,硬件初始化需要执行以下策略:

  1. 根据应用需求动态配置接口;
  2. 设置通信速率和格式;
  3. 驱动程序抽象层的实现,用于屏蔽不同接口的具体实现差异。

兼容策略的设计应遵循最小化资源占用和最大化灵活性的原则。

// 示例:配置SPI接口函数
void ConfigureSPI() {
    SPICTL |= 0x0001; // 启用SPI模块
    SPIBaud = 0x000F; // 设置SPI波特率
    ...
}

3.2.2 外设接口的配置与扩展

外设接口的配置与扩展是确保系统灵活性和扩展性的重要方面。除了初始化已安装的外设,系统设计者还应考虑未来可能的扩展需求。这通常通过以下步骤实现:

  1. 分配足够的I/O端口和中断资源;
  2. 设计可重配置的外设接口,以适应不同类型的外设;
  3. 提供扩展接口和模块,便于未来升级和维护。

灵活性和可扩展性是硬件设计中需要重点考虑的问题,以确保数字信号处理系统的长期生命力。

// 示例:外部中断配置函数
void ConfigureInterrupt() {
    INTCTL |= 0x0003; // 配置外部中断行为
    INTMask |= 0x0004; // 启用特定中断源
    ...
}

在接下来的章节中,我们将探讨如何优化数据传输机制和管理显示内容的更新策略,以及如何处理可能出现的错误,并制定相应的恢复策略。

4. 数据传输机制与方法

数据传输是电子设备间交流信息的核心功能,对于数字信号处理器而言,如何高效、可靠地进行数据传输至关重要。本章节将深入探讨数据传输机制与方法,包括底层实现以及高效数据传输策略。

4.1 数据传输的底层实现

底层实现涉及到硬件和软件两个层面的交互,是数据传输过程中最基本的组成部分。正确理解并实现数据传输机制,对提升数据处理速度和系统稳定性有着直接影响。

4.1.1 数据缓冲与批量传输技术

数据缓冲是数据传输过程中解决速率不匹配、异步处理等问题的一种常见方法。通过设置缓冲区,系统可以暂时存储数据,从而平衡发送和接收端之间的速度差异。

为了说明这一点,我们来看一个简化的伪代码示例:

// 伪代码示例:数据缓冲操作
#define BUFFER_SIZE 1024 // 缓冲区大小设置
unsigned char buffer[BUFFER_SIZE]; // 缓冲区数组

int readIndex = 0; // 读索引
int writeIndex = 0; // 写索引

void pushData(unsigned char data) {
    // 将数据写入缓冲区,如果缓冲区已满则等待
    buffer[writeIndex++] = data;
    if (writeIndex >= BUFFER_SIZE) {
        writeIndex = 0; // 循环使用缓冲区
    }
}

unsigned char popData() {
    // 从缓冲区读取数据,如果缓冲区为空则等待
    unsigned char data = buffer[readIndex++];
    if (readIndex >= BUFFER_SIZE) {
        readIndex = 0; // 循环使用缓冲区
    }
    return data;
}

在上述示例中, pushData popData 函数分别实现了数据的写入和读取。当缓冲区满时, pushData 函数将等待,直到缓冲区中有可用空间。同样,如果缓冲区为空, popData 函数也将等待。这种方法减少了数据丢失的可能性,并且可以在不同的速度下传输数据。

4.1.2 传输协议和接口协议

数据传输协议是数据传输过程中必须遵守的规则,其定义了数据如何进行打包、传输以及如何被接收端处理。接口协议则指定了不同设备或组件间数据交换的物理和电气接口标准。

  • 传输协议: 通常包括起始位、数据位、奇偶校验位和停止位。在串行数据传输中尤为重要,确保数据的完整性和可靠性。
  • 接口协议: 比如常见的SPI、I2C、UART、USB等,每种协议都有其特定的速率、数据包大小和电气特性。

4.2 高效数据传输策略

在保障了数据传输的可靠性之后,下一步就是如何提高传输效率。这包括减少传输延时、优化数据结构和算法以降低处理时间等。

4.2.1 减少传输延时的方法

传输延时是影响整体数据传输效率的一个关键因素,尤其是对于实时系统。减少传输延时可以通过多种方式实现:

  • 优先级调整: 为高优先级数据设置更高的传输优先级,确保关键数据能够快速传输。
  • 缓冲优化: 精细调整缓冲区的大小和管理策略,以适应传输速率变化。
  • 中断机制: 利用硬件中断来处理数据传输事件,减少CPU轮询的时间开销。

4.2.2 数据压缩与解压技术

数据压缩是通过算法将数据编码成更少的字节以节省传输时间。对于较大的数据集,压缩效果尤为明显。而数据压缩一般伴随着解压过程,需要平衡压缩率和CPU处理时间。

一个简单的数据压缩例子如下:

// 伪代码示例:简单的数据压缩和解压
void compressData(unsigned char* input, int inputSize, unsigned char* output, int* outputSize) {
    // 简单的重复字节压缩
    int count = 1;
    for (int i = 1; i < inputSize; ++i) {
        if (input[i] == input[i - 1]) {
            count++;
        } else {
            output[(*outputSize)++] = input[i - 1];
            if (count > 1) {
                output[(*outputSize)++] = count; // 记录重复次数
            }
            count = 1;
        }
    }
    output[(*outputSize)++] = input[inputSize - 1];
    if (count > 1) {
        output[(*outputSize)++] = count; // 记录重复次数
    }
}

void decompressData(unsigned char* input, int inputSize, unsigned char* output) {
    int outputIndex = 0;
    for (int i = 0; i < inputSize;) {
        output[outputIndex++] = input[i++];
        if (i < inputSize) {
            int count = input[i++];
            for (int j = 0; j < count; j++) {
                output[outputIndex++] = input[i]; // 重复填充
            }
        }
    }
}

以上代码展示了如何使用简单的重复字节压缩算法来减少数据量,这在不损失任何信息的前提下,可以有效减少传输数据的大小,进而降低延时。

表格:不同压缩技术的比较

下面表格展示了常用的数据压缩技术,并进行了比较:

| 压缩技术 | 压缩率 | 速度 | 复杂度 | 适用场景 | | --- | --- | --- | --- | --- | | Huffman 编码 | 中 | 快 | 低 | 文本、数据文件 | | Lempel-Ziv-Welch (LZW) | 高 | 中 | 中 | 图像、视频 | | Deflate | 高 | 中 | 高 | 网络传输 | | Run-Length 编码 | 低 | 极快 | 低 | 简单图形、动画 |

Mermaid流程图:数据传输过程

flowchart LR
    A[数据源] -->|压缩| B[压缩数据]
    B --> C[传输介质]
    C -->|接收| D[解压]
    D --> E[数据目的地]

以上流程图简单地描述了数据在源和目的地之间的传输过程,包括压缩和解压的环节。正确的压缩和解压策略能够显著提高传输效率,节省带宽资源。

5. 控制时序生成和管理

时序控制是数字系统设计中的关键因素,特别是在显示设备控制中,合适的时序可以确保信息正确无误地显示在屏幕上。本章节将深入探讨时序控制的基础理论和实践技巧,从时序图的解读与分析开始,进而讨论时序参数的计算与优化,最终落实到时序管理的实践技巧,包括时序同步与异步处理,以及实时调度与时序精度调整。

5.1 时序控制的基础理论

在数字电路设计中,时序控制涉及到精确的时间管理,保证数据在正确的时间点被读取或写入。时序图的正确解读与分析是理解和应用时序控制的基础。

5.1.1 时序图的解读与分析

时序图是一种图形工具,用来表示信号状态的变化随时间变化的图表。在显示设备控制中,时序图通常用来描述数据线(D0-Dn)、地址线(A0-An)、控制信号(如读/写信号、时钟信号等)在不同时间点的状态。

一个典型的时序图包括时间轴、信号线、信号状态变化点,以及信号的持续时间。在解读时序图时,需要关注的关键点包括时钟周期、建立时间、保持时间、以及信号的稳定时间。

sequenceDiagram
    participant D as 数据线(D0-Dn)
    participant A as 地址线(A0-An)
    participant R as 读信号
    participant W as 写信号
    participant CLK as 时钟信号

    Note over D,A: 初始化状态
    R->>CLK: 上升沿触发读操作
    W->>CLK: 下降沿触发写操作
    Note over D,A: 数据/地址设置
    D-->>CLK: 数据设置时间
    A-->>CLK: 地址设置时间
    Note over D,A: 数据/地址稳定时间
    D->>CLK: 数据稳定时间
    A->>CLK: 地址稳定时间

在上述时序图中,我们描述了读写操作的时序要求。数据和地址在读写信号的触发下,经过特定的稳定时间后被采样,这保证了数据的正确读写。

5.1.2 时序参数的计算与优化

时序参数的计算是根据硬件特性和所需的数据传输速率来确定的。比如,时钟频率、周期、上升沿和下降沿时间,以及信号的建立时间、保持时间和传播延迟都是需要精心计算的时序参数。

| 参数       | 描述                                                         | 计算公式                   |
|------------|--------------------------------------------------------------|----------------------------|
| 时钟频率   | 时钟信号每秒钟的周期数                                       | F = 1/T (单位: Hz)         |
| 周期       | 时钟信号周期性变化的时间间隔                                 | T = 1/F (单位: 秒)         |
| 建立时间   | 数据信号在时钟边沿之前的最小稳定时间                         | Tsetup                     |
| 保持时间   | 数据信号在时钟边沿之后的最小稳定时间                         | Thold                      |
| 传播延迟   | 信号从输入到输出所需的最小时间                               | Tprop = (L/S) (单位: 秒)   |

时序优化的目的是为了减少信号传播延迟,提高系统的稳定性。优化措施包括减小信号线长度、使用高速缓冲存储器、调整时钟频率等方法。

5.2 时序管理的实践技巧

在实际的时序管理中,设计者需要综合考量硬件的特性和软件的需求,通过软件实现硬件时序的管理。以下介绍时序同步与异步处理的策略,以及如何进行实时调度与时序精度的调整。

5.2.1 时序同步与异步处理

时序同步指的是系统中的所有操作都在统一的时钟信号控制下进行。这种方法简化了设计,但可能会因为时钟信号的传播延迟导致系统性能下降。

异步处理则不需要统一的时钟信号,各部分根据各自的需求进行独立操作。这种方法虽然提高了系统的性能和可靠性,但设计和调试过程相对复杂。

# 异步处理示例代码
import threading

def process_task(task):
    # 处理任务的代码
    pass

def main():
    # 创建线程池,处理多个任务
    with concurrent.futures.ThreadPoolExecutor() as executor:
        for task in tasks:
            executor.submit(process_task, task)

if __name__ == '__main__':
    main()

5.2.2 实时调度与时序精度调整

实时调度是指在满足时序要求的前提下,合理安排任务的执行顺序。这通常需要使用实时操作系统(RTOS)来完成,通过优先级调度或时间片轮转算法保证任务按照既定的时序执行。

gantt
    title 实时任务调度示例
    dateFormat  YYYY-MM-DD
    section Section1
    Task1: done,   des1, 2023-04-01, 3d
    Task2: active, des2, after des1, 3d
    section Section2
    Task3:         des3, after des1, 2d
    Task4:         des4, after des2, 3d

时序精度调整是确保系统长时间稳定运行的关键。可以通过动态调整时钟频率、添加时钟校准机制等方法来实现。

以上章节内容以控制时序生成和管理为核心,从理论到实践,介绍了时序控制的基础知识、时序图的解读分析、时序参数的计算与优化,以及时序同步与异步处理策略、实时调度与时序精度调整等实践技巧。通过对这些内容的深入理解和应用,IT专业人员可以有效地管理显示设备的时序问题,提高设备性能和稳定性。

6. 显示内容更新策略

更新显示内容是图形用户界面中一项常见而重要的任务,它不仅关乎视觉效果,还影响着用户体验和系统性能。内容更新策略的优劣直接决定了显示系统的响应速度和稳定性。

6.1 动态内容更新机制

动态内容更新涉及在显示设备上刷新页面和维护帧缓冲区。这要求驱动程序能够高效地处理每一帧数据,以保证实时性和流畅性。

6.1.1 页面刷新与帧缓冲技术

页面刷新是将新的图像数据写入到屏幕上的过程。在LCD显示系统中,帧缓冲技术允许将待显示的数据先存储在内存中,再一次性刷新到屏幕。这种技术可以减少屏幕闪烁和提高显示质量。

// 简单的帧缓冲更新代码示例
void refresh_frame_buffer(uint8_t* frame_buffer, int width, int height) {
    // 清除帧缓冲区
    memset(frame_buffer, 0, width * height * BYTES_PER_PIXEL);

    // 绘制新帧内容...
    // ...

    // 将帧缓冲区数据发送到LCD
    send_to_lcd(frame_buffer, width, height);
}

6.1.2 实时渲染与帧率控制

实时渲染是指尽可能快速地渲染每一帧图像,而帧率控制则是对渲染过程进行管理,确保显示效果的平滑性和连贯性。为了实现这一目标,驱动程序可能需要实施一种限速机制,以避免过高的帧率消耗大量资源。

6.2 静态内容的高效处理

不同于动态内容,静态内容的处理主要集中在减少不必要的更新和优化显示效率上。

6.2.1 图像缓存策略与优化

对于不需要频繁更新的图像数据,可以采用图像缓存策略。缓存可以存储在高速的内存中,以加快访问速度并减少对存储设备的读取次数。

// 图像缓存策略伪代码
int image_cache[MAX_CACHE_SIZE][IMAGE_HEIGHT][IMAGE_WIDTH]; // 假设是2D图像
for (int i = 0; i < MAX_CACHE_SIZE; ++i) {
    if (image_needs_to_be_updated(i)) {
        // 从存储设备加载新图像到缓存
        load_image_from_disk(&image_cache[i]);
    }
}
// 使用缓存中的图像进行显示...
// ...

6.2.2 内容自适应与优化

内容自适应处理意味着显示内容能够根据不同的环境和需求进行调整。例如,当系统资源紧张时,动态降低分辨率或改变颜色深度可以提升显示效率。

本章节深入探讨了显示内容更新策略,从动态内容更新到静态内容的高效处理,提供了详细的机制分析和优化方法。后续章节将更加详细地阐述错误处理和恢复操作的技术细节。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:本文深入探讨了如何基于数字信号处理器TMS320C5402实现LCD驱动程序,涵盖了初始化、数据传输、控制时序、显示更新和错误处理等核心组件。提供了一个实践案例,分析了名为“dsp_lcdfile.c”的源代码,以及可能包含相关头文件的“lcd”目录,为嵌入式系统工程师提供了一个宝贵的实践机会。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值