STC学习:可校准的实时时钟

程序设计目标及程序运行效果说明
程序设计目标:通过DS1302芯片、晶振、电池和数码管实现实时时钟的数码管显示,并实现实时时钟的时间的准确校准。

程序运行效果说明:将程序下载至芯片,数码管会出现实时的时钟,通过按键key1以及导航键可以实现时间的精确校准。

程序原理说明及相关电路
1.原理说明
本实验在实时时钟的基础上,利用按键Key1以及导航键实现了时间的校准。程序主要是利用导航按键和数字按键综合校准时钟,利用ADC口对来自导航按键不同方向的电压值进行采集,并将采集后的转换结果获取高三位值,将此值作为导航按键方向判断标准。导航按键是通过ADC采集电压的改变从而判断按下的方向,而数字按键是通过电平的直接改变判断是否按下。
导航按键的上键:控制时分秒的数值增1;
导航按键的下键:控制时分秒的数值减1;
K1键:进入或退出时间设置状态;

2.电路原理图及其工作原理
(1)DS1302模块电路
在这里插入图片描述
本实验采用DS1302芯片,DS1302是 DALLAS 公司推出的涓流充电时钟芯片内含有一个实时时钟/日历和 31 字节静态 RAM,外接32.768kHz 晶振,为芯片提供计时脉冲,在电路板的纽扣电池(位于电路板左下方圆柱体)的持续供电下,实现DS1302的独立时间走动。我们的电子钟电子表是利用这种原理实现的。

DS1302的2、3引脚外接32.768kHz 晶振的晶振,为芯片提供计时脉冲,通过秒寄存器的最高位控制晶振的工作状态,当为高时,停止工作;当为低时,晶振开始工作,实时模块自动计时。

RTC_SCLK引脚作为输入引脚,用于在串行接口上控制数据的输入与输出

RTC_IO引脚作为输入输出引脚,为实时时钟的数据线。

RTC_/RST引脚作为输入引脚,在读、写数据时必须置为高电平。该引脚有两个功 能:第一,CE开始控制字访问移位寄存器的控制逻辑;其次,CE 提供结束单字节或多字节数据传输的方法,即如图所示:
在这里插入图片描述
DS1302对应的时序:单个字节读:在前8个SCLK时钟周期内,上升沿写入控制字,在后8个SCLK时钟周期内,下降沿读取数据字;均从最低位开始。
在这里插入图片描述
单个字节写:在前8 个 SCLK 时钟周期,上升沿写入控制字,在后 8 个 SCLK 时钟周期,上升沿写入数据字;均从最低位开始。
在这里插入图片描述

(2)数码管显示电路
在这里插入图片描述
其中LED_SEL(P2.0)引脚决定E3的值:当LED_SEL为低时,使能74HC138译码器工作产生位选信号;LED共阴极,段选信号有效相应位置的LED管亮;通过定时器以一定频率扫描位选信号,结合段选信号进行数码管点亮,从而给人视觉上几个数码管几乎同时显示的效果。

(3)导航按键原理图
在这里插入图片描述
从上图中可以看出,导航按键的不同方向对应的不同的电压值,通过不同的AD值实现不同的按键操作,从而实现对值的设置。

测试说明

  1. 用STC ISP打开并下载HEX文件;

  2. 默认下载后显示时分秒信息;

  3. 按下key1,进行时分秒设置,默认对分进行设置,例如显示01-02.-03(你的实验板的时间一般和我此时测试的不太一样),02右下角的小数点表示当前设置的是小时(小数点亮对应位置可以通过功能键的上下键进行值调节),按功能键的上或下键调节值大小;

  4. 按功能键的左(时)、右(秒)、确认键(分),结合上、下键进行值调节;

  5. 再次按下key1退出设置;

  6. 时钟依靠自身的晶振跑起来,显示时钟的时分秒;

代码如下:

/**********************
文件名称:realtimeclock.c
作者:
说明:进行实时时钟模块测试的例程
采用定时器0,方式1通过数码管对时间进行显示并进行时分秒的修改
修改记录:
***********************/
/**********************
基于STC15F2K60S2系列单片机C语言编程实现
使用如下头文件,不用另外再包含"REG51.H"
***********************/
#include"STC15F2K60S2.H" //头文件
#include"intrins.H" //头文件
#include"ctype.h"
#define uchar unsigned char 	   //宏定义
#define uint unsigned int
#define ADC_CHS1_7 0X07
/***********时分秒写寄存器**************/
#define DS1302_SECOND_WRITE 0x80			
#define DS1302_MINUTE_WRITE 0x82
#define DS1302_HOUR_WRITE   0x84 
#define DS1302_WEEK_WRITE   0x8A
#define DS1302_DAY_WRITE    0x86
#define DS1302_MONTH_WRITE  0x88
#define DS1302_YEAR_WRITE   0x8C
#define ADC_POWER 0X80
#define ADC_FLAG 0X10  /*当A/D转换完成后,ADC_FLAG要软件清零*/
#define ADC_START 0X08
#define ADC_SPEED_90 0X60
/***********时分秒读寄存器**************/
#define DS1302_SECOND_READ  0x81
#define DS1302_MINUTE_READ  0x83
#define DS1302_HOUR_READ    0x85 
#define DS1302_WEEK_READ    0x8B
#define DS1302_DAY_READ     0x87
#define DS1302_MONTH_READ   0x89
#define DS1302_YEAR_READ    0x8D
#define	P1_7_ADC 0x80
/*时、分、秒标志*/
bit set_H_flag;
bit set_Ms_flag;
bit set_S_flag;

/*时、分、秒值*/
uint set_H_val;
uint set_Ms_val;
uint set_S_val;

bit set_HMS_done;  //时分秒设置完
bit show_set_HMS;  //显示时分秒
bit show_HMS;  //显示时分秒
bit show_key_val;
unsigned char key_val;

/**********************
引脚别名定义
***********************/
/********DS1302*******/
sbit Rtc_sclk = P1^5;			//时钟线引脚,控制数据的输入与输出
sbit Rtc_rst  = P1^6;			//CE线引脚,读、写数据时必须置为高电平
sbit Rtc_io   = P5^4;			//实时时钟的数据线引脚
/********数码管显示******/
sbit Led_sel = P2^3;		   //流水灯和数码管选通引脚
sbit Sel0    = P2^0;		   //Sel0、Sel1、Sel2三位二进制进行数码管位选0-7  	
sbit Sel1    = P2^1;
sbit Sel2    = P2^2;
sbit KEY1=P3^2;	 			  //Key1
/**********************
变量定义
***********************/
uchar duanxuan[]={ 					  //数码管显示所要用的段码
 
                0x3F,  //"0"
                0x06,  //"1"
                0x5B,  //"2"
                0x4F,  //"3"
                0x66,  //"4"
                0x6D,  //"5"
                0x7D,  //"6"
                0x07,  //"7"
                0x7F,  //"8"
                0x6F,  //"9"
                0x77,  //"A"
                0x7C,  //"B"
                0x39,  //"C"
                0x5E,  //"D"
                0x79,  //"E"
                0x71,  //"F"
                0x76,  //"H"
                0x38,  //"L"
                0x37,  //"n"
                0x3E,  //"u"
                0x73,  //"P"
                0x5C,  //"o"
                0x40,  //"-"
                0x00,  //熄灭
                0x00  //自定义
 
                };

uchar weixuan[]={0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07};	   //数码管位选数组
uchar flag;					 //所选择点亮的数码管0-7标志位
uchar temp;					 //要写入到DS1302的数据
/*******************************
 * 函数名:Delayms
 * 描述  :毫秒延时程序
 * 输入  :延时i毫秒
 * 输出  :无
 *******************************/
void Delayms(char i) 			
{
	while(i--)
	{	
		int n=500;
		while (n--)
	    {
	        _nop_();
	        _nop_();
	        _nop_();
	        _nop_();
	        _nop_();
			_nop_();
	    }
	}
}
/**********************
定义时间结构体
***********************/
typedef struct __SYSTEMTIME__
{
	uchar Second;
	uchar Minute;
	uchar Hour;
	uchar Week;
	uchar Day;
	uchar Month;
	uchar Year;
}SYSTEMTIME; 			//定义的时间类型
SYSTEMTIME t;			
/**********************
函数名称:Ds1302_write
功能描述:Ds1302写入一字节
入口参数:uchar 要写入的数据 
***********************/
void Ds1302_write(uchar temp) 		 //temp:要写入的数据
{
	uchar i;
	for(i=0;i<8;i++)				 //循环8次写入一个字节
	{
		Rtc_sclk=0;					//时钟脉冲拉低
		Rtc_io=(bit)(temp&0x01);	 //取最低位数据
		temp>>=1;					 //右移一位
		Rtc_sclk=1;					  //上升沿输入 	
	}
}

/**********************
函数名称:Ds1302_read
功能描述:Ds1302读取一字节
入口参数:无
出口参数:返回uchar 读出的数据
***********************/
uchar Ds1302_read()	 
{
	 uchar i, dat;
	 for(i=0;i<8;i++)			
	 {
	 	Rtc_sclk=0;				//时钟脉冲拉低	
	 	dat>>=1;				//要返回的数据右移一位	 
		if(Rtc_io==1)			//数据线为高,证明该位数据为1
		dat|=0x80;				//要传输数据的当前值置为1,若不是,则为0
		Rtc_sclk=1;				//拉高时钟线 
	 }
	 return dat;				//返回读取出的数据
}


/**********************
函数名称:WriteDS1302
功能描述:向Addr对应的寄存器中写入数据Data
入口参数:uchar Addr 寄存器地址, uchar Data 要写入寄存器的数据
***********************/
void WriteDS1302(uchar Addr, uchar Data) 	   //Addr: DS1302地址,Data: 要写的数据
{
    Rtc_rst = 0;						 //初始CE线置0
    Rtc_sclk = 0;						 //初始时钟线置0
    Rtc_rst = 1;						 //初始CE线置为1,传输开始
	Ds1302_write(Addr);					 // 地址,传输命令字
	Ds1302_write(Data);			   		 // 写1Byte数据 
	Rtc_rst = 0;   						 //读取结束,CE置0,结束数据的传输
    Rtc_sclk = 1;						 //时钟线拉高
}

/**********************
函数名称:ReadDS1302
功能描述:读出Addr对应的寄存器中的数据
入口参数:uchar cmd 寄存器地址
***********************/
uchar ReadDS1302(uchar cmd)
{
    uchar Data;
    Rtc_rst = 0;			  //初始CE线置为0
    Rtc_sclk = 0;			  //初始时钟线置为0
    Rtc_rst = 1;			  //初始CE置为1,传输开始
    Ds1302_write(cmd);        // 地址,传输命令字 
    Data =Ds1302_read();      // 读1Byte数据	  
	Rtc_rst = 0;			  //读取结束,CE置为0,结束数据的传输
    Rtc_sclk = 1; 			  //时钟线拉高
    return Data;			  //返回得到的数据
}

/**********************
函数名称:DS1302_GetTime_BCD
功能描述:读出DS1302中时、分、秒、年、月、日寄存器中对应的数据
***********************/

SYSTEMTIME DS1302_GetTime()
{
	SYSTEMTIME Time;
 	uchar ReadValue;
 	ReadValue = ReadDS1302(DS1302_SECOND_READ);
 	//将BCD码转换成十进制了
 	Time.Second=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);		  //读取秒寄存器中的数据
	ReadValue=ReadDS1302(DS1302_MINUTE_READ);
 	Time.Minute = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);		  //读取分寄存器中的数据
 	ReadValue = ReadDS1302(DS1302_HOUR_READ);
 	Time.Hour = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);		  //读取时寄存器中的数据
	ReadValue = ReadDS1302(DS1302_DAY_READ);
 	Time.Day = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F); 		  //读取日寄存器中的数据
 	ReadValue = ReadDS1302(DS1302_WEEK_READ);
 	Time.Week = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);		  //读取周寄存器中的数据
 	ReadValue = ReadDS1302(DS1302_MONTH_READ);
 	Time.Month = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);		  //读取月寄存器中的数据
 	ReadValue = ReadDS1302(DS1302_YEAR_READ);
 	Time.Year=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F); 			  //读取年寄存器中的数据

	return Time;
}

/**********************
函数名称:Init
功能描述:完成各部分功能模块的初始化
入口参数:无 
出口参数:无
备注:
***********************/
void Init()
{	P3=0xEF;				  //关蜂鸣器
 	P2M0=0xff;				 //设置推挽模式
   	P2M1=0x00;
    P0M0=0xff;
    P0M1=0x00;
	Led_sel=0;				 //选通数码管

 	TMOD=0x01;				//定时器0,方式1
	EA=1;					//打开总的中断
	ET0=1;					//开启定时器中断	
 	TH0=(65535-1000)/256;	//设置定时初值
	TL0=(65535-1000)%256;
	TR0=1;					//启动定时器
}
void Init_key()
{
	/*时、分、秒值*/
	set_H_val=7;
	set_Ms_val=8;
	set_S_val=9;
	set_HMS_done=0;  //时分秒设置完
	/*时、分、秒标志*/
	set_H_flag=0;
	set_Ms_flag=0;
	set_S_flag=0;
	/*默认显示时、分、秒标志*/
	show_HMS=1;
	show_set_HMS=0;
	show_key_val=0;
	key_val=0x00;
//	P3M0=0x10;			   //设置推挽模式	 蜂鸣器不用推挽
//	P3M1=0x00;
//	P1M0=0x00;
//	P1M1=0x00;
}
/**************************************
 * 函数名:GetADC
 * 描述  :获得AD转换的值,没有设置A/D转换中断(具体看IE、IP)
 * 输入  :无
 * 输出  :AD转换的结果
 **************************************/
unsigned char GetADC()
{
	unsigned char result;
	ADC_CONTR = ADC_POWER | ADC_START | ADC_SPEED_90 | ADC_CHS1_7;//没有将ADC_FLAG置1,用于判断A/D是否结束
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	while(!(ADC_CONTR&ADC_FLAG));//等待直到A/D转换结束
	ADC_CONTR &= ~ADC_FLAG; //ADC_FLAGE软件清0
	result = ADC_RES; //获取AD的值
	return result;	  //返回ADC值
}

/********************************
 * 函数名:Fun_Keycheck()	   
 * 描述  :检测功能键的上5、下2、左4、右1、确认键3、开关按键3(0),没按下返回0x07,返回相应的值  (包含消抖过程)
 * 输入  :无
 * 输出  :键对应的值
********************************/
unsigned char Fun_Keycheck()
{
	unsigned char key;
	key=GetADC();		  //获得ADC值赋值给key
	if(key!=255)
	{
		Delayms(1);
		key=GetADC();
		if(key!=255)	  //按键消抖
		{
	     	key=key&0xE0;//获取高3位,其他位清零
        	key=_cror_(key,5);//循环右移5位
			return key;
		}
	}
	return 0x07;
}

/**********************
函数名称:Fun_Key_task_HMS
功能描述:监听功能键,完成时分秒相关值的设置,左对应时、有对应秒、确认对应分;
		  上对应值加1、下对应值减1
入口参数:无 
出口参数:无
***********************/
void Fun_Key_task_HMS()
{
	key_val=Fun_Keycheck();
	switch(key_val)	   
	{
		case 0x05:
		if(set_H_flag)//小时加1
		set_H_val=(set_H_val+1)%24;
		if(set_Ms_flag)//分钟加1
		set_Ms_val=(set_Ms_val+1)%60;
		if(set_S_flag)//秒钟加1
	   	set_S_val=(set_S_val+1)%60;
		break; 	//上  加
	    case 0x02:
		if(set_H_flag)//小时减1
		set_H_val=(set_H_val>0)?set_H_val-1:23;
		if(set_Ms_flag)//分钟减1
		set_Ms_val=(set_Ms_val>0)?set_Ms_val-1:59;
		if(set_S_flag)//秒钟减1
	   	set_S_val=(set_S_val>0)?set_S_val-1:59;
		break;  //下  减
		case 0x04:
		{
			set_H_flag=1;
			set_S_flag=0;
			set_Ms_flag=0;
		}
		break; 	//左   时
	    case 0x01:
		{
			set_S_flag=1;
			set_H_flag=0;
			set_Ms_flag=0;
		}
		break;  //右	  秒
		case 0x03:
		{
			set_Ms_flag=1;
			set_H_flag=0;
			set_S_flag=0;
		}
		break;	//确认 分
		default:break;	  
	}
}
/**********************
函数名称:Fun_key1
功能描述:监听按键1,完成时分秒设置
入口参数:无 
出口参数:无
***********************/
void Fun_key1()
{
	if(KEY1==0)// 按键2控制时分秒的设置
	{		 	
 		Delayms(5);
		while(!KEY1); //消抖
		
		set_HMS_done=0;
		show_set_HMS=1;  //显示十分秒

		show_HMS=0;

		/*默认设置分*/
		set_H_flag=0;				   //设置时间时默认设置分钟
		set_Ms_flag=1;
		set_S_flag=0;

		set_H_val=t.Hour;				//把此时的时间作为设置时间的默认值
		set_Ms_val=t.Minute;
		set_S_val=t.Second;	

		while(1)
		{

			if(KEY1==0)
			{
				Delayms(5);
				while(!KEY1);					//按键消抖
				set_H_flag=0;
				set_Ms_flag=0;
				set_S_flag=0;
				set_HMS_done=1;				   //时间设置完成
				break;						   //退出时间设置
			}
			else
			{
				Fun_Key_task_HMS();			   //进入设置选项
				while(key_val!=0x07)
				{
					key_val=Fun_Keycheck();
				}
			}
		}
	}
}
/**********************
函数名称:Key_OFFON
功能描述:设置时分秒,进行时间的校准。
入口参数:无 
出口参数:无
***********************/
void Key_OFFON()
{
	uchar temp,dtime;
	uchar table_D_BCD[]={0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09};
 	t=DS1302_GetTime();

    key_val=Fun_Keycheck();
	if(key_val==0x03)
	{
		while(key_val==0x03)
		{
			key_val=Fun_Keycheck();
		}
		set_HMS_done=0;
	
	}
	if(set_HMS_done) //完成设置 对应校时功能
	{				
		show_set_HMS=0;			
		show_HMS=1;//显示时分秒 
		WriteDS1302(0x8E,0x00);	 //禁止写保护位
		temp=ReadDS1302(DS1302_SECOND_READ)|0x80;
		WriteDS1302(0x80,temp);//晶振停止工作
		/*写入时、分、秒值*/	 
		dtime=(table_D_BCD[set_S_val/10]<<4)|table_D_BCD[set_S_val%10];	
		WriteDS1302(DS1302_SECOND_WRITE,dtime);
		dtime=(table_D_BCD[set_Ms_val/10]<<4)|table_D_BCD[set_Ms_val%10];
		WriteDS1302(DS1302_MINUTE_WRITE,dtime);
		dtime=(table_D_BCD[set_H_val/10]<<4)|table_D_BCD[set_H_val%10];	
		WriteDS1302(DS1302_HOUR_WRITE,dtime);
		WriteDS1302(0x8E,0x80); //写保护位置1
		set_HMS_done = 0;
	}
}

void Initial_DS1302(void)	
{	unsigned char hour,min,sec;
//    unsigned char code DataStr[]=__DATE__;	  //格式: "Jan 13 2017"   12字符(含结束符)
    unsigned char code DataStr[]=__TIME__;	  //格式:"09:12:04"	  9字符(含结束符)

    hour=((toint(DataStr[0]))<<4)+toint(DataStr[1]);
	min=((toint(DataStr[3]))<<4)+toint(DataStr[4]);
	sec=((toint(DataStr[6]))<<4)+toint(DataStr[7]);

    WriteDS1302(0x8E,0x00);			 //禁止写保护位	
	WriteDS1302(DS1302_SECOND_WRITE,sec);
	WriteDS1302(DS1302_MINUTE_WRITE,min);
	WriteDS1302(DS1302_HOUR_WRITE,hour);
	
	temp=ReadDS1302(DS1302_SECOND_READ)&0x7f ;
	WriteDS1302(0x80,temp);		   	//晶振开始工作
//	WriteDS1302(0x90,0xa9);         //  充电设置:允许充电,2个二极管,2K电阻 		
	WriteDS1302(0x8E,0x80);			 //写保护位置1						 
}
	
void set_charge_DS1302()
{  WriteDS1302(0x8E,0x00);			 //禁止写保护位
   WriteDS1302(0x90,0xa9);         //  充电设置:允许充电,2个二极管,2K电阻 		
   WriteDS1302(0x8E,0x80);			 //写保护位置1
}
/********************************定时器中断处理程序************************************************/
void timer0() interrupt 1	  //把数码管的显示提到中断里面来了
 {
 	TH0=(65535-1000)/256;	  //重新填充初值
	TL0=(65535-1000)%256;

	/********显示程序*******/
	flag++;						  
	if(flag==8)					  
	flag=0;
	P0=0x00;							   
	P2=weixuan[flag];
	if(show_HMS)
	{  //显示格式14-23-54(14点23分54秒)
		switch(flag){
		case 0:P0=duanxuan[t.Hour/10];break; 
	    case 1:P0=duanxuan[t.Hour%10];break; 
		case 3:P0=duanxuan[t.Minute/10];break; 
		case 4:P0=duanxuan[t.Minute%10];break; 
		case 6:P0=duanxuan[t.Second/10];break; 
		case 7:P0=duanxuan[t.Second%10];break; 
		default:P0=duanxuan[22];break;
		}
	}
	if(show_set_HMS)
	{  //显示格式14-23-54(14点23分54秒)
		switch(flag){
		case 0:P0=duanxuan[set_H_val/10];break; 
		case 1:P0=(set_H_flag==1)?duanxuan[set_H_val%10]|0x80:duanxuan[set_H_val%10];break; 
		case 3:P0=duanxuan[set_Ms_val/10];break; 
		case 4:P0=(set_Ms_flag==1)?duanxuan[set_Ms_val%10]|0x80:duanxuan[set_Ms_val%10];break; 
		case 6:P0=duanxuan[set_S_val/10];break; 
		case 7:P0=(set_S_flag==1)?duanxuan[set_S_val%10]|0x80:duanxuan[set_S_val%10];break;  
		default:P0=duanxuan[22];break;
		}
	}
	if(show_key_val)
	{
		switch(flag){
		case 0:P0=duanxuan[key_val/10];break; 
		case 1:P0=duanxuan[key_val%10];break; 
		default:P0=duanxuan[22];break;
		}
	}
}
/**********************************
 * 函数名:Init_ADC
 * 描述  :初始化P1.7口为ADC
 * 输入  :无
 * 输出  :无
 **********************************/
void Init_ADC()
{
	P1ASF=P1_7_ADC;//将P1ASF寄存器对应位置1
	ADC_RES = 0;//结果寄存器清零
//	ADC_RESL=0;
	ADC_CONTR = ADC_POWER | ADC_FLAG | ADC_START | ADC_SPEED_90 | ADC_CHS1_7;		//对应位赋值
	Delayms(2);
}

void main()
{
	Init();												 //系统初始化
	Init_ADC();											 //ADC初始化
	Init_key();											 //按键初始化
	if (ReadDS1302(DS1302_SECOND_READ)&0x80)			  //判断掉电之后时钟是否还在运行
	Initial_DS1302();									  //若正在运行,则进行DS1302初始化
	set_charge_DS1302();
	while(1)
	{
		Delayms(200);								  //延时取值,减少取值次数
		t=DS1302_GetTime();							  //从DS1302取值送给结构体t
		Fun_key1();										  
		Key_OFFON();			
		if (ReadDS1302(DS1302_SECOND_READ)&0x80)	
		Initial_DS1302();							 //取时间各数据放到结构体t中
	}	

}
  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

布布要成为最负责的男人

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

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

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

打赏作者

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

抵扣说明:

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

余额充值