一、首先说一下关于驱动函数的书写,这些是液晶显示的基础
1、写操作的编写:
首先看一下时序图
![关于12864的使用(转载来自阿莫电子论坛) 关于12864的使用(转载来自阿莫电子论坛)](https://i-blog.csdnimg.cn/blog_migrate/a38e01189bb86b43cd58615a44f1a76c.jpeg)
由图可见操作很简单:
1>RS=1(写数据操作);或者RS=0(写命令操作);
2>RW=0;//指明为写操作
3>E=1;
4>DB=data;//data为你要写入的命令或数据值
5>E=0;
以下是我的驱动函数,仅供参考:
#define
sbit
sbit
sbit
sbit
sbit
/
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的使用(转载来自阿莫电子论坛) 关于12864的使用(转载来自阿莫电子论坛)](https://i-blog.csdnimg.cn/blog_migrate/5f08eab37dc54c8ca2d9be09bcb2224a.jpeg)
扩展程序:
/
Display_HZ_Line(2,0,"欢迎转载,转载请注明出处,谢谢!");//显示一行汉字
效果图:
![关于12864的使用(转载来自阿莫电子论坛) 关于12864的使用(转载来自阿莫电子论坛)](https://i-blog.csdnimg.cn/blog_migrate/5baf1d7c041d50cc46afe04a21cbf616.jpeg)
再来一个整体的现实效果
/
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的使用(转载来自阿莫电子论坛) 关于12864的使用(转载来自阿莫电子论坛)](https://i-blog.csdnimg.cn/blog_migrate/07356010e1abfc29d443d3775776f027.jpeg)
-
照片002.jpg(126.03 KB, 下载次数: 1)
四、关于CGRAM的使用:
可以参考这个网站的程序: http://bbs.友好站点,请勿转贴.com/ShowTopic.aspx?id=81220ST7920自行产生RAM提供使用者图像定义(造字)功能,可以提供四组16*16点的自定义图像空间,使用者可以将内部自行没有提供的图像自行定义到CGRAM中,便可以通过DDRAM显示在液晶屏上。注意:网上介绍说ST7920芯片同屏幕不能显示4个以上自定义汉字(用CGRAM)。显示CGRAM字型:将16位元资料写入DDRAM中,一共有0000H,0002H,0004H,0006H四种编码。
操作步骤:
1>
2>
3>
4>
5>
6>
五、关于GDRAM绘图模式的操作
操作步骤:
1>设置为扩充指令集,关闭绘图模式;
2>写两字节的GDRAM地址,先写垂直地址,后写水平地址地址;
3>写入两字节的数据,先写高八位数据,后写低八位数据;
4>打开绘图模式;
5>设置回基本指令集;
![关于12864的使用(转载来自阿莫电子论坛) 关于12864的使用(转载来自阿莫电子论坛)](https://i-blog.csdnimg.cn/blog_migrate/de48183266f7e6fb23aac460a6c50042.jpeg)
应用实例:
GUI_Fill_GDRAM(0xcc);
实物图:
![关于12864的使用(转载来自阿莫电子论坛) 关于12864的使用(转载来自阿莫电子论坛)](https://i-blog.csdnimg.cn/blog_migrate/f2fa61a1291b298f7489242a08930c4f.jpeg)
1、打点
打点操作是作图的基础,众所周知,画任何图形均可以由画一个个点来实现。
具体打点的操作步骤:
1>确定打点的位置;
2>读出该点所在的数据值;
3>修改该点相应的位的值,对于单色液晶来说,只有两种操作,已是点亮该点,二是熄灭该点;
4>将修改后的数据值写入对应的地址;
由于打点首先需要进行读操作,因此需要编写读数据的驱动函数:
![关于12864的使用(转载来自阿莫电子论坛) 关于12864的使用(转载来自阿莫电子论坛)](https://i-blog.csdnimg.cn/blog_migrate/262c6d77d5fe1f2fde9a6c57447b51ec.jpeg)
操作如下:
1>释放总线:DB=0;
2>RS=1(读数据操作);或者RS=0(读状态操作);
3>RW=1;//指明为读操作
4>E=1;
5>data=DB;//data为存储读回数据的变量
6>E=0;
读操作参考程序:
打点参考程序:
![关于12864的使用(转载来自阿莫电子论坛) 关于12864的使用(转载来自阿莫电子论坛)](https://i-blog.csdnimg.cn/blog_migrate/80b2849fe02744769d9b3b5eef879a53.jpeg)
![关于12864的使用(转载来自阿莫电子论坛) 关于12864的使用(转载来自阿莫电子论坛)](https://i-blog.csdnimg.cn/blog_migrate/97e6f5f9e0d25617f2039231ea692d41.jpeg)
应用实例:
GUI_Point(64,32,1);
![关于12864的使用(转载来自阿莫电子论坛) 关于12864的使用(转载来自阿莫电子论坛)](https://i-blog.csdnimg.cn/blog_migrate/e17bd23d7ca3779a6441cf6a56c5f868.jpeg)
![关于12864的使用(转载来自阿莫电子论坛) 关于12864的使用(转载来自阿莫电子论坛)](https://i-blog.csdnimg.cn/blog_migrate/0b9d8edf6eece29e6c4968e830ca08c6.jpeg)
![关于12864的使用(转载来自阿莫电子论坛) 关于12864的使用(转载来自阿莫电子论坛)](https://i-blog.csdnimg.cn/blog_migrate/4a32d5973c0af7b75f9878dbe78f5399.jpeg)
应用例子:
GUI_HLine(10,120,10,1);
GUI_RLine(10,10,60,1);
任意两点画线:
![关于12864的使用(转载来自阿莫电子论坛) 关于12864的使用(转载来自阿莫电子论坛)](https://i-blog.csdnimg.cn/blog_migrate/881ddb1d6cb43b4f5636f84d982728c0.jpeg)
![关于12864的使用(转载来自阿莫电子论坛) 关于12864的使用(转载来自阿莫电子论坛)](https://i-blog.csdnimg.cn/blog_migrate/67e9c2a74fa3a2895d5ddd78f4f19b58.jpeg)
![关于12864的使用(转载来自阿莫电子论坛) 关于12864的使用(转载来自阿莫电子论坛)](https://i-blog.csdnimg.cn/blog_migrate/3d483b37f5cc10e9c6a33a3e1ace3f09.jpeg)
![关于12864的使用(转载来自阿莫电子论坛) 关于12864的使用(转载来自阿莫电子论坛)](https://i-blog.csdnimg.cn/blog_migrate/696bae4291bbba85a7dc32b4b277cb73.jpeg)
![关于12864的使用(转载来自阿莫电子论坛) 关于12864的使用(转载来自阿莫电子论坛)](https://i-blog.csdnimg.cn/blog_migrate/d9b40498ad7bd316b801d4d32bbcda57.jpeg)
应用例子:
GUI_Line(0,0,127,63,1);
![关于12864的使用(转载来自阿莫电子论坛) 关于12864的使用(转载来自阿莫电子论坛)](https://i-blog.csdnimg.cn/blog_migrate/95494e082b941a8ead4c265b59acfa21.jpeg)
画矩形:
![]() 应用例子: GUI_Rectangle(5,5,122,58,1); ![]() |
填充矩形:
![]() |
![关于12864的使用(转载来自阿莫电子论坛) 关于12864的使用(转载来自阿莫电子论坛)](https://i-blog.csdnimg.cn/blog_migrate/cc692fd694c62aebf46616903ffebd0b.jpeg)
应用例子:
GUI_Rectangle_Fill(5,5,122,58,1);
![关于12864的使用(转载来自阿莫电子论坛) 关于12864的使用(转载来自阿莫电子论坛)](https://i-blog.csdnimg.cn/blog_migrate/2a0533f5a528f456945baea5689dac54.jpeg)
画正方形和填充正方形:
![]() ![]() 应用例子: GUI_Square(10,10,50,1); ![]() 再来个画圆的程序: ![]() 应用例子: GUI_Circle(32,32,30,1); ![]() |
-
照片015.jpg(108.2 KB, 下载次数: 2)
-
12.jpg(49.36 KB, 下载次数: 0)
-
11.jpg(169.08 KB, 下载次数: 0)
-
12(1).jpg(49.36 KB, 下载次数: 0)
//***********************************************************************************************
//说明:带字库的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++;
}
}