ADC芯片ADS1258采集数据的读取

分享一个5年前做过的通过ADS1258芯片读取霍尔传感器ACS758检测的电流数据,原理图较简单,补贴了,直接贴.h与.c文件,几年前的代码了,凑活看,实际可用,因为用在了车厂的一个非标检测项目上,已经稳定运行了5年。这里我最终用的是单通道检测,需要差分读取的,我注释的地方有写,可以直接放开。

一:代码main.c可以可以直接调用

readADS();

二:核心代码

1: ads1258.h文件


#ifndef _ADS1258_H_
#define _ADS1258_H_

#include "main.h"

typedef union ChannelData
{
	uint8_t data[4];
	uint32_t value;
}structChan;


extern uint32_t adsvolt[20];

extern structChan channelData[20];

#define MV_PER_LSB 0.16276f // 5000/30720 = 0.16276f
#define MVLOT_ACC_MID_THROR 900.0f // Mid Voltage mv
#define MPERS2_MV  0.0980665f // 100mv/1g =  9.80665f m/s2/100mv = 0.0980665f m/s2/mv 

#define MVLOT_GYRO_MID_THROR 2500.0f // Mid Voltage mv
#define ANGPERS_MV 0.142857f // 7mv -> 1ang/s = 1/7 = 0.142857f  





#define ADS1258_CS_LOW   GPIO_ResetBits(GPIOA, GPIO_Pin_4);
#define ADS1258_CS_HIGH	 GPIO_SetBits(GPIOA, GPIO_Pin_4);


#define ADS1258_PWR_ON	 GPIO_SetBits(GPIOB, GPIO_Pin_2);

#ifdef TEST_BORAD //测试
#define DATA_READY       GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0)
#define START_H       GPIO_SetBits(GPIOB,GPIO_Pin_1);
#define START_L       GPIO_ResetBits(GPIOB,GPIO_Pin_1);
#else
#define DATA_READY       GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)
#define START_H       GPIO_SetBits(GPIOB,GPIO_Pin_0);
#define START_L       GPIO_ResetBits(GPIOB,GPIO_Pin_0);
#endif


#define BASE 0.06


#define SENDDATALEN 1000

extern unsigned char ChannelSendData[8]; 
extern unsigned char ChannelData[1000][29];//[19];// [12]; 
extern unsigned int ptrWr;
extern unsigned int ptrRd;

extern float ft;

extern void ads_rdid(void);
extern void ads_init(void);
extern void ads_test(void);
extern void ads_config(void);
extern void ads_Pulse(void);
extern void Pulse_readdata(void);
extern void ads_reset(void);
extern u8 REG_readdata(void);
extern void readADS();
#endif



2: ads1258.c文件

#include "main.h"

float ft;
float vcc;
float gain;
float offset;
float temp;
uint32_t adsvolt[20];


uint32_t ADIvcc;
uint32_t ADIref;
uint32_t ADIgain;
uint32_t ADItemp;
uint32_t ADIoffset;

structChan channelData[20];
uint8_t sys_ID = 0x00;

//根据DRDY直接读数据时使用的变量
uint8_t read_data[3] = {0x00, 0x00, 0x00};
uint8_t Status_byte = 0x00;
uint8_t HSB_byte = 0x00;
uint8_t MSB_byte = 0x00;
uint8_t LSB_byte = 0x00;
uint8_t channel = 0x00;
uint16_t Data_combine = 0x00;
float Data_result = 0;

uint8_t count = 0;					//计数 行 列
uint8_t ChannelSendData[8] = {0x00};
/*
CS引脚需要单独控制,在一串spi操作前置低 在一串spi操作结束后再拉高,在这其中的spi操作不需要延时!
spi的数据首发除了常见的那两个函数外,也可以用Ads1158_TransmitReceive,尤其对一串操作! 用这个操作比较合适 避免时序错误。
*/
static void Ads1158_TransmitReceive(uint8_t *pTxData, uint8_t *pRxData, uint16_t Size)
{
	unsigned int i = 0;
	//	SPI1_ReadWriteByte(pTxData[0]);
	for (i = 0; i < Size; i++)
	{
		//		pRxData[i] = SPI1_ReadWriteByte(pTxData[i+1]);
		pRxData[i] = SPI1_ReadWriteByte(pTxData[i]);
	}
}
static void Ads1158_Transmit(uint8_t *pTxData, uint16_t Size)
{
	unsigned int i = 0;
	for (i = 0; i < Size; i++)
	{
		SPI1_ReadWriteByte(pTxData[i]);
	}
}
static void Ads1158_SPI_Receive(uint8_t *pData, uint16_t Size)
{
	unsigned int i = 0;
	for (i = 0; i < Size; i++)
	{
		pData[i] = SPI1_ReadWriteByte(0x00);
	}
}

//ads1158初始化函数 试着读取系统ID
void ads_init(void)
{
	uint8_t cmd_reset = 0xC0;

	uint8_t cmd_readID2[2] = {0x49, 0x00}; //命令读ID寄存器
	uint8_t back_readID2[2] = {0x00, 0x00};

	//SPI写0xc0(复位) 软件复位
	ADS1258_CS_LOW;
	delay_us(20);
	Ads1158_Transmit(&cmd_reset, 1);
	delay_us(100);
	ADS1258_CS_HIGH;
	delay_ms(10);

	//SPI写0x49(寄存器读命令 一次访问一个寄存器 访问09h寄存器),然后读值,值应该是0x9b(判断设备ID)
	ADS1258_CS_LOW;
	delay_us(20);
	Ads1158_TransmitReceive(cmd_readID2, back_readID2, 2);
	delay_us(20);
	ADS1258_CS_HIGH;
	delay_ms(10);

	sys_ID = back_readID2[1];
	if (sys_ID == 0x8B)
	{
		//ok
		printf("ads1258 ok\r\n");
	}
	else
	{
		//error
		printf("ads1258 failed\r\n");
	}
	printf("ads1258 id is %d\r\n",sys_ID);
}

void ads_rdid(void)
{
	//uint8_t cmd_reset=0xC0;
	uint8_t cmd_readID2[2] = {0x49, 0x00}; //命令读ID寄存器
	uint8_t back_readID2[2] = {0x00, 0x00};

	//SPI写0x49(寄存器读命令 一次访问一个寄存器 访问09h寄存器),然后读值,值应该是0x9b(判断设备ID)
	ADS1258_CS_LOW;
	delay_us(100);
	Ads1158_TransmitReceive(cmd_readID2, back_readID2, 2);
	delay_us(100);
	ADS1258_CS_HIGH;
	delay_ms(10);

	sys_ID = back_readID2[1];
	printf("id is %d\r\n",sys_ID);
	if (sys_ID == 0x9B)
	{
		back_readID2[1] = 0; //ok
	}
	else
	{
		back_readID2[1] = 1; //error
	}
}
void ads_test(void)
{

	uint8_t cmd_readID2 = 0x49;
	uint8_t aaa = 0x00;

	ADS1258_CS_LOW;
	Ads1158_Transmit(&cmd_readID2, 1);
	Ads1158_SPI_Receive(&aaa, 1);
	ADS1258_CS_HIGH;
}

void ads_reset(void)
{
	uint8_t reset_cmd = 0xc0;
	
	ADS1258_CS_LOW;
	Ads1158_Transmit(&reset_cmd, 1);
	ADS1258_CS_HIGH;
}

/*配置ADS1158的10个寄存器
unsigned char write_conf[11]={0x70,0x02,0x50,0x00,0x00,0x80,0x1F,0x00,0xFF,0x00,0x8B},read_conf[10];
0x70 :寄存器写命令 从00h 写到09h
0x16 :1 config0  auto-scan,外部adc输入,带状态字
0x01 :2 config1  standby 转速延迟16period 转换速率最低
0x00 :3 MUXSCH fixed设置,默认值
0x00 :4 MUXDIF scan设置,没有使用差分输入,设置为0
0x80 :5 MUXSG0 使用单端输入7-12,这个寄存器设置0-7 FF
0x1F :6 MUXSG1 单端输入8-15配置,我们使用8-12      03 
0x00 :7 SYSRED 读取系统温度,可以用作验证     
0xFF,0x00 :8 9 GPIOC GPIOD 不使用,默认值     
0x8B :10 ID寄存器 默认是0x9Bh    
*/

void ads_config(void)
{
	uint8_t i = 0, j = 0;
	
	#ifdef AUTOSCAN
	//uint8_t txdata[11] = {0x70, 0x06, 0x01, 0x00, 0x00, 0xFF, 0x03, 0x00, 0xFF, 0x00, 0x8B}; //normal-autoscan   neibu
	//uint8_t txdata[11] = {0x70, 0x16, 0x01, 0x00, 0x00, 0xFF, 0x03, 0x00, 0xFF, 0x00, 0x8B}; //normal-autoscan
	//uint8_t txdata[11] = {0x70, 0x16, 0x01, 0x00, 0x1f, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x8B}; //normal-autoscan
	//uint8_t txdata[11] = {0x70, 0x06, 0x01, 0x00, 0x1f, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x8B}; //normal-autoscan   内部直连
	#ifdef DIFF
	//uint8_t txdata[11] = {0x70, 0x02, 0x01, 0x00, 0x1f, 0x00, 0x00, 0x3d, 0xFF, 0x00, 0x8B}; //normal-autoscan   内部直连  基准计算
	uint8_t txdata[11] = {0x70, 0x12, 0x01, 0x00, 0x1f, 0x00, 0x00, 0x3d, 0xFF, 0x00, 0x8B}; //normal-autoscan   外部直连 差分 基准计算
	#else
	//uint8_t txdata[11] = {0x70, 0x02, 0x01, 0x00, 0x00, 0xFF, 0x03, 0x3d, 0xFF, 0x00, 0x8B}; //normal-autoscan   内部直连  基准计算   用在天津与保定项目
	uint8_t txdata[11] = {0x70, 0x02, 0x01, 0x00, 0x00, 0x1C, 0x00, 0X3C, 0xFF, 0x00, 0x8B}; //normal-autoscan   内部直连  基准计算   用三个通道
	#endif
	#endif
	#ifdef SINGLE
	uint8_t txdata[11] = {0x70, 0x36, 0x01, 0x76, 0x00, 0xc0, 0x00, 0x00, 0xFF, 0x00, 0x8B}; //normal-fixed-01
	//uint8_t txdata[11] = {0x70, 0x36, 0x01, 0x10, 0x00, 0x03, 0x00, 0x00, 0xFF, 0x00, 0x8B}; //normal-fixed-01
	#endif
  //
	//uint8_t txdata[11] = {0x70, 0x16, 0x01, 0x00, 0x00, 0x28, 0x3c, 0x00, 0xFF, 0x00, 0x8B}; //normal
	//uint8_t txdata[11] = {0x70, 0x12, 0x01, 0x00, 0x00, 0x28, 0x3c, 0x3c, 0xFF, 0x00, 0x9B};//config ref channel for test
	uint8_t readcmd[11] = {0}; //从00h到09h 读所有寄存器

	uint8_t rxdata[11] = {0}; //回读10个寄存器的数据,判断设置是否成功

	//配置10个寄存器
	ADS1258_CS_LOW;
	delay_us(20);
	Ads1158_TransmitReceive(txdata, rxdata, 11);
	delay_us(20);
	ADS1258_CS_HIGH;
	delay_ms(10);

	//回读10个寄存器
	readcmd[0] = 0x50; //从00h到09h 读所有寄存器

	ADS1258_CS_LOW;
	delay_us(10);
	Ads1158_TransmitReceive(readcmd, rxdata, 11);
	delay_us(10);
	ADS1258_CS_HIGH;
	delay_ms(10);
	
	printf("tx data is %x %x %x %x %x %x %x %x %x %x\r\n",txdata[1],txdata[2],txdata[3],txdata[4],txdata[5],txdata[6],txdata[7],txdata[8],txdata[9],txdata[10]);
	printf("rx data is %x %x %x %x %x %x %x %x %x %x\r\n",rxdata[1],rxdata[2],rxdata[3],rxdata[4],rxdata[5],rxdata[6],rxdata[7],rxdata[8],rxdata[9],rxdata[10]);
	for (i = 1; i < 9; i++)
	{
		if (txdata[i] == rxdata[i])
			j++;
	}
	if (j == 8)
	{
		//配置ok
		printf("ads1258 set up ok\r\n");
	}
}

void ads_Pulse(void)
{
	uint8_t cmd_Pulse = 0x80; //转换命令
	ADS1258_CS_LOW;
	//delay_us(1);
	START_H
	//delay_us(1);
	//Ads1158_Transmit(&cmd_Pulse, 1);
	START_L
	//delay_us(1);
	ADS1258_CS_HIGH;
}

/*
ads1158通道数据的读取
我们使用的是单端输入7-12:7 gyro_x; 8 gyro_y; 9 gyro_z; 10 acc_x ; 11 acc_y; 12 acc_z
配置中使用的auto_scan模式,
转换命令触发转发,根据DRDY读取转换的结果,一次转化的结束后 通道自动指向下一个选中的通道 再次转换命令
*/

u16 dataChannelFlag = 0;
float vTemp;
float wendu;
u8 REG_readdata(void)
{

	u8 ret = 0;
	
	uint8_t REG_cmddata[5] = {0x30, 0x00, 0x00, 0x00,0x00}; //使用寄存器方式 读取通道数据
	uint8_t REG_recdata[5] = {0x00, 0x00, 0x00, 0x00,0x00}; //使用寄存器方式 读取通道数据
	

	ADS1258_CS_LOW;
	delay_us(1);
	
	Ads1158_TransmitReceive(REG_cmddata, REG_recdata,5);

	delay_us(1);
	ADS1258_CS_HIGH;
	

	Status_byte = REG_recdata[1];
	channel = Status_byte & 0x1f;

	if(channel<24)
		channel = channel - 0x08;

	HSB_byte = REG_recdata[2];
	MSB_byte = REG_recdata[3];
	LSB_byte = REG_recdata[4];


	switch(channel)
	{
		case 0:
		adsvolt[0] = (HSB_byte<<16) | (MSB_byte<<8) | LSB_byte;
		break;
		case 1:
		adsvolt[1] = (HSB_byte<<16) | (MSB_byte<<8) | LSB_byte;
		break;
		case 2:
		adsvolt[2] = (HSB_byte<<16) | (MSB_byte<<8) | LSB_byte;
		break;
		case 3:
		adsvolt[3] = (HSB_byte<<16) | (MSB_byte<<8) | LSB_byte;
		break;
		case 4:
		adsvolt[4] = (HSB_byte<<16) | (MSB_byte<<8) | LSB_byte;
		break;
		case 5:
		adsvolt[5] = (HSB_byte<<16) | (MSB_byte<<8) | LSB_byte;
		break;
		case 6:
		adsvolt[6] = (HSB_byte<<16) | (MSB_byte<<8) | LSB_byte;
		break;
		case 7:
		adsvolt[7] = (HSB_byte<<16) | (MSB_byte<<8) | LSB_byte;
		break;
		case 8:
		adsvolt[8] = (HSB_byte<<16) | (MSB_byte<<8) | LSB_byte;
		break;
		case 9:
		adsvolt[9] = (HSB_byte<<16) | (MSB_byte<<8) | LSB_byte;
		break;
		case 24:
			ADIoffset = (HSB_byte<<16) | (MSB_byte<<8) | LSB_byte;
			break;
		case 26:
			ADIvcc = (HSB_byte<<16) | (MSB_byte<<8) | LSB_byte;
		  vcc = ADIvcc/786432.0;
		  vcc = vcc + BASE;
			break;
		case 27:
			ADItemp = (HSB_byte<<16) | (MSB_byte<<8) | LSB_byte;
		  if(ADItemp & 0x800000)
			{
				wendu = ((float)(0xffffff - ADItemp)/(float)0x780000)*ft;
				wendu = -vTemp;
			}
			else
			{
				wendu = ((float)ADItemp/(float)0x780000)*ft;
			}
			wendu = (wendu * 1000000 - 168000) / 563 + 25;
			break;
		case 28:
			ADIgain = (HSB_byte<<16) | (MSB_byte<<8) | LSB_byte;
		  gain = ADIgain/7864320.0;
			break;
		case 29:
			ADIref = (HSB_byte<<16) | (MSB_byte<<8) | LSB_byte;
		  ft = ADIref/786432.0;
			break;
		default:
			break;
	}
	if(channel < 9)
	{
		if(adsvolt[channel] & 0x800000)
		{
			vTemp = ((float)(0xffffff - adsvolt[channel])/(float)0x780000)*ft/gain;
			vTemp = -vTemp;
		}
		else
		{
			vTemp = ((float)adsvolt[channel]/(float)0x780000)*ft/gain;
		}
		

		if(4 == channel)
			dataInfoCan.voltCanSend = vTemp * 50;//V*10
		else if(2 == channel)
		{
			//vTemp = vTemp - 0.613;
		  if(vTemp<0)
				vTemp = -vTemp;
			dataInfoCan.currentLCanSend = vTemp/0.006;//100MA
			if(dataInfoCan.currentLCanSend<4)
				dataInfoCan.currentLCanSend = 0;
		}
		else if(3 == channel)
		{
			//vTemp = vTemp - 0.613;
		  if(vTemp<0)
				vTemp = -vTemp;
			
			dataInfoCan.currentRCanSend = vTemp/0.006;//100MA
			if(dataInfoCan.currentRCanSend<4)
				dataInfoCan.currentRCanSend = 0;
		}

		
		#ifdef PRINTF
		printf("%d:%f  ",channel,vTemp);
		#endif
	}

	//printf("channel %d is %x:%f\r\n",channel,adsvolt[channel],vTemp);
	if(channel ==4)
	{
		#ifdef PRINTF
		printf("ref:%f  ",ft);
		printf("temp:%f  ",wendu);
		printf("vcc:%f  ",vcc);
		printf("gain:%f    ",gain);
		//printf("offset:%d  ",ADIoffset);
		printf("totol time is %.2f ms",(10000-timestamp1)*0.1);
		printf("\r\n\r\n");
		#endif
		return 1;
	}

}

void readADS(void)
{
		if(_loop_count == 0)
		{
			 int timeout = 10000;
			 timestamp1 = 10000;
			 _loop_count = LOOP_DELAY;
			 ads_Pulse();
			 
			 while(timeout)
			 {
					if (DATA_READY == 0)
					{
						if (REG_readdata() == 1) 
						{
						//	timeout = 0;
							break;
						}
						ads_Pulse();
					}
					timeout--;
			 }
		}
}


		

3:依赖代码

   上述ads1258.c有一个依赖函数SPI1_ReadWriteByte,做以下注解:

本项目采用STM32单片机平台完成,引用的STM32的固件库,依赖函数SPI1_ReadWriteByte如下

  

void SPI1_Init(void)
{
 	GPIO_InitTypeDef GPIO_InitStructure;
    SPI_InitTypeDef  SPI_InitStructure;

	RCC_APB2PeriphClockCmd(	RCC_APB2Periph_GPIOA, ENABLE );
	RCC_APB2PeriphClockCmd(	RCC_APB2Periph_GPIOB, ENABLE );
	RCC_APB2PeriphClockCmd(	RCC_APB2Periph_SPI1,  ENABLE );
 
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	GPIO_SetBits(GPIOA,GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7);  
	

	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_1;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; 
 	GPIO_Init(GPIOB, &GPIO_InitStructure);
	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 
 	GPIO_Init(GPIOB, &GPIO_InitStructure);

	
	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_4;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 
 	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_2;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 
 	GPIO_Init(GPIOB, &GPIO_InitStructure);
	

	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  
	SPI_InitStructure.SPI_Mode = SPI_Mode_Master;		
	SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;		
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;		
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;	
	SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;		
	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;		
	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;	
	//SPI_InitStructure.SPI_CRCPolynomial = 7;	
	SPI_Init(SPI1, &SPI_InitStructure);  
	SPI_Cmd(SPI1, ENABLE); 
	SPI1_ReadWriteByte(0xff);
 
}   

u8 SPI1_ReadWriteByte(u8 TxData)
{		
	u8 retry=0;				 	
	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET) 
    {
		retry++;
		if(retry>200)
            return 0;
	}			  
	SPI_I2S_SendData(SPI1, TxData); 
	retry=0;

	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET) 
	{
		retry++;
		if(retry>200)
            return 0;
	}	  						    
	return SPI_I2S_ReceiveData(SPI1);			    
}

  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
ads1248是一种高精度、低功耗、具有多通道的模拟信号采集芯片。为了编写ads1248的数据采集程序,需要以下步骤: 1. 初始化芯片:首先,需要对芯片进行初始化设置。这包括配置芯片的工作模式、增益、参考电压、数据速率等参数。可以使用SPI通信协议将这些设置发送给芯片。 2. 启动转换:然后,需要启动模拟到数字转换(ADC)。通过发送特定的命令给芯片,将它置于转换模式,并开始采集模拟信号。 3. 等待转换完成:在转换过程中,需要等待芯片完成采样和转换。可以通过查询芯片的状态寄存器来检查转换是否完成。 4. 读取转换结果:转换完成后,可以通过读取芯片数据寄存器来获取转换结果。这些结果可以是模拟信号的数字表示,根据芯片的分辨率和增益设置进行缩放。 5. 数据处理和存储:获取到转换结果后,可以根据需要进行进一步的数据处理,比如滤波、校准或者其他算法处理。然后,可以将结果存储到相应的存储介质中,比如内存、硬盘或者外部设备。 6. 循环采集:为了连续采集数据,可以将上述步骤放入一个循环中,以重复执行。在每次循环中,可以对芯片进行重新配置,然后再次启动转换。 总的来说,编写ads1248数据采集程序需要进行初始化、启动转换、等待转换完成、读取结果、数据处理和存储等步骤,以实现精确、高效地采集模拟信号数据

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

laixiong_embed

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值