关于12864的使用

关于ST7920控制器的12864液晶,网上资料有很多,但是大部分感觉都有漏洞或者说是错误。本文转载网上zhaoshan413之手,感谢他的无私贡献。
一、首先说一下关于驱动函数的书写,这些是液晶显示的基础
      一般包括四个函数:
     1、写命令函数;
     2、写数据函数;
     3、读状态函数;
     4、读数据函数;
     这四个函数并不是必须全部写的,具体要看你实现的功能,如果只是单纯的显示汉字和字符,写命令、写数据、读状态这三个函数就够了,如过你还需要进行一些绘图的操作,那读数据函数也必须书写。
     另外关于读状态函数,其实也就是用于判忙操作,我看郭天祥的书里面是这样说的:原则上每次对控制器进行读写操作之前,都必须进行读写检测,由于单片机的操作速度慢于液晶控制器的反应速度,因此可不进行读写检测,或者只进行简短的延时即可。因此,读状态函数也可以不写,只用简短的延时函数替换即可。

1、写操作的编写:
首先看一下时序图 关于12864的使用(转载来自阿莫电子论坛)

由图可见操作很简单:
1>RS=1(写数据操作);或者RS=0(写命令操作);
2>RW=0;//指明为写操作
3>E=1;
4>DB=data;//data为你要写入的命令或数据值
5>E=0;

以下是我的驱动函数,仅供参考:

#define  lcd_data  P0        //数据口
sbit  RS   = P2^4;          //选择寄存器(并行)0:指令寄存器 1:数据寄存器;
sbit  RW   = P2^5;          //读写控制脚(并行)0:写入 1:读出
sbit     =P2^6;          //读写数据启始脚(并行)
sbit  PSB  = P2^1;         //串并方式选择引脚,0为串行模式,1为8/4位数据口模式
sbit  RST  = P2^3;         //复位引脚

/
Set_Cursor(0,0); //光标地址设定
Display_Char(0x21); //显示字符!

扩展程序:在指定位置显示字符串
/
Display_String(1,0,"WWW.CEPARK.COM");              //显示字符串
3、显示汉字

因为一个汉字占用两个字节的大小,因此要想显示一个汉字,需要进行两个数据写入操作。
所支持的8192个16*16的汉字详见数据手册附录中的ST7920GB中文字型码表。
参考程序:
/
Display_HZ(0,1,"电");                                //显示电
Display_HZ(0,2,"子");                                //显示子
Display_HZ(0,3,"园");                                //显示园
效果图:
关于12864的使用(转载来自阿莫电子论坛)

扩展程序:
/
Display_HZ_Line(2,0,"欢迎转载,转载请注明出处,谢谢!");//显示一行汉字
效果图:
关于12864的使用(转载来自阿莫电子论坛)

再来一个整体的现实效果
/
Display_Init();

Set_Cursor(0,0);      //光标地址设定
Display_Char(0x21);      //显示字符!

Display_String(1,0,"WWW.CEPARK.COM");  //显示字符串

Display_HZ(0,1,"电");      //显示电
Display_HZ(0,2,"子");      //显示子
Display_HZ(0,3,"园");      //显示园

Display_HZ_Line(2,0,"欢迎转载,转载请注明出处,谢谢!");//显示一行汉字
while(1);
}
关于12864的使用(转载来自阿莫电子论坛)


照片002.jpg(126.03 KB, 下载次数: 1)

 

照片 002.jpg


四、关于CGRAM的使用:
可以参考这个网站的程序: http://bbs.友好站点,请勿转贴.com/ShowTopic.aspx?id=81220ST7920自行产生RAM提供使用者图像定义(造字)功能,可以提供四组16*16点的自定义图像空间,使用者可以将内部自行没有提供的图像自行定义到CGRAM中,便可以通过DDRAM显示在液晶屏上。注意:网上介绍说ST7920芯片同屏幕不能显示4个以上自定义汉字(用CGRAM)。显示CGRAM字型:将16位元资料写入DDRAM中,一共有0000H,0002H,0004H,0006H四种编码。
关于12864的使用(转载来自阿莫电子论坛)
操作步骤:
1>    设置为扩充指令集;
2>    设置SR=O,允许设定CGRAM地址;
3>    设置为基本指令集;
4>    循环执行以下操作写入16个字节数据(设定CGRAM的存储地址;写入自定义数据);
5>    设置DDRAM地址
6>    写入显示CGRAM显示码
关于12864的使用(转载来自阿莫电子论坛)
关于12864的使用(转载来自阿莫电子论坛)

五、关于GDRAM绘图模式的操作
     ST7920提供64×32 个字节的空间(由扩充指令设定绘图RAM地址),最多可以控制256×64点阵的二维绘图缓冲空间,在更改绘图RAM时,由扩充指令设置GDRAM地址先垂直地址后水平地址(连续2个字节的数据来定义垂直和水平地址),再2个字节的数据给绘图RAM(先高8位后低8 位)。地址分布如下:
关于12864的使用(转载来自阿莫电子论坛)

操作步骤:

1>设置为扩充指令集,关闭绘图模式;

2>写两字节的GDRAM地址,先写垂直地址,后写水平地址地址;

3>写入两字节的数据,先写高八位数据,后写低八位数据;

4>打开绘图模式;

5>设置回基本指令集;


关于12864的使用(转载来自阿莫电子论坛)

应用实例:


GUI_Fill_GDRAM(0xcc);      //竖条显示

实物图:


关于12864的使用(转载来自阿莫电子论坛)

1
、打点

打点操作是作图的基础,众所周知,画任何图形均可以由画一个个点来实现。

具体打点的操作步骤:

1>确定打点的位置;

2>读出该点所在的数据值;

3>修改该点相应的位的值,对于单色液晶来说,只有两种操作,已是点亮该点,二是熄灭该点;

4>将修改后的数据值写入对应的地址;


由于打点首先需要进行读操作,因此需要编写读数据的驱动函数:

读操作的编写:
时序图:

关于12864的使用(转载来自阿莫电子论坛)

操作如下:

1>释放总线:DB=0;

2>RS=1(读数据操作);或者RS=0(读状态操作);

3>RW=1;//指明为读操作

4>E=1;

5>data=DB;//data为存储读回数据的变量

6>E=0;

读操作参考程序:

关于12864的使用(转载来自阿莫电子论坛)



打点参考程序:
关于12864的使用(转载来自阿莫电子论坛)
关于12864的使用(转载来自阿莫电子论坛)

应用实例:


GUI_Point(64,32,1);       //打点操作


关于12864的使用(转载来自阿莫电子论坛)


关于12864的使用(转载来自阿莫电子论坛)
关于12864的使用(转载来自阿莫电子论坛)

应用例子:

GUI_HLine(10,120,10,1);      //画水平线操作
GUI_RLine(10,10,60,1);       //画垂直线操作


任意两点画线:
关于12864的使用(转载来自阿莫电子论坛)
关于12864的使用(转载来自阿莫电子论坛)
关于12864的使用(转载来自阿莫电子论坛)
关于12864的使用(转载来自阿莫电子论坛)
关于12864的使用(转载来自阿莫电子论坛)

应用例子:

GUI_Line(0,0,127,63,1);      //画线操作


关于12864的使用(转载来自阿莫电子论坛)
画矩形:

关于12864的使用(转载来自阿莫电子论坛)

应用例子:

GUI_Rectangle(5,5,122,58,1);     //画矩形操作


关于12864的使用(转载来自阿莫电子论坛)
填充矩形:

关于12864的使用(转载来自阿莫电子论坛)

关于12864的使用(转载来自阿莫电子论坛)

应用例子:

GUI_Rectangle_Fill(5,5,122,58,1);    //填充矩形操作


关于12864的使用(转载来自阿莫电子论坛)
画正方形和填充正方形:

关于12864的使用(转载来自阿莫电子论坛)
关于12864的使用(转载来自阿莫电子论坛)

应用例子:

GUI_Square(10,10,50,1);      //画正方形操作
GUI_Square_Fill(20,20,20,1);   //填充正方形操作


关于12864的使用(转载来自阿莫电子论坛)


再来个画圆的程序:
关于12864的使用(转载来自阿莫电子论坛)

应用例子:

GUI_Circle(32,32,30,1);      //画圆操作


关于12864的使用(转载来自阿莫电子论坛)


照片015.jpg(108.2 KB, 下载次数: 2)

 

照片 015.jpg

12.jpg(49.36 KB, 下载次数: 0)

 

12.jpg

11.jpg(169.08 KB, 下载次数: 0)

 

11.jpg

12(1).jpg(49.36 KB, 下载次数: 0)

 

12 (1).jpg
//***********************************************************************************************
//说明:带字库的12864液晶(ST7920)驱动程序
//创建人:赵山	  shanzhao_work@qq.com		
//创建日期:2009-9-18 23:20
//欢迎转载,转载请注明作者及出处!谢谢!
//***********************************************************************************************
#include "LCD12864.h"			//包含液晶端口定义的头文件

//********************************************************
//延时函数
//********************************************************
void delay(unsigned int k)
{  
	unsigned int i;
	unsigned char j;
	for(i=0;i<k;i++)
	{
		for(j=0;j<10;j++);
	}
}

//********************************************************
//延时1ms函数
//********************************************************
void delay_ms(unsigned int k)	//延时0.994us,晶振12M
{
    unsigned int x,y;
    for(x=k;x>0;x--)
        for(y=121;y>0;y--);
} 

//********************************************************
//写命令函数
//********************************************************
void LcdWcom(unsigned char WCom)
{
	  delay(1);
	  RS=0;						//指明操作对象为指令寄存器
	  RW=0;						//指明为写操作
	  E=1;
	  lcd_data=WCom;			//将命令写入总线
	  E=0;
}

//********************************************************
//写数据函数
//********************************************************		
void LcdWdata(unsigned char WData)
{
	  delay(1);
	  RS=1;						//指明操作对象为数据寄存器
	  RW=0;						//指明为写操作
	  E=1;
	  lcd_data=WData;			//将数据写入总线
	  E=0;
}

//********************************************************
//清屏函数
//********************************************************
void Display_Clear(void)
{
	LcdWcom(0x01);				//写入清楚显示命令0x01
	delay(100);
}

//********************************************************
//显示初始化函数
//********************************************************
void Display_Init(void)
{
	delay_ms(45);				//延时45ms
    PSB=1;					//8位并行口
	//复位操作
	RST=1;
	delay(1);
	RST=0;
	delay(1);
	RST=1;
	delay(1);	
	//功能设定
	LcdWcom(0x30);				//设置为8位并行口,基本指令集
	delay(10);
	LcdWcom(0x30);				//再次设置为8位并行口,基本指令集
	delay(5); 
//	//显示开关控制
	LcdWcom(0x0c);				//游标显示关,正常显示,整体显示开
	delay(10);
	//清除显示
	LcdWcom(0x01);	
	delay_ms(12);				//延时12ms
	//进入点设置
	LcdWcom(0x06); 				//设置为游标右移,DDRAM位地址加1,画面不移动
	delay(5); 
	LcdWcom(0x0C);				//开显示
}

//********************************************************
//设置光标函数
//参数说明:x为行号,y为列号
//********************************************************
void Set_Cursor(unsigned char x, unsigned char y)
{
	unsigned char i;
	switch(x)   								//确定行号
	{
		case 0x00: i=0x80; break;				//第一行
		case 0x01: i=0x90; break; 				//第二行
		case 0x02: i=0x88; break; 				//第三行
		case 0x03: i=0x98; break; 				//第四行
		default : break;
	}
	i = y+i; 									//确定列号
	LcdWcom(i);
}


//********************************************************
//显示字符函数
//********************************************************
void Display_Char(unsigned char Alphabet)
{
	LcdWdata(Alphabet);			//写入需要显示字符的显示码
}

//********************************************************
//指定位置显示字符串函数
//参数说明:x为行号,y为列号
//********************************************************
void Display_String(unsigned char x,unsigned char y,unsigned char *Alphabet)
{
	unsigned char i=0;
	Set_Cursor(x,y);				//设置显示的起始地址
	while(Alphabet[i]!='\0')
	{
		LcdWdata(Alphabet[i]);			//写入需要显示字符的显示码
		i++;
	}
}

//********************************************************
//指定位置显示汉字函数
//参数说明:x为行号,y为列号
//********************************************************
void Display_HZ(unsigned char x,unsigned char y,unsigned char *HZ)
{
	Set_Cursor(x,y);			//设置显示的起始地址
	LcdWdata(HZ[0]);			//写入需要显示汉字的高八位数据
	LcdWdata(HZ[1]);			//写入需要显示字符的低八位数据
}

//********************************************************
//指定位置显示一行汉字函数,可自动换行
//参数说明:x为行号,y为列号
//********************************************************
void Display_HZ_Line(unsigned char x,unsigned char y,unsigned char *HZ)
{
	unsigned char i=0;
	Set_Cursor(x,y);				//设置显示的起始地址
	while(HZ[i]!='\0')
	{
		LcdWdata(HZ[i++]);			//写入需要显示汉字的高八位数据
		LcdWdata(HZ[i++]);			//写入需要显示字符的低八位数据
		if((y+i)%16==0)				//如果满一行
		{	
			x++;
			if(x==4)				//如果满一屏
				x=0;
			Set_Cursor(x,0);		//重新设置显示的起始地址
		}
	}
}

//********************************************************
//设置CGRAM字库
//ST7920 CGRAM(用户自定义图标)空间分布
//空间1地址:40H~4FH共16个地址,一个地址对应两个字节数据;对应调用码:0000H
//空间2地址:50H~5FH共16个地址,一个地址对应两个字节数据;对应调用码:0002H
//空间3地址:60H~6FH共16个地址,一个地址对应两个字节数据;对应调用码:0004H
//空间4地址:70H~7FH共16个地址,一个地址对应两个字节数据;对应调用码:0006H
//参数说明:num为空间编号,CGRAM_ZIKU为地址指针
//********************************************************
void SET_CGRAM(unsigned char num,unsigned char *CGRAM_ZIKU)
{
	unsigned char i,add;
	LcdWcom(0x34);					//再次设置为8位并行口,扩展指令集
	LcdWcom(0x02);					//SR=0,允许设置CGRAM地址
	LcdWcom(0x30);					//恢复设置为8位并行口,基本指令集
	add=(num<<4)|0x40;				//计算CGRAM的首地址
	for(i=0;i<16;i++)
	{
		LcdWcom(add+i);				//设置CGRAM的首地址
		LcdWdata(CGRAM_ZIKU[i*2]);	//写入高8位数据
		LcdWdata(CGRAM_ZIKU[i*2+1]);//写入低8位数据
	}
}

//********************************************************
//指定位置显示CGRAM自造字函数
//参数说明:x为行号,y为列号,num为编号
//********************************************************
void Display_CGRAM(unsigned char x,unsigned char y,unsigned char num)
{
	Set_Cursor(x,y);				//设置显示的起始地址
	LcdWdata(0x00);					//写入需要显示汉字的高八位数据
	LcdWdata(num*2);				//写入需要显示字符的低八位数据
}

//********************************************************
//读数据函数
//********************************************************
unsigned char LcdRdata(void)
 {
	unsigned char LcdData;
	lcd_data=0xff;					//释放数据线
	RW=1;							//指明为读操作
	RS=1;							//指明操作对象为数据寄存器
	E=1;
	delay(1);
	LcdData = lcd_data;				//读取数据线上的数据
	E=0;
	return (LcdData); 	 
 }
//
********************************************************
填充GDRAM数据:
参数:dat为填充的数据
********************************************************
void GUI_Fill_GDRAM(unsigned char dat)
{ 
	unsigned char i;                 
	unsigned char j; 
	unsigned char k; 
	unsigned char bGDRAMAddrX = 0x80;		//GDRAM水平地址 
	unsigned char bGDRAMAddrY = 0x80;		//GDRAM垂直地址 
	for(i = 0; i < 2; i++)					                                                                                         
	{ 
		for(j = 0; j < 32; j++)                                                                 
		{ 
			for(k = 0; k < 8; k++)                                                         
			{ 
				LcdWcom(0x34);				//设置为8位MPU接口,扩充指令集,绘图模式关
				LcdWcom(bGDRAMAddrY+j);		//垂直地址Y                                                                         
				LcdWcom(bGDRAMAddrX+k);		//水平地址X 
				LcdWdata(dat);
				LcdWdata(dat);
			} 
		} 
		bGDRAMAddrX = 0x88;                                                                                                                                         
	} 
	LcdWcom(0x36);							//打开绘图模式
	LcdWcom(0x30);							//恢复基本指令集,关闭绘图模式   
} 
//
//
********************************************************
打点函数
参数:color=1,该点填充1;color=0,该点填充白色0;
********************************************************
void GUI_Point(unsigned char x,unsigned char y,unsigned char color)
{     
	unsigned char x_Dyte,x_byte;				//定义列地址的字节位,及在字节中的哪1位 
	unsigned char y_Dyte,y_byte;				//定义为上下两个屏(取值为0,1),行地址(取值为0~31)
	unsigned char GDRAM_hbit,GDRAM_lbit;
	
	LcdWcom(0x36);								//扩展指令命令
	/***X,Y坐标互换,即普通的X,Y坐标***/
	x_Dyte=x/16;								//计算在16个字节中的哪一个
	x_byte=x&0x0f;								//计算在该字节中的哪一位
	y_Dyte=y/32;								//0为上半屏,1为下半屏
	y_byte=y&0x1f;								//计算在0~31当中的哪一行
  
	LcdWcom(0x80+y_byte);						//设定行地址(y坐标),即是垂直地址
  	LcdWcom(0x80+x_Dyte+8*y_Dyte);				//设定列地址(x坐标),并通过8*y_Dyte选定上下屏,即是水平地址
    
	LcdRdata();									//预读取数据
	GDRAM_hbit=LcdRdata();						//读取当前显示高8位数据
	GDRAM_lbit=LcdRdata();						//读取当前显示低8位数据
	delay(1);
  
	LcdWcom(0x80+y_byte);						//设定行地址(y坐标)
	LcdWcom(0x80+x_Dyte+8*y_Dyte);				//设定列地址(x坐标),并通过8*y_Dyte选定上下屏
	delay(1);
	
	if(x_byte<8)										//判断其在高8位,还是在低8位
	{
		if(color==1)
		{
			LcdWdata(GDRAM_hbit|(0x01<<(7-x_byte)));	//置位GDRAM区高8位数据中相应的点
		}
		else 
			LcdWdata(GDRAM_hbit&(~(0x01<<(7-x_byte))));	//清除GDRAM区高8位数据中相应的点	

		LcdWdata(GDRAM_lbit);							//显示GDRAM区低8位数据 
	}
	else
	{
		LcdWdata(GDRAM_hbit);
		if(color==1)
			LcdWdata(GDRAM_lbit|(0x01<<(15-x_byte)));	//置位GDRAM区高8位数据中相应的点
		else 
			LcdWdata(GDRAM_lbit&(~(0x01<<(15-x_byte))));//清除GDRAM区高8位数据中相应的点	
	} 
	LcdWcom(0x30);										//恢复到基本指令集
}

**************************************************************
画水平线函数
参数:color=1,填充1;color=0,填充0;
		x0,x1为起始和终点的水平坐标值,y为垂直坐标值
**************************************************************
void GUI_HLine(unsigned char x0, unsigned char x1, unsigned char y, unsigned char color) 
{  
	unsigned char  bak;

	if(x0>x1) 							// 对x0、x1大小进行排列,以便画图
	{  
		bak = x1;
		x1 = x0;
		x0 = bak;
	}
   
	do
	{  
		GUI_Point(x0, y, color);		// 从左到右逐点显示,描出垂直线
		x0++;
	}while(x1>=x0);
}

//********************************************************
//画竖直线函数
//参数:color=1,填充黑色1;color=0,填充0;
//		x为起始和终点的水平坐标值,y0,y1为垂直坐标值
//********************************************************
void GUI_RLine(unsigned char x, unsigned char y0, unsigned char y1, unsigned char color) 
{  
	unsigned char  bak;

	if(y0>y1) 							// 对y0、y1大小进行排列,以便画图
	{  
		bak = y1;
		y1 = y0;
		y0 = bak;
	}
   
	do
	{  
		GUI_Point(x, y0, color);		// 从上到下逐点显示,描出垂直线
		y0++;
	}while(y1>=y0);
}

//********************************************************
//任意两点画直线函数
//参数:color=1,该线填充1;color=0,该线填充0;
//		x0:直线起点的x坐标值,y0:直线起点的y坐标值
//		x1:直线终点的x坐标值,y1:直线终点的y坐标值
//********************************************************
void GUI_Line(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char color)
{  
	char dx;							// 直线x轴差值变量
	char dy;							// 直线y轴差值变量
	char dx_sym;						// x轴增长方向,为-1时减值方向,为1时增值方向
	char dy_sym;						// y轴增长方向,为-1时减值方向,为1时增值方向
	char dx_x2;							// dx*2值变量,用于加快运算速度
	char dy_x2;							// dy*2值变量,用于加快运算速度
	char di;							// 决策变量
   
   
   	if(x0==x1)									//判断是否为垂直线
	{
		GUI_RLine(x0,y0,y1,color);				//画垂直线
		return;
	}
	if(y0==y1)									//判断是否为水平线
	{
		GUI_HLine(x0,x1,y0,color);				//画水平线
		return;
	}
	
	dx = x1-x0;									// 求取两点之间的差值
	dy = y1-y0;
   
	/* 判断增长方向,或是否为水平线、垂直线、点 */
	if(dx>0)									// 判断x轴方向
	{  
		dx_sym = 1;								// dx>0,设置dx_sym=1
	}
	else
	{  
		if(dx<0)
		{  
			dx_sym = -1;						// dx<0,设置dx_sym=-1
		}
		else
		{  
			// dx==0,画垂直线,或一点
			GUI_RLine(x0, y0, y1, color);
			return;
		}
	}
   
	if(dy>0)									// 判断y轴方向
	{  
		dy_sym = 1;								// dy>0,设置dy_sym=1
	}
	else
	{  
		if(dy<0)
		{  
			dy_sym = -1;						// dy<0,设置dy_sym=-1
		}
		else
		{  
			// dy==0,画水平线,或一点
			GUI_HLine(x0, y0, x1, color);
			return;
		}
	}
    
	/* 将dx、dy取绝对值 */
	dx = dx_sym * dx;
	dy = dy_sym * dy;
 
	/* 计算2倍的dx及dy值 */
	dx_x2 = dx*2;
	dy_x2 = dy*2;
   
	/* 使用Bresenham法进行画直线 */
	if(dx>=dy)									// 对于dx>=dy,则使用x轴为基准
	{  
		di = dy_x2 - dx;
		while(x0!=x1)
		{  
			GUI_Point(x0, y0, color);
			x0 += dx_sym;
			if(di<0)
			{  
				di += dy_x2;					// 计算出下一步的决策值
			}
			else
			{  
				di += dy_x2 - dx_x2;
				y0 += dy_sym;
			}
		}
		GUI_Point(x0, y0, color);				// 显示最后一点
	}
	else										// 对于dx<dy,则使用y轴为基准
	{ 
		di = dx_x2 - dy;
		while(y0!=y1)
		{  
			GUI_Point(x0, y0, color);
			y0 += dy_sym;
			if(di<0)
			{ 
				di += dx_x2;
			}
			else
			{  
				di += dx_x2 - dy_x2;
				x0 += dx_sym;
			}
		}
		GUI_Point(x0, y0, color);				// 显示最后一点
	} 
}

//***************************************************************************
//画指定宽度的任意两点之间的直线
//参数:color=1,该线填充1;color=0,该线填充0;
//		x0:直线起点的x坐标值,y0:直线起点的y坐标值
//		x1:直线终点的x坐标值,y1:直线终点的y坐标值
//****************************************************************************
void GUI_LineWith(unsigned char x0, unsigned char y0, unsigned char x1, unsigned char y1, unsigned char with, unsigned char color)
{  
	char	dx;						// 直线x轴差值变量
	char	dy;          			// 直线y轴差值变量
	char	dx_sym;					// x轴增长方向,为-1时减值方向,为1时增值方向
	char	dy_sym;					// y轴增长方向,为-1时减值方向,为1时增值方向
	char	dx_x2;					// dx*2值变量,用于加快运算速度
	char	dy_x2;					// dy*2值变量,用于加快运算速度
	char	di;						// 决策变量
   
	char   wx, wy;					// 线宽变量
	char   draw_a, draw_b;
   
	// 参数过滤
	if(with==0) return;
	if(with>50) with = 50;
   
	dx = x1-x0;								// 求取两点之间的差值
	dy = y1-y0;
   
	wx = with/2;
	wy = with-wx-1;
   
	//判断增长方向,或是否为水平线、垂直线、点 
	if(dx>0)								// 判断x轴方向
	{  
		dx_sym = 1;							// dx>0,设置dx_sym=1
	}
	else
	{  
		if(dx<0)
		{  
			dx_sym = -1;					// dx<0,设置dx_sym=-1
		}
		else
		{  
			//dx==0,画垂直线,或一点
			wx = x0-wx;
			if(wx<0) wx = 0;
			wy = x0+wy;
         
			while(1)
			{  
				x0 = wx;
				GUI_RLine(x0, y0, y1, color);
				if(wx>=wy) break;
				wx++;
			}
			return;
		}
	}
   
	if(dy>0)								// 判断y轴方向
	{  
		dy_sym = 1;							// dy>0,设置dy_sym=1
	}
	else
	{  
		if(dy<0)
		{  
			dy_sym = -1;					// dy<0,设置dy_sym=-1
		}
		else
		{  
			//dy==0,画水平线,或一点
			wx = y0-wx;
			if(wx<0) wx = 0;
			wy = y0+wy;
			while(1)
			{  
				y0 = wx;
				GUI_HLine(x0, y0, x1, color);
				if(wx>=wy) break;
				wx++;
			}
			return;
		}
	}
    
	// 将dx、dy取绝对值
	dx = dx_sym * dx;
	dy = dy_sym * dy;
 
	//计算2倍的dx及dy值
	dx_x2 = dx*2;
	dy_x2 = dy*2;
   
	//使用Bresenham法进行画直线
	if(dx>=dy)								// 对于dx>=dy,则使用x轴为基准
	{  
		di = dy_x2 - dx;
		while(x0!=x1)
		{  
			//x轴向增长,则宽度在y方向,即画垂直线
			draw_a = y0-wx;
			if(draw_a<0) draw_a = 0;
			draw_b = y0+wy;
			GUI_RLine(x0, draw_a, draw_b, color);
			x0 += dx_sym;				
			if(di<0)
			{  
				di += dy_x2;				// 计算出下一步的决策值
			}
			else
			{  
				di += dy_x2 - dx_x2;
				y0 += dy_sym;
			}
		}
		draw_a = y0-wx;
		if(draw_a<0) draw_a = 0;
		draw_b = y0+wy;
		GUI_RLine(x0, draw_a, draw_b, color);
	}
	else									// 对于dx<dy,则使用y轴为基准
	{  
		di = dx_x2 - dy;
		while(y0!=y1)
		{  
			//y轴向增长,则宽度在x方向,即画水平线
			draw_a = x0-wx;
			if(draw_a<0) draw_a = 0;
			draw_b = x0+wy;
			GUI_HLine(draw_a, y0, draw_b, color);
         
			y0 += dy_sym;
			if(di<0)
			{  
				di += dx_x2;
			}
			else
			{  
				di += dx_x2 - dy_x2;
				x0 += dx_sym;
			}
		}
		draw_a = x0-wx;
		if(draw_a<0) draw_a = 0;
		draw_b = x0+wy;
		GUI_HLine(draw_a, y0, draw_b, color);
	} 
  
}

//***************************************************************************
//画矩形函数
//参数: x0:矩形左上角的x坐标值
//       y0:矩形左上角的y坐标值
//       x1:矩形右下角的x坐标值
//       y1:矩形右下角的y坐标值
//       color=1,填充黑色1;color=0,填充0;
//****************************************************************************
void GUI_Rectangle(unsigned char x0, unsigned char y0, unsigned char x1, unsigned char y1, unsigned char color)
{  
	GUI_HLine(x0, x1, y0, color);
	GUI_RLine(x0, y0, y1, color);
	GUI_RLine(x1, y0, y1, color);
	GUI_HLine(x0, x1, y1, color);
}

//***************************************************************************
//填充矩形函数
//参数: x0:矩形左上角的x坐标值
//       y0:矩形左上角的y坐标值
//       x1:矩形右下角的x坐标值
//       y1:矩形右下角的y坐标值
//       color=1,填充1;color=0,填充0;
//****************************************************************************
void GUI_Rectangle_Fill(unsigned char x0, unsigned char y0, unsigned char x1, unsigned char y1, unsigned char color)
{  
	unsigned char  i;

	//先找出矩形左上角与右下角的两个点,保存在(x0,y0),(x1,y1)
	if(x0>x1) 						// 若x0>x1,则x0与x1交换
	{ 
		i = x0;
		x0 = x1;
		x1 = i;
	}
	if(y0>y1)						// 若y0>y1,则y0与y1交换
	{  
		i = y0;
		y0 = y1;
		y1 = i;
	}
   
	//判断是否只是直线
	if(y0==y1) 
	{  
		GUI_HLine(x0,x1,y0,color);
		return;
	}
	if(x0==x1) 
	{  
		GUI_RLine(x0,y0,y1,color);
		return;
	}

	while(y0<=y1)						
	{  
		GUI_HLine(x0,x1,y0,color);		// 当前画水平线
		y0++;							// 下一行
	}
}

//***************************************************************************
//画正方形函数
//参数:x0:正方形左上角的x坐标值
//      y0:正方形左上角的y坐标值
//      with:正方形的边长
//      color=1,填充1;color=0,填充0;
//说明:正方形即是长宽相等的特殊矩形
//****************************************************************************
void GUI_Square(unsigned char x0, unsigned char y0, unsigned char with, unsigned char  color)
{   
	if(with==0) return;
	if((x0+with)>127) return;
	if((y0+with)>63) return;
	GUI_Rectangle(x0, y0, x0+with, y0+with, color);
}

//***************************************************************************
//画正方形并填充
//参数:x0:正方形左上角的x坐标值
//      y0:正方形左上角的y坐标值
//      with:正方形的边长
//      color=1,填充黑色(1);color=0,填充白色(0)
//****************************************************************************
void GUI_Square_Fill(unsigned char x0, unsigned char y0, unsigned char with, unsigned char color)
{   
	if(with==0) return;
	if( (x0+with) > 127 ) return;
	if( (y0+with) > 163) return;
	GUI_Rectangle_Fill(x0, y0, x0+with, y0+with, color);
}


//********************************************************
//画圆函数
//参数:color=1,填充1;color=0,填充0;
//      x0,y0为圆心坐标,r为圆的半径;
//********************************************************
void GUI_Circle(unsigned char x0,unsigned char y0,unsigned char r,unsigned char color)
{
	char a,b;
	char di;
	if(r>31 ||r==0)	return;				//参数过滤,次液晶显示的最大圆半径为31
	a=0;
	b=r;
	di=3-2*r;							//判断下个点位置的标志
	while(a<=b)
	{
		GUI_Point(x0-b,y0-a,color);		//3           
		GUI_Point(x0+b,y0-a,color);		//0           
		GUI_Point(x0-a,y0+b,color);		//1       
		GUI_Point(x0-b,y0-a,color);		//7           
		GUI_Point(x0-a,y0-b,color);		//2             
		GUI_Point(x0+b,y0+a,color);		//4               
		GUI_Point(x0+a,y0-b,color);		//5
		GUI_Point(x0+a,y0+b,color);		//6 
		GUI_Point(x0-b,y0+a,color);             
		a++;
		/***使用Bresenham算法画圆**/     
		if(di<0)
			di +=4*a+6;
		else
		{
			di +=10+4*(a-b);   
			b--;
		} 
		GUI_Point(x0+a,y0+b,color);
	}
}

//***************************************************************************
//画正椭圆函数
//说明:给定椭圆的四个点的参数,最左、最右点的x轴坐标值为x0、x1,最上、最下点
//      的y轴坐标为y0、y1.
//说明:显示效果不好
//***************************************************************************
void GUI_Ellipse(char x0, char x1, char y0, char y1, char color)
{  
	char  draw_x0, draw_y0;			// 刽图点坐标变量
	char  draw_x1, draw_y1;
	char  draw_x2, draw_y2;
	char  draw_x3, draw_y3;
	char  xx, yy;					// 画图控制变量
    
	char  center_x, center_y;		// 椭圆中心点坐标变量
	char  radius_x, radius_y;		// 椭圆的半径,x轴半径和y轴半径
	int  radius_xx, radius_yy;		// 半径乘平方值
	int  radius_xx2, radius_yy2;	// 半径乘平方值的两倍
	char  di;						// 定义决策变量
	
   /* 参数过滤 */
   if( (x0==x1) || (y0==y1) ) return;
   	
   /* 计算出椭圆中心点坐标 */
   center_x = (x0 + x1) >> 1;			
   center_y = (y0 + y1) >> 1;
   
   /* 计算出椭圆的半径,x轴半径和y轴半径 */
   if(x0 > x1)
   {  radius_x = (x0 - x1) >> 1;
   }
   else
   {  radius_x = (x1 - x0) >> 1;
   }
   if(y0 > y1)
   {  radius_y = (y0 - y1) >> 1;
   }
   else
   {  radius_y = (y1 - y0) >> 1;
   }
		
   /* 计算半径平方值 */
   radius_xx = radius_x * radius_x;
   radius_yy = radius_y * radius_y;
	
   /* 计算半径平方值乘2值 */
   radius_xx2 = radius_xx<<1;
   radius_yy2 = radius_yy<<1;
	
   /* 初始化画图变量 */
   xx = 0;
   yy = radius_y;
  
   di = radius_yy2 + radius_xx - radius_xx2*radius_y ;	// 初始化决策变量 
	
   /* 计算出椭圆y轴上的两个端点坐标,作为作图起点 */
   draw_x0 = draw_x1 = draw_x2 = draw_x3 = center_x;
   draw_y0 = draw_y1 = center_y + radius_y;
   draw_y2 = draw_y3 = center_y - radius_y;
  
	 
   GUI_Point(draw_x0, draw_y0, color);					// 画y轴上的两个端点 
   GUI_Point(draw_x2, draw_y2, color);
	
   while( (radius_yy*xx) < (radius_xx*yy) ) 
   {  if(di<0)
	  {  di+= radius_yy2*(2*xx+3);
	  }
	  else
	  {  di += radius_yy2*(2*xx+3) + 4*radius_xx - 4*radius_xx*yy;
	 	  
	     yy--;
		 draw_y0--;
		 draw_y1--;
		 draw_y2++;
		 draw_y3++;				 
	  }
	  
	  xx ++;						// x轴加1
	 		
	  draw_x0++;
	  draw_x1--;
	  draw_x2++;
	  draw_x3--;
		
	  GUI_Point(draw_x0, draw_y0, color);
	  GUI_Point(draw_x1, draw_y1, color);
	  GUI_Point(draw_x2, draw_y2, color);
	  GUI_Point(draw_x3, draw_y3, color);
   }
  
   di = radius_xx2*(yy-1)*(yy-1) + radius_yy2*xx*xx + radius_yy + radius_yy2*xx - radius_xx2*radius_yy;
   while(yy>=0) 
   {  if(di<0)
	  {  di+= radius_xx2*3 + 4*radius_yy*xx + 4*radius_yy - 2*radius_xx2*yy;
	 	  
	     xx ++;						// x轴加1	 		
	     draw_x0++;
	     draw_x1--;
	     draw_x2++;
	     draw_x3--;  
	  }
	  else
	  {  di += radius_xx2*3 - 2*radius_xx2*yy;	 	 		     			 
	  }
	  
	  yy--;
 	  draw_y0--;
	  draw_y1--;
	  draw_y2++;
	  draw_y3++;	
		
	  GUI_Point(draw_x0, draw_y0, color);
	  GUI_Point(draw_x1, draw_y1, color);
	  GUI_Point(draw_x2, draw_y2, color);
	  GUI_Point(draw_x3, draw_y3, color);
   }     
}


//********************************************************
//画满屏图片
//参数:dat为填充的数据
//********************************************************
void GUI_Draw_Full_Picture (unsigned char *dat)
{ 
	unsigned char i;                 
	unsigned char j; 
	unsigned char k; 
	unsigned char bGDRAMAddrX = 0x80;		//GDRAM水平地址 
	unsigned char bGDRAMAddrY = 0x80;		//GDRAM垂直地址 
	for(i = 0; i < 2; i++)					                                                                                         
	{ 
		for(j = 0; j < 32; j++)                                                                 
		{ 
			for(k = 0; k < 8; k++)                                                         
			{ 
				LcdWcom(0x34);				//设置为8位MPU接口,扩充指令集
				LcdWcom(bGDRAMAddrY+j);		//垂直地址Y                                                                         
				LcdWcom(bGDRAMAddrX+k);		//水平地址X 
				LcdWdata(*dat++);
				LcdWdata(*dat++);
			} 
		} 
		bGDRAMAddrX = 0x88;					//写下半屏幕
	} 
	LcdWcom(0x36);							//打开绘图模式
	LcdWcom(0x30);							//恢复基本指令集,关闭绘图模式   
} 


unsigned char code  DCB2HEX_TAB[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
//输出一行数据
//参数:flag反显标志,1为反显
unsigned char GUI_LoadLine(unsigned char x,unsigned char y,unsigned char *dat,unsigned char no,unsigned char flag)
{  
	unsigned char bit_dat;
	unsigned char i;

	/* 参数过滤 */
	if(x>127) return(0);
	if(y>63) return(0);
   
	for(i=0; i<no; i++)
	{  
		/* 判断是否要读取点阵数据 */
		if( (i%8)==0 ) bit_dat = *dat++;
     
		/* 设置相应的点为1或为0 */
		if( (bit_dat&DCB2HEX_TAB[i&0x07])==0 ) 
		{
			if(flag==0)				//是否反显?	
				GUI_Point(x,y,0); 	//正常显示
			else
				GUI_Point(x,y,1); 	//反显
		}
		else  
		{
			if(flag==0)
				GUI_Point(x,y,1); 
			else
				GUI_Point(x,y,0); 
		}  		     
     
		if( (++x)>127) return(0);
   }
   
   return(1);
}

//***************************************************************************
//显示自定义大小的区域
//参数说明: x		指定显示位置,x坐标
//           y		指定显示位置,y坐标
//          dat		要输出显示的汉字点阵数据。
//          hno		要显示此行的点个数
//          lno		要显示此列的点个数
//          flag反显标志,1为反显
//****************************************************************************
void  GUI_Put_Area(unsigned char x,unsigned char y,unsigned char *dat,unsigned char hno,unsigned char lno,unsigned char flag)
{  
	unsigned char i;

	for(i=0;i<lno;i++)
	{  
		GUI_LoadLine(x,y,dat,hno,flag);						// 输出一行数据
		y++;												// 显示下一行
		dat += (hno>>3);									// 计算下一行的数据
		if((hno&0x07)!=0) 
			dat++;
	}
}



  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值