七、赛普拉斯EZ-USB FX3 I2C

一、简介

          1.1 I2C简介

                I2C(Inter-Integrated Circuit)是一种串行通信总线,由飞利浦公司在1980年代为了让主机连接其它外设而定制的一种低速通信协议,目前广泛应用于手机、电脑、家电等嵌入式设备。

图1.0 典型的I2C总线(挂载多个从设备)

         1.2 电气特性

                I2C使用两根数据总线,一根是数据线(SDA),一根是时钟线(SCL),采用双向漏极开路,并使用电阻进行上拉,I2C允许比较大的工作电压范围,但一般采用3.3V或者5V。设备地址使用7位长度和10位长度。I2C 传输速率有不同的模式:

                ·标准模式:100Kbit/s

                ·快速模式:400Kbit/s

                ·高速模式:3.4Mbit/s

图1.1 I2C内部结构图

        1.3 I2C 协议层  

                        1.3.1 I2C读写帧格式

 图1.2 I2C写一个字节数据

 图1.3 I2C读一个字节数据

                         1.3.2 I2C起始信号

                                当主机要与从机开始通信时需要发送起始信号,SCL线在高电平时,SDA线由高变为低。一般流程是拉高SCL线与SDA线保持4us,再拉低SDA线保持4us,最后拉低SCL。

图1.4 I2C起始信号

                         1.3.3 I2C停止信号

                                当主机要与从机结束通信时需要发送停止信号,SCL线在高电平时,SDA线由低变为高。一般流程是拉低SCL线和SDA线保持4us,再拉高SCL线和SDA线保持4us。

 图1.5 I2C停止信号

                         1.3.4 I2C应答信号

                                应答信号也相当于一位数据,SCL为高时,数据线拉低,表示为应答。

图1.6 I2C应答信号 

                         1.3.5 I2C非应答信号 

                                非应答信号也相当于一位数据,SCL为高时,数据线拉高,表示为非应答。

 图1.7 I2C非应答信号

                         1.3.6 I2C数据

                                数据的传输格式,高位先发,SCL为高时数据有效,SCL为低时数据变化。

 图1.8 一个字节数据传输示例

二、程序

        I2C设备初始化函数

 extern CyU3PReturnStatus_t
CyU3PI2cInit (
        void);

        I2C配置函数

 extern CyU3PReturnStatus_t
CyU3PI2cSetConfig (
        CyU3PI2cConfig_t *config,       /**< I2C configuration settings */
        CyU3PI2cIntrCb_t cb             /**< Callback for getting the events */
        );

         I2C读数据函数

extern CyU3PReturnStatus_t
CyU3PI2cReceiveBytes (
        CyU3PI2cPreamble_t *preamble,   /**< Preamble information to be sent out before the data transfer. */
        uint8_t *data,                  /**< Pointer to buffer where the data is to be placed. */
        uint32_t byteCount,             /**< Size of the transfer in bytes. */
        uint32_t retryCount             /**< Number of times to retry request in case of a NAK response or error. */
        );

        I2C写数据函数

extern CyU3PReturnStatus_t
CyU3PI2cTransmitBytes (
        CyU3PI2cPreamble_t *preamble,   /**< Preamble information to be sent out before the data transfer. */
        uint8_t *data,                  /**< Pointer to buffer containing data to be written. */
        uint32_t byteCount,             /**< Size of the transfer in bytes. */
        uint32_t retryCount             /**< Number of times to retry request in case of a slave NAK response. */
        );

        I2C源文件

#include "cyfx3_i2c.h"
#include "cyu3error.h"
#include "cyu3gpio.h"
#include "cyu3utils.h"


static CyU3PReturnStatus_t CyFx3GpioConfig(void)
{
	CyU3PReturnStatus_t CyFx3Status = CY_U3P_SUCCESS;

	//GPIO时钟配置(整个工程中只需要初始化一次)
	CyU3PGpioClock_t GpioClkConifg = {
		.fastClkDiv = 2,
		.slowClkDiv = 0,
		.halfDiv = 0,
		.simpleDiv = CY_U3P_GPIO_SIMPLE_DIV_BY_2,
		.clkSrc = CY_U3P_SYS_CLK,
	};
	CyFx3Status = CyU3PGpioInit(&GpioClkConifg,NULL);

#if !I2C_HARDWARE

	//重定向为普通IO
	CyU3PDeviceGpioOverride(I2C_SDA_GPIO_PIN,CyTrue);
	CyU3PDeviceGpioOverride(I2C_SCL_GPIO_PIN,CyTrue);

	//GPIO配置为输出模式,不使能中断
	CyU3PGpioSimpleConfig_t I2cSdaGpioConfig = {
			.outValue = CyTrue,
			.driveLowEn = CyTrue,
			.driveHighEn = CyTrue,
			.inputEn = CyFalse,
			.intrMode = CY_U3P_GPIO_NO_INTR,
	};
	CyFx3Status = CyU3PGpioSetSimpleConfig(I2C_SDA_GPIO_PIN,&I2cSdaGpioConfig);

	CyU3PGpioSimpleConfig_t I2cSclGpioConfig = {
				.outValue = CyTrue,
				.driveLowEn = CyTrue,
				.driveHighEn = CyTrue,
				.inputEn = CyFalse,
				.intrMode = CY_U3P_GPIO_NO_INTR,
		};
	CyFx3Status = CyU3PGpioSetSimpleConfig(I2C_SCL_GPIO_PIN,&I2cSclGpioConfig);

	if(CyFx3Status != CY_U3P_SUCCESS)
	{
		return CyFx3Status;
	}

#endif

	return CyFx3Status;
}


CyU3PReturnStatus_t CyFx3I2cInit(void)
{
	CyU3PReturnStatus_t CyFx3Status;

#if I2C_HARDWARE
	CyFx3Status = CyU3PI2cInit();
	if(CyFx3Status != CY_U3P_SUCCESS)
	{
		return CyFx3Status;
	}

	CyU3PI2cConfig_t I2cConfig = {
		.bitRate = I2C_FREQUENCY,
		.isDma = CyFalse,
		.busTimeout = I2C_BUS_TIMEOUT_VALUE,
		.dmaTimeout = I2C_DMA_TIMEOUT_VALUE,
	};
	return CyU3PI2cSetConfig(&I2cConfig,NULL);

#else

	return CyFx3GpioConfig();
#endif
}

#if I2C_HARDWARE

CyU3PReturnStatus_t CyFx3I2cReadBytes(uint8_t  DevAddr,
									  uint16_t RegAddr,
									  uint8_t  *ReadData,
									  uint32_t ReadLen,
									  uint32_t RetryCnt,
									  uint8_t  RegBit)
{
	CyU3PI2cPreamble_t Preanble;

	if(RegBit == I2C_REG_8BIT_ADDR)
	{
		Preanble.buffer[0] = (DevAddr << 1) | I2C_CMD_WRITE;
		Preanble.buffer[1] = (RegAddr & 0xff);
		Preanble.buffer[2] = (DevAddr << 1) | I2C_CMD_READ;
		Preanble.length = 3;
		Preanble.ctrlMask = 0x0002;
	}
	else
	{
		Preanble.buffer[0] = (DevAddr << 1) | I2C_CMD_WRITE;
		Preanble.buffer[1] = (RegAddr >> 8);
		Preanble.buffer[2] = (RegAddr & 0xff);
		Preanble.buffer[3] = (DevAddr << 1) | I2C_CMD_READ;
		Preanble.length = 4;
		Preanble.ctrlMask = 0x0004;
	}

	return CyU3PI2cReceiveBytes(&Preanble,ReadData,ReadLen,RetryCnt);
}

CyU3PReturnStatus_t CyFx3WriteBytes(uint8_t  DevAddr,
									uint16_t RegAddr,
									uint8_t  *WriteData,
									uint32_t WriteLen,
									uint32_t RetryCnt,
									uint8_t  RegBit)
{
	CyU3PI2cPreamble_t Preanble;

	if(RegBit == I2C_REG_8BIT_ADDR)
	{
		Preanble.buffer[0] = (DevAddr << 1) | I2C_CMD_WRITE;
		Preanble.buffer[1] = (RegAddr & 0xff);
		Preanble.length = 2;
		Preanble.ctrlMask = 0x0000;
	}
	else
	{
		Preanble.buffer[0] = (DevAddr << 1) | I2C_CMD_WRITE;
		Preanble.buffer[1] = (RegAddr >> 8);
		Preanble.buffer[2] = (RegAddr & 0xff);
		Preanble.length = 3;
		Preanble.ctrlMask = 0x0000;
	}

	return CyU3PI2cTransmitBytes(&Preanble,WriteData,WriteLen,RetryCnt);
}

#else

CyU3PReturnStatus_t I2cSdaIn(void)
{
	//GPIO配置为输出模式,不使能中断
	CyU3PGpioSimpleConfig_t I2cSdaGpioConfig = {
			.outValue = CyTrue,
			.driveLowEn = CyFalse,
			.driveHighEn = CyFalse,
			.inputEn = CyTrue,
			.intrMode = CY_U3P_GPIO_NO_INTR,
	};
	return CyU3PGpioSetSimpleConfig(I2C_SDA_GPIO_PIN,&I2cSdaGpioConfig);
}


CyU3PReturnStatus_t I2cSdaOut(void)
{
	CyU3PGpioSimpleConfig_t I2cSdaGpioConfig = {
				.outValue = CyTrue,
				.driveLowEn = CyTrue,
				.driveHighEn = CyTrue,
				.inputEn = CyFalse,
				.intrMode = CY_U3P_GPIO_NO_INTR,
		};
	return CyU3PGpioSetSimpleConfig(I2C_SDA_GPIO_PIN,&I2cSdaGpioConfig);
}


static CyU3PReturnStatus_t I2cSetSdaValue(CyBool_t isHigh)
{
	return CyU3PGpioSetValue(I2C_SDA_GPIO_PIN,isHigh);
}

static CyU3PReturnStatus_t I2cSetSclValue(CyBool_t isHigh)
{
	return CyU3PGpioSetValue(I2C_SCL_GPIO_PIN,isHigh);
}

static CyBool_t I2cGetSdaValue(void)
{
	return CyFx3GpioReadBit(I2C_SDA_GPIO_PIN);
}


void I2CStart(void)
{
	I2cSdaOut();
	I2cSetSdaValue(CyTrue);
	I2cSetSclValue(CyTrue);
	CyU3PBusyWait(4);
	I2cSetSdaValue(CyFalse);
	CyU3PBusyWait(4);
	I2cSetSclValue(CyFalse);
}

void I2cStop(void)
{
	I2cSdaOut();
	I2cSetSclValue(CyFalse);
	I2cSetSdaValue(CyFalse);
	CyU3PBusyWait(4);
	I2cSetSclValue(CyTrue);
	I2cSetSdaValue(CyTrue);
	CyU3PBusyWait(4);
}

CyBool_t I2cWaitAck(void)
{
	uint8_t ErrTime = 0;

	I2cSdaIn();
	I2cSetSdaValue(CyTrue);
	CyU3PBusyWait(1);
	I2cSetSclValue(CyTrue);
	CyU3PBusyWait(1);
	while(I2cGetSdaValue() == CyTrue)
	{
		ErrTime++;
		if(ErrTime > 250)
		{
			I2cStop();
			return CyTrue;
		}
	}
	I2cSetSclValue(CyFalse);
	return CyFalse;
}

void I2cAck(void)
{
	I2cSdaOut();
	I2cSetSclValue(CyFalse);
	I2cSetSdaValue(CyFalse);
	CyU3PBusyWait(2);
	I2cSetSclValue(CyTrue);
	CyU3PBusyWait(2);
	I2cSetSclValue(CyFalse);
}

void I2cNAck(void)
{
	I2cSdaOut();
	I2cSetSclValue(CyFalse);
	I2cSetSdaValue(CyTrue);
	CyU3PBusyWait(2);
	I2cSetSclValue(CyTrue);
	CyU3PBusyWait(2);
	I2cSetSclValue(CyFalse);
}

void I2cWriteByte(uint8_t Data)
{
    uint8_t i;

    I2cSdaOut();
    I2cSetSclValue(CyFalse);
    for(i = 0;i < 8;i++)
    {
		if((Data & 0x80) >> 7)
		{
			I2cSetSdaValue(CyTrue);
		}
		else
		{
			I2cSetSdaValue(CyFalse);
		}
		Data <<= 1;
		CyU3PBusyWait(2);
		I2cSetSclValue(CyTrue);
		CyU3PBusyWait(2);
		I2cSetSclValue(CyFalse);
		CyU3PBusyWait(2);
    }
}

uint8_t I2cReadByte(CyBool_t isAck)
{
	uint8_t i;
	uint8_t Data = 0x0;

	I2cSdaIn();

    for(i = 0;i < 8;i++ )
	{
    	I2cSetSclValue(CyFalse);
    	CyU3PBusyWait(2);
		I2cSetSclValue(CyTrue);
		Data <<= 1;
        if(I2cGetSdaValue() == CyTrue)
		{
        	Data++;
		}
        CyU3PBusyWait(1);
    }
    if(isAck)
	{
    	I2cAck();
	}
    else
	{
    	I2cNAck();
	}
    return Data;
}

CyU3PReturnStatus_t CyFx3I2cReadBytes(uint8_t  DevAddr,
									  uint16_t RegAddr,
									  uint8_t  *ReadData,
									  uint32_t ReadLen,
									  uint32_t RetryCnt,
									  uint8_t  RegBit)
{
	uint32_t i = 0;

	I2CStart();
	I2cWriteByte((DevAddr << 1) | I2C_CMD_WRITE);
	I2cWaitAck();
	if(RegBit == I2C_REG_8BIT_ADDR)
	{
		I2cWriteByte(RegAddr);
		I2cWaitAck();
	}
	else
	{
		I2cWriteByte((uint8_t)(RegAddr >> 8));
		I2cWaitAck();
		I2cWriteByte((uint8_t)(RegAddr & 0xFF));
		I2cWaitAck();
	}

	I2CStart();
	I2cWriteByte((DevAddr << 1) | I2C_CMD_READ);
	I2cWaitAck();

	if(ReadLen > 1)
	{
		for(i = 0 ;i < ReadLen - 1;i++)
		{
			ReadData[i] = I2cReadByte(CyTrue);
		}
	}
	ReadData[i] = I2cReadByte(CyFalse);
	I2cStop();

	return CY_U3P_SUCCESS;
}

CyU3PReturnStatus_t CyFx3WriteBytes(uint8_t  DevAddr,
									uint16_t RegAddr,
									uint8_t  *WriteData,
									uint32_t WriteLen,
									uint32_t RetryCnt,
									uint8_t  RegBit)
{
	uint32_t i;

	I2CStart();
	I2cWriteByte((DevAddr << 1) | I2C_CMD_WRITE);
	I2cWaitAck();
	if(RegBit == I2C_REG_8BIT_ADDR)
	{
		I2cWriteByte(RegAddr);
		I2cWaitAck();
	}
	else
	{
		I2cWriteByte((uint8_t)(RegAddr >> 8));
		I2cWaitAck();
		I2cWriteByte((uint8_t)(RegAddr & 0xFF));
		I2cWaitAck();
	}

	for(i = 0 ;i < WriteLen;i++)
	{
		I2cWriteByte(WriteData[i]);
		if(I2cWaitAck())
		{
			I2cStop();
			return CY_U3P_ERROR_TIMEOUT;
		}
		CyU3PBusyWait(2);
	}
	I2cStop();

	return CY_U3P_SUCCESS;
}

#endif

        I2C头文件

#ifndef CYFX3_I2C_H_
#define CYFX3_I2C_H_

#include "cyu3i2c.h"
#include "gpio_regs.h"

#define I2C_BUS_TIMEOUT_VALUE			0xFFFFFFFFU
#define I2C_DMA_TIMEOUT_VALUE			0xFFFFU
#define I2C_FREQUENCY					100000U
#define I2C_REG_8BIT_ADDR				8
#define I2C_REG_16BIT_ADDR				16

#define I2C_CMD_WRITE               	0
#define I2C_CMD_READ                	1

#define I2C_HARDWARE					1			//0软件模拟I2C 1硬件I2C

#if !I2C_HARDWARE

#define CyFx3GpioReadBit(GpioPin)	    ((GPIO->lpp_gpio_simple[GpioPin]& CY_U3P_LPP_GPIO_IN_VALUE) >> 1)
#define CyFx3GpioSetBit(GpioPin)		((*(uvint32_t *)&GPIO->lpp_gpio_simple[GpioPin]) |= CY_U3P_LPP_GPIO_OUT_VALUE)
#define CyFx3GpioResetBit(GpioPin)		((*(uvint32_t *)&GPIO->lpp_gpio_simple[GpioPin]) &= ~CY_U3P_LPP_GPIO_OUT_VALUE)

#define I2C_SDA_GPIO_PIN				59
#define I2C_SCL_GPIO_PIN				58

void I2CStart(void);
void I2cStop(void);
CyBool_t I2cWaitAck(void);
void I2cAck(void);
void I2cNAck(void);
void I2cWriteByte(uint8_t Data);
uint8_t I2cReadByte(CyBool_t isAck);

#endif


CyU3PReturnStatus_t CyFx3I2cInit(void);

CyU3PReturnStatus_t CyFx3I2cReadBytes(uint8_t  DevAddr,
									  uint16_t RegAddr,
									  uint8_t  *ReadData,
									  uint32_t ReadLen,
									  uint32_t RetryCnt,
									  uint8_t  RegBit);

CyU3PReturnStatus_t CyFx3WriteBytes(uint8_t  DevAddr,
									uint16_t RegAddr,
									uint8_t  *WriteData,
									uint32_t WriteLen,
									uint32_t RetryCnt,
									uint8_t  RegBit);
#endif /* CYFX3_I2C_H_ */

         M24M02源文件

#include "m24m02.h"
#include "cyu3error.h"

CyU3PReturnStatus_t M24M02WriteBytes(uint16_t WriteAddr,uint8_t *WriteData,uint32_t WriteByteNum)
{
	 return CyFx3WriteBytes(M24M02_ADDRESS,
							WriteAddr,
							WriteData,
							WriteByteNum,
							2,
							I2C_REG_16BIT_ADDR);
}

CyU3PReturnStatus_t M24M02ReadBytes(uint16_t ReadAddr,uint8_t *ReadData,uint32_t ReadByteNum)
{
	return CyFx3I2cReadBytes(M24M02_ADDRESS,
							 ReadAddr,
							 ReadData,
							 ReadByteNum,
							 2,
							 I2C_REG_16BIT_ADDR);
}

        M24M02头文件

#ifndef M24M02_H_
#define M24M02_H_

#include "cyfx3_i2c.h"

#define M24M02_ADDRESS               0x50

CyU3PReturnStatus_t M24M02WriteBytes(uint16_t WriteAddr,uint8_t *WriteData,uint32_t WriteByteNum);
CyU3PReturnStatus_t M24M02ReadBytes(uint16_t ReadAddr,uint8_t *ReadData,uint32_t ReadByteNum);

#endif /* M24M02_H_ */

        主函数

#include "cyu3os.h"
#include "cyu3error.h"
#include "cyu3uart.h"
#include "cyfx3_i2c.h"
#include "m24m02.h"

CyU3PThread I2cThreadHandler;

#define I2C_THREAD_PRIORITY			8
#define I2C_THREAD_STACK_SIZE		512


static CyU3PReturnStatus_t CyFx3LogInit(void)
{
	CyU3PReturnStatus_t CyFx3Status;

	//初始化串口设备
	CyFx3Status = CyU3PUartInit();

	if(CyFx3Status != CY_U3P_SUCCESS)
	{
		return CyFx3Status;
	}

	//配置uart
	CyU3PUartConfig_t  UartConfig = {
		.txEnable = CyTrue,
		.rxEnable = CyFalse,
		.flowCtrl = CyFalse,
		.isDma    = CyTrue,
		.baudRate = 115200,
		.stopBit = CY_U3P_UART_ONE_STOP_BIT,
		.parity = CY_U3P_UART_NO_PARITY,
	};
	CyFx3Status = CyU3PUartSetConfig(&UartConfig,NULL);
	if(CyFx3Status != CY_U3P_SUCCESS)
	{
		return CyFx3Status;
	}

	//设置发送字节大小
	CyFx3Status = CyU3PUartTxSetBlockXfer(0xFFFFFFFF);
	if (CyFx3Status != CY_U3P_SUCCESS)
	{
		return CyFx3Status;
	}

	//不输出8字节前导数据
	CyU3PDebugPreamble(CyFalse);

	//初始化串口日志功能
	CyFx3Status = CyU3PDebugInit(CY_U3P_LPP_SOCKET_UART_CONS,8);
	if(CyFx3Status != CY_U3P_SUCCESS)
	{
		return CyFx3Status;
	}

	return CY_U3P_SUCCESS;
}

void I2cThread(uint32_t arg)
{
	CyU3PReturnStatus_t CyFx3Status;
	uint8_t WriteData[] = "m24m02 i2c read write test!!!";
	uint8_t ReadData[50] = {0};

	CyFx3I2cInit();
	CyFx3LogInit();

	CyFx3Status = M24M02WriteBytes(0x00,WriteData,sizeof(WriteData));
	if(CyFx3Status != CY_U3P_SUCCESS)
	{
		CyU3PDebugPrint(6,"Write Error\r\n");
	}

	CyU3PThreadSleep(50);

	CyFx3Status = M24M02ReadBytes(0x00,ReadData,sizeof(WriteData));
	if(CyFx3Status != CY_U3P_SUCCESS)
	{
		CyU3PDebugPrint(6,"Read Error\r\n");
	}

	CyU3PDebugPrint(6,"result:%s\r\n",ReadData);


	while(1)
	{

		CyU3PThreadSleep(1000);
	}
}


void CyFxApplicationDefine(void)
{

	void *I2cStackStart = CyU3PMemAlloc(I2C_THREAD_STACK_SIZE);
	if(I2cStackStart != NULL)
	{
		CyU3PThreadCreate((CyU3PThread*		 ) &I2cThreadHandler,
						  (char*			 ) "21:I2c Thread 1",
						  (CyU3PThreadEntry_t) I2cThread,
						  (uint32_t          ) 0,
						  (void*			 ) I2cStackStart,
						  (uint32_t          ) I2C_THREAD_STACK_SIZE,
						  (uint32_t          ) I2C_THREAD_PRIORITY,
						  (uint32_t          ) I2C_THREAD_PRIORITY,
						  (uint32_t          ) CYU3P_NO_TIME_SLICE,
						  (uint32_t          ) CYU3P_AUTO_START);
	}
}



int main(void)
{
	CyU3PReturnStatus_t CyFx3Status;

	//初始化FX3设备
	CyFx3Status = CyU3PDeviceInit(NULL);
	if(CyFx3Status != CY_U3P_SUCCESS)
	{
		goto HandleFatalError;
	}

	//初始化FX3内核缓存
	CyFx3Status = CyU3PDeviceCacheControl(CyTrue,CyTrue,CyTrue);
	if(CyFx3Status != CY_U3P_SUCCESS)
	{
		goto HandleFatalError;
	}

	//配置IO矩阵(16位数据总线 + UART + GPIO)
	CyU3PIoMatrixConfig_t MatrixcConfig = {
		.isDQ32Bit = CyFalse,
		.s0Mode = CY_U3P_SPORT_INACTIVE,
		.s1Mode = CY_U3P_SPORT_INACTIVE,
		.useUart   = CyTrue,
#if I2C_HARDWARE
		.useI2C    = CyTrue,
		.gpioComplexEn[0] = 0,
#else
		.useI2C    = CyFalse,
#endif
		.useI2S    = CyFalse,
		.useSpi    = CyFalse,
		.lppMode   = CY_U3P_IO_MATRIX_LPP_UART_ONLY,
		.gpioSimpleEn[0]  = 0,
		.gpioSimpleEn[1]  = 0,
		.gpioComplexEn[0] = 0,
		.gpioComplexEn[1] = 0,
	};
	CyFx3Status = CyU3PDeviceConfigureIOMatrix(&MatrixcConfig);
    if (CyFx3Status != CY_U3P_SUCCESS)
    {
        goto HandleFatalError;
    }

    //初始化RTOS内核
	CyU3PKernelEntry();

HandleFatalError:
	//复位
	CyU3PDeviceReset(CyTrue);
}

三、验证

        验证I2C读写开发板上的M24M02芯片,芯片地址为A0

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值