05.TMS570LC43入门指南——串口中断

05.TMS570LC43入门指南——串口中断

一、简介

通过上节对串口的学习,我们学会了如何使用串口进行收发操作。通过本节的学习,将首次接触和使用 TMS570LC43 的中断。

通过这篇文章,你将学到以下内容:

  1. 如何使用 HALCoGen 开启中断
  2. 如何使用 SCI(即串口) 中断
  3. 使用其他串口的一些注意事项

开发平台:

  • Windows x64
  • TMS570LC43开发板

二、项目实现

首先我们需要建立 CCS 以及 HALCoGen 工程文件,这里不再赘述,具体操作可以参考我前面的文章,链接如下:

02.TMS570LC43入门指南——点亮LED_tms570lc43xx-CSDN博客

欢迎各位大佬阅读。

其次我们需要认识一下 TMS570LC43 的中断管理器。具体信息可以参考数据手册(官方链接,可放心跳转): ti.com/lit/ds/spns195c/spns195c.pdf。我这里进行简单的总结。

TMS570LC43 有两个片上矢量中断管理器(VIM)模块。VIM模块提供硬件辅助,用于对设备上存在的许多中断源进行优先级排序和控制。中断是由程序执行正常流程之外的事件引起的。通常,这些事件需要CPU及时响应;因此,当中断发生时,CPU将执行从正常程序流切换到中断服务例程(ISR)。

VIM模块具有以下特性:

  • 支持128个中断通道
  • 为请求线路提供可编程优先级
  • 通过屏蔽管理中断通道
  • 将中断通道优先分配给CPU
  • 每次中断时向CPU提供ISR(中断服务程序)的地址

两个VIM模块是同步的。这两个VIM模块被内存映射到相同的地址空间。从程序员模型的角度来看,它只是一个VIM模块。对VIM1寄存器和内存的写入将广播到VIM1和VIM2。从VIM1读取将只读取VIM1寄存器和内存。所有发送到VIM1模块的中断请求也将发送到VIM2模块。

由于VIM1和VIM2具有相同的设置,因此它们都将导致响应相同中断请求的相同输出行为。第二个VIM模块充当诊断检查器模块。两个VIM模块的输出信号被路由到 CCM-R5F 模块,并不断进行比较。检测到的错误比较将作为错误信号发送给 ESM 模块。

本节内容,我们就将学习使用 SCI 的中断。

2.1 硬件部分

对于硬件具体的介绍,可以参考我前一篇文章,在本章中,硬件设备均一致,链接为:04.TMS570LC43入门指南——串口操作

另外,补充上一篇的相关内容。如果需要使用引脚输出的串口,需要使用串口转USB模块,常见的为CH340G模块,某宝上很便宜,有条件的大佬也可自己制作工具。

2.2 软件部分——接收中断

2.2.1 HALCoGen 配置

上节中讲到的基本配置我就不再赘述,我这里之讲解后续步骤。最好阅读一下我上节所讲的配置方法,然后接着根据本文档配置!!!

  1. SCI -> SCI Global 中开启串口接收中断

    在这里插入图片描述

  2. TMS570LC4357ZWT -> VIM Channel 0-31 中勾选 LIN1 High

    在这里插入图片描述

  3. 配置完上述功能后,即可生成程序。依旧使用快捷键 F5 或依次点击 File -> Generate Code

2.2.2 CCS 配置

按照上述步骤后,生成文件,依旧在 CCS 中进行编写逻辑代码的操作。还是先找到我们的 HL_sys_main.c 文件。这里我给出示例代码:

/* USER CODE BEGIN (0) */
/* USER CODE END */

/* Include Files */

#include "HL_sys_common.h"

/* USER CODE BEGIN (1) */
#include "HL_system.h"
#include "HL_sci.h"

#include "stdio.h"
#include "string.h"
/* USER CODE END */

/** @fn void main(void)
*   @brief Application main function
*   @note This function is empty by default.
*
*   This function is called after startup.
*   The user can use this function to implement the application.
*/

/* USER CODE BEGIN (2) */
#define BUF_MAX_SIZE                (1024U)                         // 缓冲区最大大小

/* SCI 状态宏定义 */
#define SCI_RXIDLE                  ((uint8)(0x00))                 // SCI 空闲状态
#define SCI_RXD                     ((uint8)(0x01))                 // SCI 接收到 0x0D
#define SCI_RXEND                   ((uint8)(0x02))                 // SCI 接收完成


/* SCI 结构体 */
typedef struct
{
    uint8               rxstatus;                                   // SCI 接收状态
    uint16              rxlen;                                      // 接收数据长度
    uint8               rxBuf[BUF_MAX_SIZE];                        // 接收缓冲区
}SCI_STR;

SCI_STR sciStr;
/* USER CODE END */

int main(void)
{
/* USER CODE BEGIN (3) */
    _enable_interrupt_();           // 使能中断

    sciInit();

    sciStr.rxstatus = SCI_RXIDLE;

    while(1)
    {
        if (sciStr.rxstatus == SCI_RXEND) {
            sciSend(sciREG1, sciStr.rxlen, sciStr.rxBuf);
            sciStr.rxstatus = SCI_RXIDLE;
            memset(&sciStr.rxBuf[0], 0, sciStr.rxlen);
            sciStr.rxlen = 0;
        }
    }
/* USER CODE END */

    return 0;
}


/* USER CODE BEGIN (4) */
/*
 * @brief       : 串口通知函数
 * @param       : [sci]: sci端口寄存器
 *                [flags]: 中断标志
 * @return      : void
 * @author      : Liu Jiahao
 * @date        : 2024-03-26
 * @version     : v1.1
 * @copyright   : Copyright By Liu Jiahao, All Rights Reserved
 */
void sciNotification(sciBASE_t *sci, uint32 flags)
{
    switch (flags)
    {
    /* 接收中断 */
    case SCI_RX_INT:
    {
        uint8 dat = (uint8)(sci->RD & 0x000000FFU);

        if (sciStr.rxlen < BUF_MAX_SIZE) {
            sciStr.rxBuf[sciStr.rxlen] = dat;
            sciStr.rxlen++;
            if ((dat == (uint8)(0x0D)) && (sciStr.rxstatus != SCI_RXD)) {
                sciStr.rxstatus = SCI_RXD;
            }
            else if ((dat == (uint8)(0x0A)) && sciStr.rxstatus == SCI_RXD) {
                sciStr.rxstatus = SCI_RXEND;
            }
            else {
                sciStr.rxstatus = SCI_RXIDLE;
            }
        }

    }   break;
    default: break;
    }
}
/* USER CODE END */

同时,如果要实现该功能,还需要更改生成的函数。由于我们之前在 HALCoGen 中勾选了 LIN1 High 中断。此时我们可以看到 HL_sci.c 文件中多了一个函数 lin1HighLevelInterrupt,这是其中断服务函数,而我们需要做出如下修改:

/* SourceId : SCI_SourceId_022 */
/* DesignId : SCI_DesignId_017 */
/* Requirements : HL_CONQ_SCI_SR20, HL_CONQ_SCI_SR21 */
/** @fn void lin1HighLevelInterrupt(void)
*   @brief Level 0 Interrupt for SCI1
*/
#pragma CODE_STATE(lin1HighLevelInterrupt, 32)
#pragma INTERRUPT(lin1HighLevelInterrupt, IRQ)

void lin1HighLevelInterrupt(void)
{
    uint32 vec = sciREG1->INTVECT0;
    /******************************** 注释以下内容 **********************************/
//    uint8 byte;
/* USER CODE BEGIN (28) */
/* USER CODE END */

    switch (vec)
    {
    case 1U:
        sciNotification(sciREG1, (uint32)SCI_WAKE_INT);
        break;
    case 3U:
        sciNotification(sciREG1, (uint32)SCI_PE_INT);
        break;
    case 6U:
        sciNotification(sciREG1, (uint32)SCI_FE_INT);
        break;
    case 7U:
        sciNotification(sciREG1, (uint32)SCI_BREAK_INT);
        break;
    case 9U:
        sciNotification(sciREG1, (uint32)SCI_OE_INT);
        break;

    case 11U:
        /* receive */
        /******************************** 增加以下内容 **********************************/
        sciNotification(sciREG1, (uint32)SCI_RX_INT);
        /******************************** 注释以下内容 **********************************/
//        byte = (uint8)(sciREG1->RD & 0x000000FFU);
//
//            if (g_sciTransfer_t[0U].rx_length > 0U)
//            {
//                *g_sciTransfer_t[0U].rx_data = byte;
//                g_sciTransfer_t[0U].rx_data++;
//
//                g_sciTransfer_t[0U].rx_length--;
//                if (g_sciTransfer_t[0U].rx_length == 0U)
//                {
//                    sciNotification(sciREG1, (uint32)SCI_RX_INT);
//                }
//            }
        
        break;

    case 12U:
        /* transmit */
		/*SAFETYMCUSW 30 S MR:12.2,12.3 <APPROVED> "Used for data count in Transmit/Receive polling and Interrupt mode" */
		--g_sciTransfer_t[0U].tx_length;
        if (g_sciTransfer_t[0U].tx_length > 0U)
        {
			uint8 txdata = *g_sciTransfer_t[0U].tx_data;
            sciREG1->TD = (uint32)txdata;
            g_sciTransfer_t[0U].tx_data++;
        }
        else
        {
            sciREG1->CLEARINT = SCI_TX_INT;
            sciNotification(sciREG1, (uint32)SCI_TX_INT);
        }
        break;

    default:
        /* phantom interrupt, clear flags and return */
        sciREG1->FLR = sciREG1->SETINTLVL & 0x07000303U;
         break;
    }
/* USER CODE BEGIN (29) */
/* USER CODE END */
}

经过上述操作,我们就可以使用串口中断了。但是发送字节的末尾要跟上换行符(即0x0D、0x0A)。我们先看看效果(依旧采用上节配置的 115200 8bits数据位 1bit停止位 无校验位):

在这里插入图片描述

接下来我将阐述上述代码。

首先,对于 HL_sys_main.c 文件,我们实现的功能是将收到的数据再次发送出去,并且用 换行符(即0x0D、0x0A) 进行判断接收是否结束。

其次,对于 HL_sci.c 文件,我们修改了中断服务函数,中断产生后,复位中断,并且发送 SCI_RX_INT 通知给 sciNotification 函数进行处理。修改中断服务函数是由于,原先的服务函数是需要结构体提前输入参数的,而输入参数就需要使用到其库中原本的函数 sciReceivesciReceiveByte,并不是这两个函数有问题,而是其输入参数需要写明需要接收的字节数,这对于实际情况而言,我们并不知道这一帧数据有多少个字节,所以其不够灵活,于是我将它注释掉了。

那么有的朋友会问了,sciNotification 这个函数在这个中断中我知道,那别的中断呢?其实,相信使用过 STM32 HAL 库 的朋友对这个都不陌生,其 HAL 库也采用类似于这种的中断->通知的方法。我们看到项目文件中的 source 目录下,存在一个叫做 HL_notification.c 的文件,这个文件里包含通知函数,有些朋友也喜欢将函数实现直接写在这里面,我是在外部进行了实现,两种方法均可。这里我粘贴出,HL_notification.c 中的SCI通知函数:

#pragma WEAK(sciNotification)
void sciNotification(sciBASE_t *sci, uint32 flags)     
{
/*  enter user code between the USER CODE BEGIN and USER CODE END. */
/* USER CODE BEGIN (32) */
/* USER CODE END */
}

这里提一句,自己的代码需要写在 USER CODE BEGINUSER CODE END 中间,否则下次使用 HALCoGen 对该项目生成文件的时候会覆盖调你写的代码。

可以看到,其使用了 弱函数 声明,关于该解释可以跳转 _weak 弱函数-CSDN博客 进行阅读。我在这里进行简单介绍,带 weak 的函数和不带 weak 的函数可以同时存在,如果有不带 weak 的函数,就会优先链接不带 weak 的实现,如果没有找到不带 weak 的实现函数,就会使用 weak 函数作为默认的实现。

我这里再次推荐一篇不错的文,讲解有关 weak 的知识:

使用 weak(弱函数)构建跨平台的C语言代码 - 知乎 (zhihu.com)

  • 如无法跳转,可以复制进行手动跳转: https://zhuanlan.zhihu.com/p/616109439

言归正传,我在 HL_sys_main.c 文件中重新定义了 sciNotification 函数并进行了实现。由此,我们就完成了有关 SCI 中断接收 的工作。如果之前有 stm32 HAL 库开发经验的朋友,相信对这部分理解起来还是很快的,不熟悉的朋友可以再次看看源码是如何实现的。

2.3 软件部分——发送中断

既然我们实现了接收中断,那么对应的发送中断也应当玩一玩,好处呢就是,发送数据的时候不需要在等待寄存器标志上浪费时间,那么你就可以让程序继续运行在主函数中

为了方便,我们直接使用 2.2 中的配置,继续在此基础上进行增加

2.3.1 HALCoGen 配置

SCI1 -> SCI Global 中勾选 RX INT:

在这里插入图片描述

设置完成后,别忘了生成文件!!!

2.3.2 CCS 配置

同样,对上述代码进行修改,这里我给出 HL_sys_main.c 的示例:

/* USER CODE BEGIN (0) */
/* USER CODE END */

/* Include Files */

#include "HL_sys_common.h"

/* USER CODE BEGIN (1) */
#include "HL_system.h"
#include "HL_sci.h"

#include "stdio.h"
#include "string.h"
/* USER CODE END */

/** @fn void main(void)
*   @brief Application main function
*   @note This function is empty by default.
*
*   This function is called after startup.
*   The user can use this function to implement the application.
*/

/* USER CODE BEGIN (2) */
#define BUF_MAX_SIZE                (1024U)                         // 缓冲区最大大小

/* SCI 状态宏定义 */
#define SCI_RXIDLE                  ((uint8)(0x00))                 // SCI 空闲状态
#define SCI_RXD                     ((uint8)(0x01))                 // SCI 接收到 0x0D
#define SCI_RXEND                   ((uint8)(0x02))                 // SCI 接收完成

#define SCI_TXIDLE                  ((uint8)(0x00))                 // SCI 发送空闲状态
#define SCI_TXON                    ((uint8)(0x01))                 // SCI 正在发送状态


/* SCI 结构体 */
typedef struct
{
    uint8               rxstatus;                                   // SCI 接收状态
    uint16              rxlen;                                      // 接收数据长度
    uint8               rxBuf[BUF_MAX_SIZE];                        // 接收缓冲区

    uint8               txstatus;                                   // SCI 发送状态
    uint16              txlen;                                      // 发送数据长度
    uint8               txBuf[BUF_MAX_SIZE];                        // 发送缓冲区
}SCI_STR;

SCI_STR sciStr;
/* USER CODE END */

int main(void)
{
/* USER CODE BEGIN (3) */
    _enable_interrupt_();           // 使能中断

    sciInit();

    sciStr.rxstatus = SCI_RXIDLE;
    sciStr.txstatus = SCI_TXIDLE;

    while(1)
    {
        if ((sciStr.rxstatus == SCI_RXEND) && (sciStr.txstatus == SCI_TXIDLE)) {
            memcpy(&sciStr.txBuf[0], &sciStr.rxBuf[0], sciStr.rxlen);
            sciStr.txlen = sciStr.rxlen;
            sciStr.txstatus = SCI_TXON;
            sciSend(sciREG1, sciStr.txlen, sciStr.txBuf);

            sciStr.rxstatus = SCI_RXIDLE;
            memset(&sciStr.rxBuf[0], 0, sciStr.rxlen);
            sciStr.rxlen = 0;
        }
    }
/* USER CODE END */

    return 0;
}


/* USER CODE BEGIN (4) */
/*
 * @brief       : 串口通知函数
 * @param       : [sci]: sci端口寄存器
 *                [flags]: 中断标志
 * @return      : void
 * @author      : Liu Jiahao
 * @date        : 2024-03-26
 * @version     : v1.1
 * @copyright   : Copyright By Liu Jiahao, All Rights Reserved
 */
void sciNotification(sciBASE_t *sci, uint32 flags)
{
    switch (flags)
    {
    /* 接收中断 */
    case SCI_RX_INT:
    {
        uint8 dat = (uint8)(sci->RD & 0x000000FFU);

        if (sciStr.rxlen < BUF_MAX_SIZE) {
            sciStr.rxBuf[sciStr.rxlen] = dat;
            sciStr.rxlen++;
            if ((dat == (uint8)(0x0D)) && (sciStr.rxstatus != SCI_RXD)) {
                sciStr.rxstatus = SCI_RXD;
            }
            else if ((dat == (uint8)(0x0A)) && sciStr.rxstatus == SCI_RXD) {
                sciStr.rxstatus = SCI_RXEND;
            }
            else {
                sciStr.rxstatus = SCI_RXIDLE;
            }
        }

    }   break;
    /* 发送完成中断 */
    case SCI_TX_INT:
    {
        sciStr.txstatus = SCI_TXIDLE;
        memset(&sciStr.txBuf[0], 0, sciStr.txlen);
    }   break;
    default: break;
    }
}
/* USER CODE END */

同样,由于我们重新生成过代码,故需要重新在 HL_sci.c 中修改:

/* SourceId : SCI_SourceId_022 */
/* DesignId : SCI_DesignId_017 */
/* Requirements : HL_CONQ_SCI_SR20, HL_CONQ_SCI_SR21 */
/** @fn void lin1HighLevelInterrupt(void)
*   @brief Level 0 Interrupt for SCI1
*/
#pragma CODE_STATE(lin1HighLevelInterrupt, 32)
#pragma INTERRUPT(lin1HighLevelInterrupt, IRQ)

void lin1HighLevelInterrupt(void)
{
    uint32 vec = sciREG1->INTVECT0;
    /******************************** 注释以下内容 **********************************/
//    uint8 byte;
/* USER CODE BEGIN (28) */
/* USER CODE END */

    switch (vec)
    {
    case 1U:
        sciNotification(sciREG1, (uint32)SCI_WAKE_INT);
        break;
    case 3U:
        sciNotification(sciREG1, (uint32)SCI_PE_INT);
        break;
    case 6U:
        sciNotification(sciREG1, (uint32)SCI_FE_INT);
        break;
    case 7U:
        sciNotification(sciREG1, (uint32)SCI_BREAK_INT);
        break;
    case 9U:
        sciNotification(sciREG1, (uint32)SCI_OE_INT);
        break;

    case 11U:
        /* receive */
        /******************************** 增加以下内容 **********************************/
        sciNotification(sciREG1, (uint32)SCI_RX_INT);
        /******************************** 注释以下内容 **********************************/
//        byte = (uint8)(sciREG1->RD & 0x000000FFU);
//
//            if (g_sciTransfer_t[0U].rx_length > 0U)
//            {
//                *g_sciTransfer_t[0U].rx_data = byte;
//                g_sciTransfer_t[0U].rx_data++;
//
//                g_sciTransfer_t[0U].rx_length--;
//                if (g_sciTransfer_t[0U].rx_length == 0U)
//                {
//                    sciNotification(sciREG1, (uint32)SCI_RX_INT);
//                }
//            }
        
        break;

    case 12U:
        /* transmit */
		/*SAFETYMCUSW 30 S MR:12.2,12.3 <APPROVED> "Used for data count in Transmit/Receive polling and Interrupt mode" */
		--g_sciTransfer_t[0U].tx_length;
        if (g_sciTransfer_t[0U].tx_length > 0U)
        {
			uint8 txdata = *g_sciTransfer_t[0U].tx_data;
            sciREG1->TD = (uint32)txdata;
            g_sciTransfer_t[0U].tx_data++;
        }
        else
        {
            sciREG1->CLEARINT = SCI_TX_INT;
            sciNotification(sciREG1, (uint32)SCI_TX_INT);
        }
        break;

    default:
        /* phantom interrupt, clear flags and return */
        sciREG1->FLR = sciREG1->SETINTLVL & 0x07000303U;
         break;
    }
/* USER CODE BEGIN (29) */
/* USER CODE END */
}

那我,我们先运行之后看看效果:

在这里插入图片描述

大家一定不要忘记,发送的时候勾选上发送新行。由此,发送中断完成,下面我将解释上述代码。

首先,对于 HL_sys_main.c 文件,我依旧使用了 sciNotification 通知函数进行解析,大家可以看到,我对 SCI_TX_INT 的注释是 发送完成中断。为什么这样写呢,那是因为,大家可以看到 HL_sci.c 中的 lin1HighLevelInterrupt 函数中对于发送中断的处理,这部分写的还是比较好的,大家可以放心使用。我们在发送的时候只需要调用 sciSendsciSendByte 即可,TI对于这部分的代码做的还不错,所以我也没有进行修改。我们可以看到,其操作是,发送完成后才通知 SCI_TX_INT 标志,故我注释的是 发送完成中断


三、一些小问题

3.1使用 SCI2、SCI3、SCI4的配置问题

我们使用 SCI1 的时候,它只需要我上述的简单配置,但对于其他串口,我们需要在 HALCoGen 中勾选 PINMUX 才能正确输出,如下所示:

在这里插入图片描述

大家可以按照需要进行勾选,这也是大多数人明明配置好SCI但引脚没有输出的原因!!!

3.2 必须要使能中断

大家可以看到我上述的代码中,在 main 函数中的第一句是:

_enable_interrupt_();           // 使能中断

这一句是必要的,否则中断不生效!!!

3.3 串口中断线优先级

串口中断的时候,其实有两个优先级可以选择,我这里说的不是总中断里面的优先级,总中断里面的优先级可以自定义,而串口里面自带两个优先等级供选择:

在这里插入图片描述

大家可以看到分为 Low LevelHigh Level,通常默认情况下都是 High Level,其在 VIM 中如下所示:

在这里插入图片描述

上图来源为数据手册:ti.com/lit/ds/spns195c/spns195c.pdf

HALCoGen 中分别为 LIN1 HighLIN1 Low,大家可以自行查看。


四、写在最后

本文介绍了 如何在TMS570LC43上进行串口中断收发的操作以及一些配置的小问题。另外,该方法不建议用在具体项目中,否则每一帧数据都要加帧结束的判定。

在后续的文章中,将继续对 TMS570LC43x 进行详细的入门指导,欢迎读者关注!!!

目前暂时没有考虑整合的打算,所以各位读者如果需要看别的教程,可以点进 专栏 进行查找。在后续的更新中,将会逐步加入各个文章的链接,以便大家快速翻阅。另外源码会逐步开源。

欢迎广大读者提出问题以及修改意见,本人看到后会给予回应,欢迎留言,后续会逐步进行开源!!!
另外,由于文章是作者手打的文字,有些地方可能文字会出错,望谅解,也可私信联系我,我对其进行更改。

  • 20
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: autonavi.tms是一种面向位置服务的开发平台,由高德地图提供支持。该平台提供了丰富的地图和位置数据,便于开发者进行地图应用的制作和应用程序的开发。autonavi.tms可以实现地图显示、地图搜索、路径规划等功能,并且还提供了个性化地图定制和数据可视化功能,为开发者提供了更多的自由度。 自动导航技术是指利用计算机、无线通信等信息技术对车辆的位置、路况等信息进行处理和分析,并输出导航指令,指引驾驶员规避交通拥堵、避开危险路段,以达到较高的导航准确度和安全性。 在日常生活中,自动导航技术被广泛应用于各个领域,如出行导航、旅游景点查询等,为人们提供了更为便捷、快捷的出行体验。autonavi.tms作为自动导航技术的实现平台,正在为更多的应用场景提供优质、可靠的地图和数据服务,推动自动导航技术的发展和普及。 ### 回答2: Autonavi是一家提供数字地图和车联网解决方案的公司。其中,Autonavi.tms是该公司的一个重要产品。它是一种运输管理系统,可以帮助企业提高运输效率、降低成本,优化物流管理过程。Autonavi.tms的主要功能包括路线规划、运输调度、车辆跟踪、数据分析等。它可以通过与其他软件和硬件系统集成,实现实时监控车辆位置、温度、湿度等数据,确保货物的安全运输。同时,Autonavi.tms还提供了数据分析和报表功能,帮助企业了解运输的成本和效率,并根据数据做出优化决策。由于物流管理对于企业运营至关重要,因此,Autonavi.tms的推出可以为企业提供更为科学的、精准的管理方案,从而提高品牌竞争力和市场占有率。总之,Autonavi.tms是一种智能化、高效率的运输管理系统,可帮助企业优化物流流程,节约成本,提高效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值