51单片机入门——LCD1602

1.初识 LCD1602

LCD ( Liquid Crystal Display 的简称)液晶显示器

LCD 的构造是在两片平行的玻璃基板当中放置液晶盒,下基板玻璃上设置TFT(薄膜晶体管),上基板玻璃上设置彩色滤光片,通过TFT上的信号与电压改变来控制液晶分子的转动方向,从而达到控制每个像素点偏振光出射与否而达到显示目的。

1.1.1602 液晶的硬件接口

1602 液晶,从它的名字我们就可以看出它的显示容量,就是可以显示 2 行,每行 16 个字符的液晶。它的工作电压为 4.5V~5.5V ,对于这点我们在设计电路的时候,直接按照 5V 系统设计即可,但是要保证我们的 5V 系统不能低于 4.5V 。在 5V 工作电压下测量它的工作电流是 2mA ,大家注意,这个 2mA 仅仅是指液晶,而它的黄绿背光都是用 LED 做的,所以功耗不会太小。
在这里插入图片描述
1602 液晶一共有 16 个引脚,每个引脚的功能,我们都可以在它的数据手册中获取。而这些基本信息,在我们设计电路和编写程序之前,必须先看明白。
在这里插入图片描述
液晶的电源 1 脚 2 脚以及背光电源的 15 脚 16 脚,不用多说,正常接就可以了。

3 脚叫做液晶显示偏压信号,大家注意到小黑块没有,当我们要显示一个字符的时候,有的黑点显示,有的黑点就不能显示,这样就可以实现我们想要的字符了。我们这个 3 脚就是用来调整显示的黑点和不显示的之间的对比度,调整好了对比度,就可以让我们的显示更加清晰一些。在进行电路设计实验的时候,通常的办法是在这个引脚上接个电位器,也就是我们初中学过的滑动变阻器。通过调整电位器的分压值,来调整 3 脚的电压。而当产品批量生产的时候,我们可以把我们调整好的这个值直接用简单电路来实现。

4 脚是数据命令选择端。对于液晶,有时候我们要发送一些命令,让它实现我们想要的一些状态,有时候我们要发给它一些数据,让它显示出来,液晶就通过这个引脚来判断接收到的是命令还是数据。大家注意学会读手册,看到这个引脚描述里:数据/命令选择端,而后跟了括号(H/L),他的意思就是当这个引脚是 H(High)高电平的时候,是数据,当这个引脚是 L(Low)低电平的时候,是命令。

5 脚和 4 脚用法类似,功能是读写选择端。我们既可以写给液晶数据或者命令,也可以读取液晶内部的数据或状态,就是控制这个引脚。因为液晶本身内部有 RAM,实际上我们送给液晶的命令或者数据,液晶需要先保存在缓存里,然后再写到内部的寄存器或者 RAM中,这个就需要一定的时间。所以我们进行读写操作之前,首先要读一下液晶当前状态,是不是在“忙”,如果不忙,我们可以读写数据,如果在“忙”,我们就需要等待液晶忙完了,再进行操作。读状态是常用的,不过读液晶数据我接触的场合没怎么用过,大家了解这个功能即可。

6 脚是使能信号,很关键,液晶的读写命令和数据,都要靠它才能正常读写,我们后边详细讲这个引脚怎么用。

7 到 14 引脚就是 8 个数据引脚了,我们就是通过这 8 个引脚读写数据和命令的,统一接到了 P0 口上。
在这里插入图片描述

1.2.1602 液晶的读写时序

1602 的时序问题,大家要学会通过 LCD1602 的数据手册提供的时序图和时序参数表格来进行研究,而且看懂时序图是学习单片机所必须掌握的一项技能,如下图:在这里插入图片描述
我们先来看一下读操作时序的 RS 引脚和 R/W 引脚,这两个引脚先进行变化,因为是读操作,所以 R/W 引脚首先要置为高电平,而不管它原来是什么。读指令还是读数据,都是读操作,而且都有可能,所以 RS 引脚既有可能是置为高电平,也有可能是置为低电平,大家注意图上的画法。而 RS 和 R/W 变化了经过 Tsp1 这么长时间后,使能引脚 E 才能从低电平到高电平发生变化。

而使能引脚 E 拉高经过了 tD 这么长时间后,LCD1602 输出 DB 的数据就是有效数据了,我们就可以来读取 DB 的数据了。读完了之后,我们要先把使能 E 拉低,经过一段时间后 RS、R/W 和 DB 才可以变化继续为下一次读写做准备了。

而写操作时序和读操作时序的差别,就是写操作时序中,DB 的改变是由单片机来完成的,因此要放到使能引脚 E 的变化之前进行操作,其它区别大家可以自行对比一下。

细心的同学会发现,这个时序图上还有很多时间标签。比如 E 的上升时间 tR,下降时间时间 tF,使能引脚 E 从一个上升沿到下一个上升沿之间的长度周期 tC,使能 E 下降沿后,R/W 和 RS 变化时间间隔 tHD1 等等很多时间要求,这些要求怎么看呢?放心,只要是正规的数据手册,都会把这些时间要求给大家标记出来的。我们来看下表 :
在这里插入图片描述
tC:指的是使能引脚 E 从本次上升沿到下次上升沿的最短时间是 400ns,而我们单片机因为速度较慢,一个机器周期就是 1us 多,而一条 C 语言指令肯定是一个或者几个机器周期的,所以这个条件完全满足。

tPW:指的是使能引脚 E 高电平的持续时间最短是 150ns,同样由于我们的单片机比较慢,这个条件也完全满足。

tR, tF:指的是使能引脚 E 的上升沿时间和下降沿时间,不能超过 25ns,别看这个数很小,其实这个时间限值是很宽裕的,我们实际用示波器测了一下开发板的这个引脚上升沿和下降沿时间大概是 10ns 到 15ns 之间,完全满足。

tSP1:指的是 RS 和 R/W 引脚使能后至少保持 30ns,使能引脚 E 才可以变成高电平,这个条件同样也完全满足。

tHD1:指的是使能引脚 E 变成低电平后,至少保持 10ns 之后,RS 和 R/W 才能进行变化,这个条件也完全满足。

tD:指的是使能引脚 E 变成高电平后,最多 100ns 后,1602 就把数据送出来了,那么我们就可以正常去读取状态或者数据了。

tHD2:指的是读操作过程中,使能引脚 E 变成低电平后,至少保持 20ns,DB 数据总线才可以进行变化,这个条件也完全满足。

tSP2:指的是 DB 数据总线准备好后,至少保持 40ns,使能引脚 E 才可以从低到高进行使能变化,这个条件也完全满足。

tHD2:指的是写操作过程中,要引脚 E 变成低电平后,至少保持 10ns,DB 数据总线才可以变化,这个条件也完全满足。

1602 液晶内部带了 80 个字节的显示 RAM ,用来存储我们发送的数据,它的构造如图所示:
在这里插入图片描述
第一行的地址是 0x00H 到 0x27,第二行的地址从 0x40 到 0x67,其中第一行 0x00 到 0x0F 是与液晶上第一行 16 个字符显示位置相对应的,第二行 0x40 到 0x4F 是与第二行 16 个字符显示位置相对应的。而每行都多出来一部分,是为了显示移动字幕设置的。1602 字符液晶是显示字符的,因此它跟 ASCII 字符表是对应的。比如我们给 0x00 这个地址写一个‘a’,也就是十进制的 97,液晶的最左上方的那个小块就会显示一个字母 a。

液晶有一个状态字字节,我们通过读取这个状态字的内容,就可以知道 1602 液晶的一些内部情况,如下表所示。在这里插入图片描述
这个状态字节有 8 个位,最高位表示了当前液晶是不是“忙”,如果这个位是 1 表示液晶正“忙”,禁止我们读写数据或者命令,如果是 0,则可以进行读写。而低 7 位就表示了当前数据地址指针的位置。

1602 的基本操作时序,一共有 4 个,这些大家都不需要记住,但是都需要理解,因为我们现在不是为了应付考试,所以不需要你把手册背熟,但是你写程序的时候,打开手册要能看懂如何操作,还要再提醒一句,单片机读外部状态前,必须先保证自己是高电平哦。

我们这里要做 1602 液晶的程序,因此先把用到的总线接口做一个统一声明:

#define LCD1602_DB P0 

sbit LCD1602_RS = P2^6 ;
sbit LCD1602_RW = P2^5 ;
sbit LCD1602_E = P2^7 ;

1、读状态:RS = L , R/W = H ,E = H 。这个逻辑很简单,也就是说我们接着写:

	LCD1602_DB = 0xFF ;
	LCD1602_RS = 0 ;
	LCD1602_RW = 1 ;
	LCD1602_E = 1 ;
	sta = LCD1602_DB ; 

这样就把当前液晶的状态字读到了 sta 这个变量中,我们可以通过判断 sta 最高位的值来了解当前液晶是否处于“忙”状态,也可以得知当前数据的指针位置。两个问题,一是如果我们当前读到的状态是“不忙”,那么我们程序可以进行读写操作,如果当前状态是“忙”,那么我们还得继续等待重新判断液晶的状态;问题二,大家可以看我之前的文章,流水灯、数码管、点阵、1602 液晶都是用到了 P0 口总线,我们读完了液晶状态继续保持 LCD1602_E 是高电平的话,1602 液晶会继续输出它的状态值,输出的这个值会占据了 P0 总线,干扰到流水灯数码管等其它外设,所以我们读完了状态,通常要把这个引脚拉低来释放总线,这里我们用了一个 do…while 循环语句来实现。

uchar sta ;
	
LCD1602_DB = 0xFF ;
LCD1602_RS = 0 ;
LCD1602_RW = 1 ;

do
{
	LCD1602_E = 1 ;
	sta = LCD1602_DB ; // 读取状态字
	LCD1602_E = 0 ;
} while(sta & 0x80) ; // bit7为1表示液晶正忙,重复检测为0为止	

2、读数据:RS=H,R/W=H,E=H。这个逻辑也很简单,但是读数据不常用,大家了解一下就可以了,这里就不详细解释了。

3、写指令:RS=L,R/W=L,D0~D7=指令码,E=高脉冲。
这个在逻辑上没什么难的,只是 E=高脉冲这个问题要解释一下。这个指令一共有 4 条语句,其中前三条语句顺序无所谓,但是 E=高脉冲这一句很关键。实际上流程是这样的:因为我们现在是写数据,所以我们首先要保证我们的 E 引脚是低电平状态,而前三句不管我们怎么写,1602 液晶只要没有接收到 E 引脚的使能控制,它都不会来读总线上的信号的。当通过前三句准备好数据之后,E 使能引脚从低电平到高电平变化,然后 E 使能引脚再从高电平到低电平出现一个下降沿,1602 液晶内部一旦检测到这个下降沿后,并且检测到 RS=L,R/W=L,就马上来读取 D0~D7 的数据,完成单片机写 1602 指令过程。归纳总结我们写了个 E=高脉冲,意思就是:E 使能引脚先从低拉高,再从高拉低,形成一个高脉冲。

4、写数据:RS=H,R/W=L,D0~D7=数据,E=高脉冲
写数据和写指令是类似的,就是把 RS 改成 H,把总线改成数据即可。

此外要顺便提一句,这里用的1602液晶所使用的接口时序是摩托罗拉公司所创立的 6800时序,还有另外一种时序是 Intel 公司的 8080 时序,也有部分液晶模块采用,只是相对来说比较少见,大家知道这么回事即可。

1.3.1602 液晶的指令

与单片机寄存器的用法类似,1602 液晶在使用的时候,我们首先要进行初始的功能配置,1602 液晶有以下几个指令需要了解。

1、显示模式设置
写指令 0x38,设置 16x2 显示,5x7 点阵,8 位数据接口。这条指令对我们这个液晶来说是固定的,必须写 0x38,大家仔细看会发现我们的液晶实际上内部点阵是 5x8 的,还有一些 1602 液晶还兼容串行通信,用 2 个 IO 口即可,但是速度慢,我们这个液晶就是固定的 0x38 模式。

2、显示开/关以及光标设置指令
这里有 2 条指令,第一条指令,一个字节中 8 位,其中高 5 位是固定的 0b00001,低 3 位我们分别用 DCB 从高到低表示,D=1 表示开显示,D=0 表示关显示;C=1 表示显示光标,C=0 表示不显示光标;B=1 表示光标闪烁,B=0 表示光标不闪烁。

第二条指令,高 6 位是固定的 0b000001,低 2 位我们分别用 NS 从高到低表示,其中 N=1 表示读或者写一个字符后,指针自动加 1,光标自动加 1,N=0 表示读或者写一个字符后指针自动减 1,光标自动减 1;S=1 表示写一个字符后,整屏显示左移(N=1)或右移(N=0),以达到光标不移动而屏幕移动的效果,如同我们的计算器输入一样的效果,而 S=0 表示写一个字符后,整屏显示不移动。

3、清屏指令
固定的,写入 0x01 表示显示清屏,其中包含了数据指针清零,所有的显示清零。写入 0x02 则仅仅是数据指针清零,显示不清零。

4、RAM 地址设置指令
该指令码的最高位为 1,低 7 位为 RAM 的地址,RAM 地址与液晶上字符的关系如上表所示。通常,我们在读写数据之前都要先设置好地址,然后再进行数据的读写操作。

2.实例

2.1.显示字符

1602 液晶手册提供了一个初始化过程,由于不检测“忙”位,所以程序比较复杂,而我们总结了一个更加简易方便的过程提供给大家,手册上描述的那个,大家仅仅作为了解就可以了,下面我把程序写出来大家看下,我们的初始化只用了 4 条语句,没有像手册介绍的那么繁琐。

#include<reg52.h>

typedef unsigned char uchar ;
typedef unsigned int uint ;
typedef	unsigned long ulong ;

#define LCD1602_DB P0 

sbit LCD1602_RS = P2^6 ;
sbit LCD1602_RW = P2^5 ;
sbit LCD1602_E = P2^7 ;

void InitLcd1602();
void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str);

void main()
{
 unsigned char str[] = "Kingst Studio";
 InitLcd1602();
 LcdShowStr(2, 0, str);
 LcdShowStr(0, 1, "Welcome to YU");
 while (1);
}

/* 液晶等待函数 */
void LcdWaitReady()
{
	uchar sta ;
	
	LCD1602_DB = 0xFF ;
	LCD1602_RS = 0 ;
	LCD1602_RW = 1 ;

	do
	{
		LCD1602_E = 1 ;
		sta = LCD1602_DB ; // 读取状态字
		LCD1602_E = 0 ;
	} while(sta & 0x80) ; // bit7为1表示液晶正忙,重复检测为0为止	
}

/* 向LCD1602写入命令函数 */
void LcdWriteCmd(uchar cmd)
{
	LcdWaitReady() ;
	LCD1602_RS = 0 ;
	LCD1602_RW = 0 ;
	LCD1602_DB = cmd ;
	LCD1602_E = 1 ;
	LCD1602_E = 0 ;	
}

/* 向LCD1602写入数据函数 */
void LcdWriteDat(uchar dat)
{
	LcdWaitReady() ;
	LCD1602_RS = 1 ;
	LCD1602_RW = 0 ;
	LCD1602_DB = dat ;
	LCD1602_E = 1 ;
	LCD1602_E = 0 ;	
}

/* 设置RAM起始地址,亦光标位置,(x,y)- 对应屏幕上的字符坐标 */
void LcdSetCursor(uchar x , uchar y)
{
	uchar addr ;

	if (y == 0) // 由输入的屏幕坐标计算显示RAM的地址
		addr = 0x00 + x ;
	else 
		addr = 0x40 + x ;
	LcdWriteCmd(addr | 0x80) ; // 设置RAM的地址
}

/* 在液晶上显示字符串 (x,y)- 对应屏幕上的起始坐标,stc - 字符串指针 */
void LcdShowStr(uchar x , uchar y ,uchar *str) 
{
	LcdSetCursor(x , y) ; // 设置起始地址
	while(*str != '\0')
	{
		LcdWriteDat(*str ++) ; // 连续写入字符串数据,直到检测到结束符	
	}	
}

/* 区域清除,清除从(x,y)坐标起始的len个字符位 */
void LcdAreaClear(uchar x , uchar y , uchar len)
{
	LcdSetCursor(x , y) ;
	while(len --)
	{
		LcdWriteDat(' ') ;
	}
}

/* 整屏清除 */
void LcdFullClear()
{
	LcdWriteCmd(0x01)  ;
}

/* LCD1602初始化 */
void InitLcd1602()
{
	LcdWriteCmd(0x38) ;	// 16*2 显示,5*7点阵,8位数据接口 
	LcdWriteCmd(0x0C) ;	// 显示器开,光标关闭
	LcdWriteCmd(0x06) ;	// 文字不动,地址自动+1
	LcdWriteCmd(0x01) ;	// 清屏
}

在这里插入图片描述

2.2.整屏移动

我们前边学点阵 LED 的时候,可以实现上下移动,左右移动等。而对于 1602 液晶来说,也可以进行屏幕移动,实现我们想要的一些效果,那我们来用一个例程实现字符串在 1602 液晶上的左移。

#include<reg52.h>

typedef unsigned char uchar ;
typedef unsigned int uint ;
typedef	unsigned long ulong ;

#define LCD1602_DB P0 

sbit LCD1602_RS = P2^6 ;
sbit LCD1602_RW = P2^5 ;
sbit LCD1602_E = P2^7 ;

bit flag500ms = 0; //500ms 定时标志
uchar T0RH = 0; //T0 重载值的高字节
uchar T0RL = 0; //T0 重载值的低字节

//待显示的第一行字符串
uchar code str1[] = "Kingst Studio";
//待显示的第二行字符串,需保持与第一行字符串等长,较短的行可用空格补齐
uchar code str2[] = "Let's move...";

void ConfigTimer0(uint ms);
void InitLcd1602();
void LcdShowStr(uchar x, uchar y, uchar *str, uchar len);

void main()
{
	uchar i;
	uchar index = 0; //移动索引
	uchar pdata bufMove1[16+sizeof(str1)+16]; //移动显示缓冲区 1
	uchar pdata bufMove2[16+sizeof(str2)+16]; //移动显示缓冲区 2
	EA = 1; //开总中断
	ConfigTimer0(10); //配置 T0 定时 10ms
	InitLcd1602(); //初始化液晶
 	//缓冲区开头一段填充为空格
	for (i=0; i<16; i++)
	{
		bufMove1[i] = ' ';
		bufMove2[i] = ' ';
	}
	//待显示字符串拷贝到缓冲区中间位置
	for (i=0; i<(sizeof(str1)-1); i++)
	{
	bufMove1[16+i] = str1[i];
	bufMove2[16+i] = str2[i];
	}
	 //缓冲区结尾一段也填充为空格
	for (i=(16+sizeof(str1)-1); i<sizeof(bufMove1); i++)
	{
	bufMove1[i] = ' ';
	bufMove2[i] = ' ';
	}
 
	while (1)
	{
		if (flag500ms) //每 500ms 移动一次屏幕
		{
			flag500ms = 0;
			 //从缓冲区抽出需显示的一段字符显示到液晶上
			LcdShowStr(0, 0, bufMove1+index, 16);
			LcdShowStr(0, 1, bufMove2+index, 16);
			 //移动索引递增,实现左移
			index++;
			if (index >= (16+sizeof(str1)-1))
			{ //起始位置达到字符串尾部后即返回从头开始
				index = 0;
			}
		}
	} 
}

/* 定时器函数 */
void ConfigTimer0(uint ms)
{
	ulong tmp ;
	tmp = 11059200 / 12 ; // 定时器频率
	tmp = (tmp * ms) / 1000 ; // 计算所需的计数值
	tmp = 65536 - tmp ; // 计算定时器重载值
	tmp = tmp + 18 ; // 补偿中断响应延时造成的误差 
	T0RH = (uchar)(tmp >> 8) ;
	T0RL = (uchar)tmp ;
	TMOD = TMOD & 0xF0 ;
	TMOD = TMOD | 0x01 ;
	TH0 = T0RH ; // 加载T0重载值
	TL0 = T0RL ;
	ET0 = 1 ; // 使能T0中断
	TR0 = 1 ; // 启动T0
}

/* 液晶等待函数 */
void LcdWaitReady()
{
	uchar sta ;
	
	LCD1602_DB = 0xFF ;
	LCD1602_RS = 0 ;
	LCD1602_RW = 1 ;

	do
	{
		LCD1602_E = 1 ;
		sta = LCD1602_DB ; // 读取状态字
		LCD1602_E = 0 ;
	} while(sta & 0x80) ; // bit7为1表示液晶正忙,重复检测为0为止	
}

/* 向LCD1602写入命令函数 */
void LcdWriteCmd(uchar cmd)
{
	LcdWaitReady() ;
	LCD1602_RS = 0 ;
	LCD1602_RW = 0 ;
	LCD1602_DB = cmd ;
	LCD1602_E = 1 ;
	LCD1602_E = 0 ;	
}

/* 向LCD1602写入数据函数 */
void LcdWriteDat(uchar dat)
{
	LcdWaitReady() ;
	LCD1602_RS = 1 ;
	LCD1602_RW = 0 ;
	LCD1602_DB = dat ;
	LCD1602_E = 1 ;
	LCD1602_E = 0 ;	
}

/* 设置RAM起始地址,亦光标位置,(x,y)- 对应屏幕上的字符坐标 */
void LcdSetCursor(uchar x , uchar y)
{
	uchar addr ;

	if (y == 0) // 由输入的屏幕坐标计算显示RAM的地址
		addr = 0x00 + x ;
	else 
		addr = 0x40 + x ;
	LcdWriteCmd(addr | 0x80) ; // 设置RAM的地址
}

/* 在液晶上显示字符串 (x,y)- 对应屏幕上的起始坐标,stc - 字符串指针 */
void LcdShowStr(uchar x , uchar y ,uchar *str,uchar len) 
{
	LcdSetCursor(x , y) ; // 设置起始地址
	while(len--)
	{
		LcdWriteDat(*str ++) ; // 连续写入字符串数据,直到检测到结束符	
	}	
}

/* 区域清除,清除从(x,y)坐标起始的len个字符位 */
void LcdAreaClear(uchar x , uchar y , uchar len)
{
	LcdSetCursor(x , y) ;
	while(len --)
	{
		LcdWriteDat(' ') ;
	}
}

/* 整屏清除 */
void LcdFullClear()
{
	LcdWriteCmd(0x01)  ;
}

/* LCD1602初始化 */
void InitLcd1602()
{
	LcdWriteCmd(0x38) ;	// 16*2 显示,5*7点阵,8位数据接口 
	LcdWriteCmd(0x0C) ;	// 显示器开,光标关闭
	LcdWriteCmd(0x06) ;	// 文字不动,地址自动+1
	LcdWriteCmd(0x01) ;	// 清屏
}

/* T0 中断服务函数,定时 500ms */
void InterruptTimer0() interrupt 1
{
	static unsigned char tmr500ms = 0;
 
	TH0 = T0RH; //重新加载重载值
	TL0 = T0RL;
	tmr500ms++;
	if (tmr500ms >= 50)
	{
		tmr500ms = 0;
		flag500ms = 1;
	}
}
  • 35
    点赞
  • 163
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
单片机课程设计是电子信息类专业的重要课程之一,通过本课程的学习,能够掌握单片机的基本原理和应用技能。LCD1602移动显示是单片机课程设计中的一个常见内容,通过这个设计,能够加深对单片机工作原理的理解,并提升实际操作能力。 在这个课程设计中,我们首先需要了解LCD1602的基本原理和工作方式,包括液晶显示原理、接口方式以及驱动时序等。然后,我们需要设计一个可以控制LCD1602显示内容的单片机程序,这个程序需要能够实现LCD1602上显示内容的移动和变化。 具体而言,我们可以通过单片机的IO口控制LCD1602的数据和指令输入,从而实现在LCD1602上显示移动的文字或图形。在设计过程中,我们还要考虑到一些细节问题,比如数据的传输速度、显示内容的更新频率、以及显示效果的优化等。 除了基本的移动显示功能,我们还可以考虑加入一些其他的特色功能,比如在LCD1602上显示动态图案、实时数据的监测和显示等。这样不仅可以提升课程设计的难度和趣味性,也能够更好地锻炼我们的设计和创新能力。 总的来说,LCD1602移动显示的单片机课程设计,是一个很好的实践机会,通过这个设计,我们能够深入了解单片机的工作原理,提升实际操作能力,并且培养创新意识和问题解决能力。希望通过努力,能够圆满完成这个课程设计,为将来的学习和工作打下坚实的基础。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

倾晨灬雨曦

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

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

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

打赏作者

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

抵扣说明:

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

余额充值