【51单片机学习笔记】单片机C语言开发基础

一、运算符的应用

        C语言中的运算符主要包括:算术运算符、关系运算符、逻辑运算符、赋值运算符等。

【例】用单片机实现乘法“78×18”的运算,并通过P2口的发光二极管分时显示结果的高八位和低八位状态。

#include<reg51.h>
#define uint unsigned int    //宏定义
#define uchar unsigned char
delay()
{
uint m,n;
for(m=1000;m>0;m--)
 for(n=110;n>0;n--);
}
void main()
{
uint s;						//保存乘法结果
uchar i,j;						//保存相乘的因数
i=78;
j=18;
s=i*j;
while(1)
 {
	P2=s/256;				//取乘积的高八位送P2口显示
	delay();
	P2=0xff;
	delay();
	P2=s%256;				//取乘积的低八位送P2口显示
	delay();
 }
}

        这个程序里,我们用到了宏定义,宏定义的格式为:#define 新名称 原内容

        #define命令的作用是:用“新名称”代替后面的“原内容”,一般用于“原内容”比较长,又在程序里反复用到的情况。

【例】用十六个发光二极管显示除法运算结果。

        芯片74HC595是八位串行输入转并行输出移位寄存器。其中引脚SER14)是串行移位输入引脚,串行数据从低位到高位在该引脚输入;引脚SRCLK11)移位时钟输入引脚,该引脚的上升沿可以使14脚的数据输入芯片内,即该引脚的上升沿控制数据串行移入;引脚RCLK12)并行输出时钟端,通常情况下该引脚保持低电平,当串行数据移入完成时,该引脚产生一个上升沿,将刚才移入的数据在QAQH端并行输出。        

#include<reg51.h>
#define uint unsigned int
#define uchar unsigned char
sbit data1=P3^4;	//定义74HC595中用到的几个口
sbit iclk=P3^6;
sbit oclk=P3^5;
uchar i,j,k,m;
void delay()
{
uint a,b;
for(a=10;a>0;a--)
 for(b=110;b>0;b--);
}
void xianshi(uchar m)		//74HC595显示子程序
{
    uchar n;
    n=m;			             //要显示的数存放在n里
    oclk=0;
    iclk=0;		
    for(j=8;j>0;j--)		//要显示的数左移串行输入
	{
    n=n<<1;
    data1=CY;
    iclk=1;
    delay();
    iclk=0;
   }
     oclk=1;			   //移位完成并行输出
     delay();
     oclk=0;
  }
void main()
{
  i=10;				//被除数和除数赋给i和j
  j=6;
  P2=i/j;
  k=((i%j)*10)/j;			//小数位保存在k中
  xianshi(k);		    	 //调用显示子程序 
  while(1);
}

【例】用自增、自减运算控制P2口的流水灯。

#include<reg51.h>			
void delay()				 //延时一秒子程序
{
unsigned int i,j;
for(i=1000;i>0;i--)
 for(j=110;j>0;j--);
}
void main()
{
unsigned char m,n;
while(1)
{
  for(m=0;m<10;m++)		//m从零到九自增一,状态从P2输出
   {
    P2=m;
    delay();
   }
 for(n=10;n>0;n--)		//n从十到一自减一,状态从P2输出
  {
  P2=n;
  delay();
  }
 }
}

二、C语言的语句

        一个完整的C程序是由若干条C语句按一定的方式组合而成的。按C语句执行方式的不同,C程序可分为顺序结构、选择结构和循环结构。

        顺序结构:指程序按语句的顺序逐条执行。

        选择结构:指程序根据条件选择相应的执行顺序。

        循环结构:指程序根据某条件的存在重复执行一段程序,直到这个条件不满足为止。如果这个条件永远存在就会形成死循环。

        一般的 C程序都是由上述三种结构混合而成的。但要保证 C程序能够按照预期的意图运行,还要用到以下5类语句来对程序进行控制。

        1.控制语句完成一定的控制功能,C语言中有9种控制语句。

        if…else…:条件语句;

        for…:循环语句

        while…:循环语句

        do…while…:循环语句

        continue:结束本次循环语句

        break:终止执行循环语句

        switch:多分支选择语句

        goto:跳转语句

        return:从函数返回语句

        2.函数调用语句:调用已定义过的函数,例如延时函数。

        3.表达式语句:由一个表达式和一个分号构成,示例:z=x+y

        4.空语句:空语句什么也不做,常用于消耗若干机器周期,延时等待。

        5.复合语句:用“{ }”把一些语句括起来就构成了复合语句。

1.if语句

格式如下:

1if(表达式)

2if(表达式)

                语句1

          else

                 语句2

3if(表达式1

                 语句1

          else

          if(表达式2

                语句2

         else

          if(表达式3

                语句3

          ……

         else

        语句n

【例】if语句控制P2口一个流水灯从低位到高位循环移位点亮。

#include<reg51.h>  
void delay()
{
unsigned int i,j;
for(i=1000;i>0;i--)
 for(j=110;j>0;j--);
}
void main()
{
unsigned char m=0xfe;		//赋初值最低位的灯亮
while(1)					//无限循环
 {
	P2=m;
	delay();
	m=(m<<1)|0x01;		//m的值左移一位并且最低位填零
	if(m==0xff)m=0xfe;	//当点亮的灯移出最高位时,恢复初值0xfe
 }
}

2.switch…case多分支选择语句

一般格式如下:

  switch(表达式)

{

case 常量表达式1://如果常量表达式1满足,则执行语句1

     语句1;

break;  //执行语句1后,用此指令跳出switch结构

case 常量表达式2://如果常量表达式2满足,则执行语句2

     语句2;

break;  //执行语句2后,用此指令跳出switch结构

……

case 常量表达式n:

     语句n;

break;

default:  //上述表达式都不满足时,执行语句(n+1)

     语句n+1;

}  

【例用多分支选择语句switchcase实现P2口流水灯的控制。

#include<reg51.h>					
#define uchar unsigned char
#define uint unsigned int
void delay()
{
uint i,j;
for(i=1000;i>0;i--)
 for(j=110;j>0;j--);
}
void main()
{
   char m=3;		//m赋初值为3 
   while(1)
{
  switch(m--)		//表达式为m--,第一次执行为m的初值
  {
case 0:			//如果表达式的值为0,执行这句后面的语句
   P2=0x01;
   break;		//执行完前一条指令,跳出switch
 case 1:			//如果表达式的值为1 ,执行这句后面的语句
   P2=0x02;
   break;		
 case 2:			//如果表达式的值为2,执行这句后面的语句
   P2=0x04;
   break;
 default:		//当表达式的值不等于0-2,执行这句后面的语句
   P2=0x08;
  }
 delay();
 if(m<0)m=3;	//如果m自减一后的结果小于零,重新赋为初值3
}
}

3.dowhile循环语句

        该循环语句先执行循环体一次,再判断表达式的值。若为真值,则继续执行循环,否则退出循环。一般格式如下:

do循环体语句

while(表达式);

        do…while循环语句的执行过程如下:

        先执行一次指定的循环体语句,然后判断表达式;当表达式的值为非零时,返回到第一步重新执行循环体语句;如此反复,直到表达式的值等于0时,循环结束。

        使用时要注意while(表达式)后的分号“;”不能丢,它表示整个循环语句的结束。

【例】dowhile循环语句实现流水灯三次左移循环点亮。

#include<reg51.h>			
#include<intrins.h>		//包含循环左移指令的头文件
void delay()
{
unsigned int i,j;
for(i=1000;i>0;i--)
 for(j=110;j>0;j--);
}
void main()
{
unsigned char m,n;
n=2;
 do		//do…while语句先执行循环体,再判断循环条件
 {
P2=0xfe;			//P2口的初始状态,最低位的灯亮
  delay();
  for(m=7;m>0;m--)	//循环左移七次
   {
    P2=_crol_(P2,1);	//循环左移语句
    delay();
   }
 }while(n--);			//n减一不为零时,返回执行循环体
 while(1);			//n等于零时,跳出循环,原地踏步
}

三、C语言的数组

        数组是同类型的一组变量,引用这些变量时可用同一个标志符,借助于下标来区分各个变量。数组中的每一个变量称为数组元素。数组由连续的存储区域组成,最低地址对应于数组的第一个元素,最高地址对应于最后一个元素。数组可以是唯一的,也可以是多维的。

1.一维数组

        一维数组的表达式如下:

        类型说明符  数组名  [常量]

        方括号中的常量称为下标。C语言中,下标是从0开始的。

int  a[10];    //定义整型数组a,它有a[0]—a[9]共10个元素,每个元素都是整型变量

一维数组的赋值方法有以下几种。

1)在数组定义时赋值,示例如下:

  int a[10]={0123456789}

数组元素的下标从0开始,赋值后,a[0]=0a[1]=1,依次类推,直至a[9]=9

2)对于一个数组也可以部分赋值,示例如下:

  int b[10]={012345}

这里只对前6个元素赋值。对于没有赋值的b[6]b[9],默认的初始值为0

3)如果一个数组的全部元素都已赋值,可以省去方括号中的下标,示例如下:

int  a[ ]={0123456789}

数组元素的赋值与普通变量相同。可以把数组元素像普通变量一样使用。

2.二维数组

        C语言允许使用多维数组,最简单的多维数组是二维数组。其一般表达式形式如下:

        类型说明符  数组名[下标1][下标2]

unsigned char x[3][4];    //定义无符号字符型二维数组,有3×4=12个元素 

        二维数组以行列矩阵的形式存储。第一个下标代表行,第二个下标代表列。上一数组中各数组元素的顺序排列如下:

        x[0][0]、x[0][1]x[0][2]x[0][3]

        x[1][0]、x[1][1]x[1][2]x[1][3]

        x[2][0]、x[2][1]x[2][2]x[2][3]

二维数组的赋值方法可以采用以下两种方式。

1)按存储顺序整体赋值,这是一种比较直观的赋值方式,示例如下:

  int a[3][4]={01234567891011}

如果是全部元素赋值,可以不指定行数,即

int a[ ][4]={01234567891011}

  2)按每行分别赋值。为了能更直观地给二维数组赋值,可以按每行分别赋值,这时要用{ }标明,没有说明的部分默认为0,示例如下:

  int a[3][4]={ {0123},{4,567},{8}  };  //最后三个元素,没有赋值的被默认为0

3.字符数组

        用来存放字符型数据的数组称为字符数组。与整型数组一样,字符数组也可以在定义时进行初始化赋值。

char a[8]={‘B’,’e’,’i’,’-’,’j’,’x’,’l’,’d’};

        上述语句定义了字符型数组,它有a[0]a[7]8个元素,每个元素都是字符型变量。还可以用字符串的形式来对全体字符数组元素进行赋值。

char str[]={“Now, Temperature is:”};

        要特别注意的是:字符串是以’\0’作为结束标志的。所以,当把一个字符串存入数组时,也把结束标志’\0’存入了数组。数组必须先定义,才能使用。

4.数组的应用

        流水灯的控制方法有许多种,一种比较常用的方法是:把流水灯的控制代码按顺序存入数组,再依次引用数组元素,并送到发光二极管的接口显示。无论流水灯的控制逻辑多么复杂,用这种方法都可以很容易地通过调用控制代码实现。

【例】用数组控制P2口一个流水灯间隔1s右移点亮。

#include<reg51.h>		
#define uchar unsigned char
#define uint unsigned int
uchar code tab[]={0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};		//定义一个数组
uchar i=0;
void delay()
{
 uint m,n;
 for(m=1000;m>0;m--)
 for(n=110;n>0;n--);
}
void main()
{
 for(;i<8;i++)			//循环给P2口送数八次
 {
   P2=tab[i];			//引用数组元素,并送P2口显示
   delay();			//调用延时一秒子程序
 }
while(1);			//显示结束,程序停在这里
}

5.数组作为函数参数

        一个数组的名字表示该数组的首地址,所以用数组名作为函数的参数时,被传递的就是数组的首地址,被调用的函数的形式参数必须定义为指针型变量。

        用数组名作为函数的参数时,应该在主调函数和被调函数中分别进行数组定义,而不能只在一方定义数组。并且,两个函数中定义的数组类型必须一致。如果不一致,将导致编译出错。实参数组和形参数组的长度可以一致也可以不一致,编译器不检查形参数组的长度,只是将实参数组的首地址传递给形参数组。为保证两者长度一致,最好在定义形参数组时,不指定长度,只在数组名后面跟一个空的方括号[ ]。编译时,系统会根据实参数组的长度为形参数组自动分配长度。

【例】使用数组作参数控制P2口八位流水灯点亮。

#include<reg51.h>			
void delay()
{
unsigned int i,j;
for(i=1000;i>0;i--)
 for(j=110;j>0;j--);
}
void xianshi(unsigned char a[])		//定义显示子函数,形参为字符型数组首地址
{
    unsigned char m;
    for(m=0;m<8;m++)
{
   P2=a[m];			//取数组的第m个元素送P2口显示
   delay();
  }
}
void main()
{
   unsigned char code tab[]={0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};	//定义流水灯控制码
    while(1)
 {
   xianshi(tab);		//调用显示子函数
  }
}

四、C语言的指针

        指针是C语言中的一个重要概念,也是C语言的一个重要特色。正确而灵活地运用指针,可以有效地表示复杂的数据结构,动态地分配内存,方便地使用字符串,有效地使用数组。利用指针引用数组元素速度更快,占用内存更少。

1.指针的定义和引用

1.指针的概念

        一个数据的“指针”就是它的地址。通过变量的地址能找到该变量在内存中的存储单元,从而能得到它的值。指针具有一般变量的三要素:名字、类型和值。指针与一般变量的区别在于类型和值上。

指针的值:指针存放的是某个变量在内存中的地址值。被定义过的变量都有一个内存地址。

指针的类型:指针的类型就是该指针所指向的变量的类型。例如,一个指针指向int型变量,该指针就是int型指针。

指针的定义格式:指针变量不同于整型或字符型等其他类型的数据,使用前必须将其定义为“指针类型”。指针定义的一般形式如下:

类型说明符  * 指针名字

int i;		//定义一个整型变量i
int *pointer;		//定义整型指针,名字为pointer
//可以用取地址运算符“&”使一个指针变量指向一个变量,例如:
pointer=&i;		//“&i”表示取i的地址,将i的地址存放在指针变量pointer中

2.指针的初始化

        在使用指针前必须进行初始化,一般格式如下:

类型说明符  指针变量=初始地址值;

unsigned char *p;  //定义无符号字符型指针变量p

unsigned char m;  //定义无符号字符型数据m

p=&m;  //将m的地址存在p中(指针变量p被初始化了)

3.指针数组

        指针可以指向某类变量,也可以指向数组。以指针变量为元素的数组称为指针数组。这些指针变量应具有相同的存储类型,并且指向的数据类型也必须相同。

        指针数组定义的一般格式如下:

        类型说明符  *指针数组名[元素个数]

int * p[2];    //p[2]是含有p[0]和p[1]两个指针的指针数组,指向int型数据
//指针数组的初始化可以在定义时同时进行
unsigned char a[] = {0,1,2,3};
unsigned char * p[4] = {&a[0],&a[1],&a[2],&a[3]};  //存放的元素必须为地址

4.指向数组的指针

        一个变量有地址,一个数组元素也有地址,所以可以用一个指针指向一个数组元素。如果一个指针存放了某数组的第一个元素的地址,就说该指针是指向这一数组的指针。数组的指针即数组的起始地址。

unsigned char a[ ]={0,1,2,3};
unsigned char *p;
p=&a[0];		//将数组a的首地址存放在指针变量p中

        经上述定义后,指针p就是数组a的指针。

        C语言规定:数组名代表数组的首地址,也就是第一个元素的地址。

        p=&a[0] ;   等价于     p=a;

        C语言规定:p指向数组a的首地址后,p+1就指向数组的第二个元素a[1],p+2指向a[2],依次类推,p+i指向a[i]。

2.指针的应用

【例】用指针数组控制P2口八位流水灯点亮。

#include<reg51.h>			
#define uchar unsigned char
#define uint unsigned int
void delay()
{
uint i,j;
for(i=0;i<1000;i++)
for(j=0;j<110;j++);
}
void main()
{
uchar code tab[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};
uchar *p[]={&tab[0],&tab[1],&tab[2],&tab[3],&tab[4],&tab[5],&tab[6],&tab[7]};
uchar m=0;
for(;m<8;m++)		//循环控制取数组元素八次
 {
    P2=*p[m];		//将指针数组中第i个元素送P2口
    delay();
  }
    while(1);			 //取数完毕程序停在这里
}

【例】用指向数组的指针来控制流水灯

#include<reg51.h>		
void delay()
{
unsigned int i,j;
for(i=1000;i>0;i--)
 for(j=110;j>0;j--);
}
void main()
{
unsigned char code Tab[]={0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};	
//流水灯控制码数组
unsigned char *p,m;	//定义无符号字符型指针和控制循环的变量
 p=Tab;			//指针指向数组首地址
 for(m=0;m<8;m++)	//循环显示八个状态
 {
P2=*(p+m);			//通过指针引用数组元素的组,送到P2显示
	 delay();
 }
 while(1);			//显示完毕,程序停在这里
}

        从以上两个例子,我们可以比较一下两种用法的区别。指针数组需要先将指针数组元素都赋值(初始化)再使用,通过指针取数组元素的方法是“∗p[m]”(其中 m 是数组元素下 标)。而指向数组的指针使用前要先定义一个指针,并将数组的首地址给指针,取数组元素的方法是“∗(p+m)”。所以这两种方法使用时是有一定区别的,一定要注意区分。

3.指针作函数参数的应用

例】用指针作函数参数控制P2口八位流水灯点亮。

#include<reg51.h>		
void delay()		
{
unsigned int i,j;
for(i=1000;i>0;i--)
 for(j=110;j>0;j--);
}
void display(unsigned char *p)		//显示子程序,形参为无符号字符型指针
{
unsigned char i;
while(1)					//无限循环
 {
    i=0;
    while(*(p+i)!='\0')		 //当数组中元素未取完时,接着取数送显示
  {
    P2=*(p+i);			//取数组中第i+1个元素送P2口显示
    delay();
    i++;				//修改循环计数变量
   }
 }
}
void main()
{
  unsigned char code tab[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};	
				//定义显示码数组
  unsigned char *pin;
  pin=tab;			//指针指向数组首地址
  display(pin);			//调用显示子程序
}

4.函数型指针的应用

        在C语言中,指针变量除能指向数据对象外,也可以指向函数。一个函数在编译时,分配了一个入口地址,这个入口地址就称为函数的指针。可以用一个指针变量指向函数的入口地址,然后通过该指针变量调用此函数。

        定义指向函数的指针变量的一般形式如下:

        类型说明符(*指针变量名)(形参列表)

        函数的调用可以通过函数名调用,也可以通过函数指针来调用。要通过函数指针调用函数,只要把函数的名字赋给该指针就可以了。

【例】用函数型指针控制P2口八位流水灯点亮

#include<reg51.h>		
unsigned char code tab[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};	
//定义显示码数组
void delay()
{
  unsigned int i,j;
  for(i=1000;i>0;i--)
  for(j=110;j>0;j--);
}
void xianshi()		//定义显示子程序
{
   unsigned char i;
  for(i=0;i<8;i++)
   {
     P2=tab[i];		//取数组中的第i+1个元素送P2口
     delay();
   }
}
void main()
{
   void(*p)(void);	   //定义函数型指针p
   p=xianshi;		  //将函数入口地址赋给指针p
   while(1)(*p)();	  //通过指针p调用显示函数,并循环
}

五、C语言的编译预处理

        编译预处理是C语言编译器的一个组成部分。编译器在对整个程序进行编译之前,先对程序中的编译控制进行预处理,然后在将预处理的结果与整个C语言源程序一起进行编译,以产生目标代码。常用的预处理命令有宏定义、文件包含和条件命令。为了与一般C语言语句区别,预处理命令由“#”开头。

1.宏定义

        C语言允许用一个标志符来表示一个字符串,称为宏。被定义为宏的标志符为宏名。在编译预处理时,程序中的所有宏名都用宏定义中的字符串代替,这个过程称为宏代换。宏定义分为不带参数的宏定义和带参数的宏定义。

        不带参数的宏定义的一般形式如下:

        #define 标志符 字符串

#define uchar unsigned char

        带参数的宏定义不是进行简单的字符串替换,还要进行参数替换,其一般形式如下:

        #define 宏名(参数表) 字符串

#define PI 3.1415926
#define S(r) PI*(r)*(r)
main()
{
    float a,area;
    a = 2.3;
    area = S(a);
}

2.文件包含

        文件包含是指一个程序将另一个指定的文件的全部内容包含进来。文件包含的命令一般格式如下:

        #include<文件名>

        文件包含命令的功能是用指定文件的全部内容替换该预处理行。

        如果程序中要包含多个文件,则需要使用多个包含命令。当程序中需要调用C51编译器提供的各种库函数时,必须在程序的开头使用#include命令将相应的函数说明文件包含进来。

3.条件编译

        一般情况下,对C语言程序进行编译时,所有的程序都参加编译,但有时希望对其中一部分内容只在满足一定条件时才进行编译,这就是所谓的条件编译。C51编译器的预处理提供的条件编译命令可以分为以下三种形式。

1#ifdef 标志符

          程序段1

      #else

          程序段2

      #end if

2#if 常量表达式

            程序段1

      #else

            程序段2
      #
endif

        如果常量表达式为“真”,那么就编译该语句后的程序段。

3#ifndef 标志符

          程序段1

      #else

          程序段2

      #end if

【例】用带参数的宏定义完成运算a*b/(a+b),将结果送P2口显示。

#include<reg51.h>  
#define F(a,b) (a)*(b)/((a)+(b))
void main()
{
  int i,j,k;
  i=34;
  j=45;
  k=30;
  P2=F(i+j,k);
  while(1);
}

【例】使用条件编译控制P2口点亮灯的状态。

#include<reg51.h>
#define max 100
void main()
{
#if max>80		//当max>80时,0xf0送P2口
 P2=0xf0;
#else
 P2=0x0f;		 //当max≤80时,0x0f送P2口
#endif
}

(1)用 C51编程实现除法“90÷8”的运算,并通过 P2口的发光二极管分时显示结果的商和余数。

#include<reg51.h> //p2 分时显示除法运算结果的商和余数
#define uchar unsigned char
#define uint unsigned int
delay()
{
    uint m,n;
    for(m=1000;m>0;m--)
    for(n=110;n>0;n--);
}
void main()
{
    uchar i,j;
    i=90;
    j=8;
    while(1)
    {
    P2=i/j;
    delay();
    P2=0xff;
    delay();
    P2=i%j;
    delay();
    }
}

(2)编程实现:设初始状态为P2口8个灯全亮,用if语句控制P2口流水灯从高位到低位顺序熄灭。

#include<reg51.h> //if 用于流水灯控制
void delay()
{
    unsigned int i,j;
    for(i=1000;i>0;i--)
    for(j=110;j>0;j--);
}
void main()
{
    unsigned char m=0;
    P2=m;
    delay();
    |1: m=(m>>1)|0x80;
    P2=m;
    if(m!=0xff)goto |1;
    while(1);
}

(3)编程实现:用多分支选择语句switch···case实现P2口流水灯从高位到低位点亮。

#include<reg51.h> //多分支语句在流水灯控制中的应用
#define uchar unsigned char
#define uint unsigned int
void delay()
{
    uint i,j;
    for(i=1000;i>0;i--)
    for(j=110;j>0;j--);
}
void main()
{
    char m=8;
    while(1)
    {
        switch(m--)
        {
            case 8:
            P2=0x0ff;
            break;
            case 7:
            P2=0x7f;
            break;
            case 6:
            P2=0x3f;
            break;
            case 5:
            P2=0x1f;
            break;
            case 4:
            P2=0x0f;
            break;
            case 3:
            P2=7;
            break;
            case 2:
            P2=3;
            break;
            case 1:
            P2=1;
            break;
            case 0:
            P2=0;
            break;
            default:
            m=8;
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值