时间路行者之 51单片机(STC89C52RC)第七章 定时器以及按键控制LED流水灯模式&定时器时钟

定时器

定时器介绍:

        51单片机的定时器属于单片机的内部资源,其电路的连接和运转均在单片机内部完成

定时器作用:
        (1)用于计时系统,可实现软件计时,或者使程序每隔一固定时间完成一项操作
        (2) 替代长时间的Delay,提高CPU的运行效率和处理速度

STC89C52定时器资源


定时器个数:

        3个 (TO、T1、T2),TO和T1与传统的51单片机兼容T2是此型号单片机增加的资源
不同的型号注意:

        定时器的资源和单片机的型号是关联在一起的,可能会有不同的定时器个数和操作方式,但一般来说,TO和T1的操作方式是所有51单片机所共有的

定时器框图


        定时器在单片机内部就像一个小闹钟一样,根据时钟的输出信号每隔“一秒”,计数单元的数值就增加一,当计数单元数值增加到“设定的闹钟提醒时间”时,计数单元就会向中断系统发出中断申请产生“响铃提醒”,使程序跳转到中断服务函数中执行

定时器工作模式


        STC89C52的TO和T1均有四种工作模式

        模式0: 13位定时器/计数器
        模式1: 16位定时器/计数器 (常用)
        模式2: 8位自动重装模式
        模式3: 两个8位计数器
        工作模式1框图

        SYSclk:系统时钟,即晶振周期,本开发板上的晶振为12MHZ

这是定时器

计数器

 在单片机上看是T0处,用于接外界的计时器

中断系统

        P2口作为地址复用,P3口有第二功能引脚(这里面就有中断的相关引脚

        IAP15中断源有21个

IAP里面的5个中断源

        分时的操作(我在服务你的同时被中断后可以服务别人,这样就实现了服务对象的多样化);

        实现实时处理(可以在编译的时候,中断的子程序);

        进行故障的处理(例如:看门狗程序,进入死循环后,可以跳出并进行复位)

(下面有可能是考点)
        中断系统是为使CPU具有对外界紧急事件的实时处理能力而设置的.

        当中央处理机CPU正在处理某件事的时候外界发生了紧急事件请求,要求CPU暂停当前的工作,转而去处理这个紧急事件,处理完以后,再回到原来被中断的地方,继续原来的工作,这样的过程称为中断。实现这种功能的部件称为中断系统,请示CPU中断的请求源称为中断源

        微型机的中断系统一般允许多个中断源,当几个中断源同时向CPU请求中断,要求为它服务的时候,这就存在CPU优先响应哪一个中断源请求的问题。通常根据中断源的轻重缓急排队,优先处理最紧急事件的中断请求源,即规定每一个中断源有一个优先级别。CPU总是先响应优先级别最高的中断请求。

        当CPU正在处理一个中断源请求的时候(执行相应的中断服务程序) ,发生了另外一个优先级比它还高的中断源请求。如果CPU能够暂停对原来中断源的服务程序,转而去处理优先级更高的中断请求源,处理完以后,再回到原低级中断服务程序,这样的过程称为中断嵌套。这样的中断系统称为多级中断系统,没有中断嵌套功能的中断系统称为单级中断系统。

中断程序流程

 

 STC89C52中断资源

        中断源个数:8个(外部中断0、定时器0中断、外部中断1、定时器中断源个数:8个1中断、串口中断、外部中断2、外部中断3)

        中断优先级个数:4个
        中断号:

        注意:中断的资源和单片机的型号是关联在一起的,不同的型号可能会有不同的中断资源,例如中断源个数不同、中断优先级个数不同等等

 定时器和中断系统

IAP15和89c52的中断系统图相同

IAP15的内部中断接口

 \overline{INT0}外部中断0(连P3.2)IT0触发方式(外部请求)

                                                        IT0=0 电平触发                 低电平触发

                                                        IT0=1 边沿触发分为         上升沿(低电平转高电平)

                                                                                               下降沿(高电平转低电平)                                                                                                                        

                                               IE0为中断标志位:是用来存储前面的触发源是否有效

                                                                               (如果触发成功IE0=1,否则的等于0)

                                               EX0 中断允许:外部中断0的中断允许

                                               EA为总的中断:集体关闭中断的允许,更加方便

                                               PX0优先级:当PX0=1的时候为高优先级

                                                                (其中里面还有自然优先级的概念)

TCON控制中断请求的控制寄存器

IE,IP也都同理

 T0是靠内部的定时器进行溢出来触发请求                                            

                                                

TF0是T0的中断标志位

TR0是控制定时器启动的

相关程序书写:

1、将定时器0工作在模式1中:

        想要让定时器0在模式1下工作,那么就需要将M0打开,所以M0的值为1,其余的都为0,所以得出二进制的数为0000 0001

        GATE:门控端,表示控制启动方、方式

GATE=0(为软启动)GATE=1(为硬启动)

        C/T:为0时,为定时器模式;为1的时候,为计数器模式

        M0和M1:用于设置定时器的工作方式

                00 01都是16位的计数器,方式00具有重复计数的功能,而00只能自己再写初值(写到中断函数中)

                10 为一个8位的计数器(也具有自动重复计数功能)最多计数256个数

                11 只有T0才有方式3,TL1和TH1就各自干各自的事情(这时候T1:可以继续计数,不能发送中断请求(被TH1借走了)了,这时候就辅助串口工作(给串口产生计时脉冲(波特率(是应该脉冲信号))))

        定时器结束后,就会向单片机发送中断请求(就会让TF0=1或TF1=1)

        中断撤销:是自动撤销(TF0=0或TF1=0)

不可位寻址:表示不能控制位

可位寻址:可以控制每一位

  TMOD=0;//选择定时器
  TF=0;//选0是因为防止中断,(TF0为中断艺术标志位)
  TR0=1;//TR0是判断定时器是否开启,如果想要让电机开始工作,就赋值为1。

计数器是8个为1位的,8个只能存256个

//控制中断器的开关
  ET0=1;//打开中断的第一个开关
  EA=1;//打开第二个开关
  PT0=0;//打开第三个开关

中断函数

//闹钟响了以后要调到这个指函数中,起到中断的作用
//初始化后大概一ms后会发生中断
//后面跟的小尾巴就是中断子程序
void Timer0_Routine() interrupt 1
{

}

这个中断系统可以用STC-ISP来进行配置(需要注意配置的时候选的频率等因素)

复制过来的代码中会少一个中断定时器(中断是是需要自己开的),开头的那个12T因为是新的版本,89C52的旧版是用不到的所以可以直接删掉

(太重要了,我听了3遍才知道的技巧)

中断系统的(完整代码)

中断子程序是不能够被调用的

中断子程序有固定的地址入口

#include <REGX51.H>
/*******************************
初始化 
*******************************/
void Timer0_Init(){  
//  TMOD=0;//选择定时器//0000 0001
  //(利用“与或”的方法)
  //利用下面这两句代码来配置上面的那一句代码,可以保证在配置第四位的时候不影响高四位
  TMOD&=0xF0;//把TMOD低四位清零,高四位保持不变(“与”清零)
  TMOD|=0x01;//把TMOD低位置1,高四位保持不变(“或”置1)(任何数或零都为任何数)
  
  TF0=0;//选0是因为防止中断,(TF0为中断艺术标志位)
  TR0=1;//TR0是判断定时器是否开启,如果想要让定时器开始工作,就赋值为1。
  TH0=64535/256;//表示高位
  TL0=64535%256;//表示存下了低位(高位和地位,相当于用两个盒子把数装进去)
  
  /******上面可以用stc-isp生成,下面的中断还是需要自己打开(其中如果单片机不是12T的可以将生成的第一条删除)*********/
  
//控制中断器的开关
  ET0=1;//打开中断的第一个开关
  EA=1;//打开第二个开关
  PT0=0;//打开第三个开关
  
}

/*******************************
中断函数
*******************************/
//闹钟响了以后要调到这个指函数中,起到中断的作用
//初始化后大概一ms后会发生中断
//后面跟的小尾巴就是中断子程序

unsigned int T0Count;//定义了一个新的函数,用来尝试计时一分钟
void Timer0_Routine() interrupt 1
{
  //计数器是同步计数,起始值是64536计时才是1ms。
  TH0=64535/256;
  TL0=64535%256;//为了防止溢出过后,初始值会发生变化,所以在这里需要重置一下
  T0Count++;//来计中断的次数
  if(T0Count>=1000){
    T0Count=0;//将T0Count恢复原值
  P2_0=~P2_0;//表示在执行Timer0_Init()的时候,主函数中虽然没有写Timer0_Routine()但还是会点亮灯,这就说明中断起到了作用
  }
}




void main(){
  Timer0_Init();
  while(1){
    
  }
}
static unsigned int T0Count;//定义静态变量,这样定义的话就不会丢失数字

流水灯

        用_crol_和_cror_来实现循环左移和循环右移

完整代码如下

//main.c


#include <REGX51.H>
#include "Timer0.h"
#include "Key.h"
#include <INTRINS.H>

unsigned char KeyNum,LEDMode;//LEDMode为流水灯模式

void main(){
  P2=0xFE;//点亮最低位LED
  Timer0Init();
  while(1){
    KeyNum=Key();//给 KeyNumber赋值
    if(KeyNum)
    {
      if(KeyNum==1)
      {
        LEDMode++;
        if(LEDMode>=2)LEDMode=0;
      }
    }
  }
}
///*******************************
//初始化 
//*******************************/
//void Timer0_Init(){  
  TMOD=0;//选择定时器//0000 0001
//  //(利用“与或”的方法)
//  //利用下面这两句代码来配置上面的那一句代码,可以保证在配置第四位的时候不影响高四位
//  TMOD&=0xF0;//把TMOD低四位清零,高四位保持不变(“与”清零)
//  TMOD|=0x01;//把TMOD低位置1,高四位保持不变(“或”置1)(任何数或零都为任何数)
//  
//  TF0=0;//选0是因为防止中断,(TF0为中断艺术标志位)
//  TR0=1;//TR0是判断定时器是否开启,如果想要让定时器开始工作,就赋值为1。
//  TH0=64535/256;//表示高位
//  TL0=64535%256;//表示存下了低位(高位和地位,相当于用两个盒子把数装进去)
//  
//  /******上面可以用stc-isp生成,下面的中断还是需要自己打开(其中如果单片机不是12T的可以将生成的第一条删除)*********/
//  
控制中断器的开关
//  ET0=1;//打开中断的第一个开关
//  EA=1;//打开第二个开关
//  PT0=0;//打开第三个开关
//  
//}

/*******************************
中断函数//一般都放在主函数中
*******************************/
//闹钟响了以后要调到这个指函数中,起到中断的作用
//初始化后大概一ms后会发生中断
//后面跟的小尾巴就是中断子程序


void Timer0_Routine() interrupt 1
{
  static unsigned int T0Count;//定义静态变量//定义了一个新的函数,用来尝试计时一分钟
  //计数器是同步计数,起始值是64536计时才是1ms。
  TH0=0x18;
  TL0=0xfc;//为了防止溢出过后,初始值会发生变化,所以在这里需要重置一下
  T0Count++;//来计中断的次数
  if(T0Count>=500){//每个500毫秒进来一次
    T0Count=0;//将T0Count恢复原值
    if(LEDMode==0){
      P2=_crol_(P2,1);
    }
    if(LEDMode==1){
      P2=_cror_(P2,1);
    }
//    P2_0=~P2_0;//表示在执行Timer0_Init()的时候,主函数中虽然没有写Timer0_Routine()但还是会点亮灯,这就说明中断起到了作用
  }
}



//Timer0.c

#include <REGX51.H>
/**
  * @brief 定时器初始化,1毫秒@12.000MHz
  * @param   无 
  * @retval  无
  */
  

//Timer0.c

void Timer0Init(void)		//1毫秒@12.000MHz
{
//	AUXR &= 0x7F;		//定时器时钟12T模式//这句话在旧版的89C52中是可以删去的
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
  ET0=1;//打开中断的第一个开关
  EA=1;//打开第二个开关
  PT0=0;//打开第三个开关
}


/*定时器中断函数模板
void Timer0_Routine() interrupt 1
{
  static unsigned int T0Count;//定义静态变量//定义了一个新的函数,用来尝试计时一分钟
  //计数器是同步计数,起始值是64536计时才是1ms。
  TH0=64535/256;
  TL0=64535%256;//为了防止溢出过后,初始值会发生变化,所以在这里需要重置一下
  T0Count++;//来计中断的次数
  if(T0Count>=1000){
    T0Count=0;//将T0Count恢复原值
  P2_0=~P2_0;//表示在执行Timer0_Init()的时候,主函数中虽然没有写Timer0_Routine()但还是会点亮灯,这就说明中断起到了作用
  }
}
*/
//Timer0.h

#ifndef __TIMER0_H__
#define __TIMER0_H__
  void Timer0Init(void);		//1毫秒@12.000MHz

#endif
//Key.c

#include <REGX51.H>
#include "Delay.h"
/**
  * @brief 获取独立按键键码
  * @param    无
  * @retval  按下独立按键的键码,范围:0~4,无按键按下时值为0
  */
  unsigned char KeyNumber=0;//char的初值是不确定的
unsigned char Key(){

  
  if(P3_1==0){Delay(20);while(P3_1);Delay(20);KeyNumber=1;}
  if(P3_0==0){Delay(20);while(P3_0);Delay(20);KeyNumber=2;}
  if(P3_2==0){Delay(20);while(P3_2);Delay(20);KeyNumber=3;}
  if(P3_3==0){Delay(20);while(P3_3);Delay(20);KeyNumber=4;}
  return KeyNumber;
}
//Key.h
#ifndef __KEY_H__
#define __KEY_H__
  unsigned char Key();

#endif

中断思路

1、触发中断:选择触发方式

                开总中断

                开对应的中断

                选择设置自然优先级、

2、定义中断子程序函数

                (中断关键词 interrupt 0~4)

3、主函数

        while(1);(之后等着子程序被触发)

换灯的亮的案例

时钟的代码

//main.c

#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "Timer0.h"

unsigned char Sec=55,Min=59,Hour=23;//定义一个变量秒
  
void main(){
  LCD_Init();//LCD1602初始化
  Timer0Init();//对时钟进行初始化 
  
  LCD_ShowString(1,1,"Clock:");//初始化显示

  LCD_ShowString(2,1,"  :  :");
	while(1){
		 LCD_ShowNum(2,1,Hour,2);
    LCD_ShowNum(2,4,Min,2);
    LCD_ShowNum(2,7,Sec,2);
	}
}

void Timer0_Routine() interrupt 1 //在中断函数中不要执行过长的任务
{
  static unsigned int T0Count;//定义静态变量//定义了一个新的函数,用来尝试计时一分钟
  //计数器是同步计数,起始值是64536计时才是1ms。
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;
//  TH0=64535/256;
//  TL0=64535%256;//为了防止溢出过后,初始值会发生变化,所以在这里需要重置一下
  T0Count++;//来计中断的次数
  if(T0Count>=1000){ //每隔1s
    T0Count=0;
    Sec++;
    if(Sec>=60){
      Sec=0;
      Min++;
      if(Min>=60){
        Min=0;
        Hour++;
        if(Hour>=24){
          Hour=0;
        }
      }
    }
  }
}
//LCE1602.h


#ifndef __LCD1602_H__
#define __LCD1602_H__

//用户调用函数:
void LCD_Init();
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char);
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String);
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length);
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);

#endif
//LCE1602.c

#include <REGX52.H>

//引脚配置:
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;
#define LCD_DataPort P0

//函数定义:
/**
  * @brief  LCD1602延时函数,12MHz调用可延时1ms
  * @param  无
  * @retval 无
  */
void LCD_Delay()
{
	unsigned char i, j;

	i = 2;
	j = 239;
	do
	{
		while (--j);
	} while (--i);
}

/**
  * @brief  LCD1602写命令
  * @param  Command 要写入的命令
  * @retval 无
  */
void LCD_WriteCommand(unsigned char Command)
{
	LCD_RS=0;
	LCD_RW=0;
	LCD_DataPort=Command;
	LCD_EN=1;
	LCD_Delay();
	LCD_EN=0;
	LCD_Delay();
}

/**
  * @brief  LCD1602写数据
  * @param  Data 要写入的数据
  * @retval 无
  */
void LCD_WriteData(unsigned char Data)
{
	LCD_RS=1;
	LCD_RW=0;
	LCD_DataPort=Data;
	LCD_EN=1;
	LCD_Delay();
	LCD_EN=0;
	LCD_Delay();
}

/**
  * @brief  LCD1602设置光标位置
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @retval 无
  */
void LCD_SetCursor(unsigned char Line,unsigned char Column)
{
	if(Line==1)
	{
		LCD_WriteCommand(0x80|(Column-1));
	}
	else if(Line==2)
	{
		LCD_WriteCommand(0x80|(Column-1+0x40));
	}
}

/**
  * @brief  LCD1602初始化函数
  * @param  无
  * @retval 无
  */
void LCD_Init()
{
	LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵
	LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关
	LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动
	LCD_WriteCommand(0x01);//光标复位,清屏
}

/**
  * @brief  在LCD1602指定位置上显示一个字符
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @param  Char 要显示的字符
  * @retval 无
  */
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
{
	LCD_SetCursor(Line,Column);
	LCD_WriteData(Char);
}

/**
  * @brief  在LCD1602指定位置开始显示所给字符串
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  String 要显示的字符串
  * @retval 无
  */
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=0;String[i]!='\0';i++)
	{
		LCD_WriteData(String[i]);
	}
}

/**
  * @brief  返回值=X的Y次方
  */
int LCD_Pow(int X,int Y)
{
	unsigned char i;
	int Result=1;
	for(i=0;i<Y;i++)
	{
		Result*=X;
	}
	return Result;
}

/**
  * @brief  在LCD1602指定位置开始显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~65535
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');
	}
}

/**
  * @brief  在LCD1602指定位置开始以有符号十进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:-32768~32767
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length)
{
	unsigned char i;
	unsigned int Number1;
	LCD_SetCursor(Line,Column);
	if(Number>=0)
	{
		LCD_WriteData('+');
		Number1=Number;
	}
	else
	{
		LCD_WriteData('-');
		Number1=-Number;
	}
	for(i=Length;i>0;i--)
	{
		LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0');
	}
}

/**
  * @brief  在LCD1602指定位置开始以十六进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~0xFFFF
  * @param  Length 要显示数字的长度,范围:1~4
  * @retval 无
  */
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i,SingleNumber;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		SingleNumber=Number/LCD_Pow(16,i-1)%16;
		if(SingleNumber<10)
		{
			LCD_WriteData(SingleNumber+'0');
		}
		else
		{
			LCD_WriteData(SingleNumber-10+'A');
		}
	}
}

/**
  * @brief  在LCD1602指定位置开始以二进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~1111 1111 1111 1111
  * @param  Length 要显示数字的长度,范围:1~16
  * @retval 无
  */
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0');
	}
}
//Timer0.c

#include <REGX51.H>
/**
  * @brief 定时器初始化,1毫秒@12.000MHz
  * @param   无 
  * @retval  无
  */
  

void Timer0Init(void)		//1毫秒@12.000MHz
{
//	AUXR &= 0x7F;		//定时器时钟12T模式//这句话在旧版的89C52中是可以删去的
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
  //上面的可以用ISP进行生成
  
  //但下面的需要自己书写
  
  ET0=1;//打开中断的第一个开关
  EA=1;//打开第二个开关
  PT0=0;//打开第三个开关
}


/*定时器中断函数模板
void Timer0_Routine() interrupt 1 //在中断函数中不要执行过长的任务
{
  static unsigned int T0Count;//定义静态变量//定义了一个新的函数,用来尝试计时一分钟
  //计数器是同步计数,起始值是64536计时才是1ms。
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;
//  TH0=64535/256;
//  TL0=64535%256;//为了防止溢出过后,初始值会发生变化,所以在这里需要重置一下
  T0Count++;//来计中断的次数
  if(T0Count>=1000){ //每隔1s
    T0Count=0;//将T0Count恢复原值
  P2_0=~P2_0;//表示在执行Timer0_Init()的时候,主函数中虽然没有写Timer0_Routine()但还是会点亮灯,这就说明中断起到了作用
  }
}
*/
//Timer0.h

#ifndef __TIMER0_H__
#define __TIMER0_H__
  void Timer0Init(void);		//1毫秒@12.000MHz

#endif
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

LYPHARD MELODY。

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

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

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

打赏作者

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

抵扣说明:

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

余额充值