/**********************************************************************************************************************************************************************/
//程序说明:本程序为12864(st7920)驱动程序,只实现了最简单的显示功能
//端口设置:RS、RW、EN分别为P0口的0、1、2,数据口为P2口
用取模软件取的图形或汉字必须是逐行取的,因为本函数是在液晶上逐行打点的
/*********************************************************************************************************************************************************************/
#include<reg51.h>
#include<intrins.h> //内含-NOP-函数
#include<stdlib.h> //内含rand()函数
#define uchar unsigned char
#define uint unsigned int
//**********宏定义所需指令
#define BASIC_SET 0x30
#define EXTEND_SET 0x34
#define DRAW_ON 0x36
#define DRAW_OFF 0x34
//*************端口定义
sbit LCD_RS = P0^0;
sbit LCD_RW = P0^1;
sbit LCD_EN = P0^2;
//************变量定义
//uchar dis1[10];
//****************短延时
void delay(uint k)
{
uint i;
uchar j;
for(i = 0; i < k ;i ++)
for(j = 0; j < 10 ;j ++);
}
//***********ms级延时函数
/*void delay_1ms(uint x)
{
uint i,j;
for(j = 0;j < x; j++)
for(i = 0;i < 110; i++);
} */
//***********12864写指令函数
void write_com(uchar cmd)
{
LCD_RS = 0;
LCD_RW = 0;
P2 = cmd;
delay(5);
LCD_EN = 1;
delay(5);
LCD_EN = 0;
}
//********12864写数据函数
void write_dat(uchar dat)
{
LCD_RS = 1;
LCD_RW = 0;
P2 = dat;
delay(5);
LCD_EN = 1;
delay(5);
LCD_EN = 0;
}
//****************从LCD中读数据
uchar read_dat(void)
{
uchar temp;
P2 = 0XFF; //释放数据线
LCD_RS = 1; //数据
LCD_RW = 1; // 读模式
LCD_EN = 1; //E为高电平进行读数据或指令
delay(1);
temp = P2;
LCD_EN = 0;
return temp;
}
//********************************************************
//设置光标(地址)函数
//参数说明: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; //确定列号
write_com(i);
}
//********************************************************
//显示字符函数
//********************************************************
void display_char(unsigned char Alphabet)
{
write_dat(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')
{
write_dat(Alphabet[i]); //写入需要显示字符的显示码
i++;
}
}
//***************************************************************************以下为GDRAM绘图部分************************************************************************//
//*********************绘图显示的清屏函数(因清屏指令在画图时不能用)------------------------------------------------------------------------------注意!!!!!!!
void gui_clear()
{
uchar i , j , k;
write_com(EXTEND_SET);//扩展指令集,8位数据传输
write_com(DRAW_OFF);//绘图显示关闭
for(i = 0; i < 2; i ++)//分上下两屏写
{
for(j = 0; j < 32; j ++)
{
write_com(0x80 + j);//写y坐标
delay(1);
if(i == 0) //写x坐标
{
write_com(0x80);
delay(1);
}
else //写下半屏
{
write_com(0x88);
delay(1);
}
for(k = 0; k < 16; k ++)//写一整行数据
{
write_dat(0x00);//写高字节
write_dat(0x00);//写低字节
delay(1);
}
}
}
write_com(DRAW_ON);//打开绘图显示
write_com(BASIC_SET);//打开基本指令集
}
//*************************************************************************************************
//***************有反白显示功能的打点函数**********************************************************
//参数: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;
write_com(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当中的哪一行
write_com(0x80+y_byte); //设定行地址(y坐标),即是垂直地址
write_com(0x80+x_Dyte+8*y_Dyte); //设定列地址(x坐标),并通过8*y_Dyte选定上下屏,即是水平地址
read_dat(); //预读取数据
GDRAM_hbit= read_dat(); //读取当前显示高8位数据
GDRAM_lbit= read_dat(); //读取当前显示低8位数据
delay(1);
write_com(0x80+y_byte); //设定行地址(y坐标)
write_com(0x80+x_Dyte+8*y_Dyte); //设定列地址(x坐标),并通过8*y_Dyte选定上下屏
delay(1);
if(x_byte<8) //判断其在高8位,还是在低8位
{
if(color==1)
{
write_dat(GDRAM_hbit|(0x01<<(7-x_byte))); //置位GDRAM区高8位数据中相应的点
}
else
write_dat(GDRAM_hbit&(~(0x01<<(7-x_byte)))); //清除GDRAM区高8位数据中相应的点
write_dat(GDRAM_lbit); //显示GDRAM区低8位数据
}
else
{
write_dat(GDRAM_hbit);
if(color==1)
write_dat(GDRAM_lbit|(0x01<<(15-x_byte))); //置位GDRAM区高8位数据中相应的点
else
write_dat(GDRAM_lbit&(~(0x01<<(15-x_byte))));//清除GDRAM区高8位数据中相应的点
}
write_com(0x30); //恢复到基本指令集
}
//***********(给定坐标并打点的)任意位置打点函数
void lcd_set_dot(uchar x,uchar y)
{
uchar x_byte,x_bit;//确定在坐标的那一字节哪一位
uchar y_ping , y_bit;//确定在坐标的哪一屏哪一行
uchar tmph , tmpl;//定义两个临时变量,用于存放读出来的数据
write_com(EXTEND_SET);//扩展指令集
write_com(DRAW_OFF);//绘图显示关闭
x_byte = x / 16;//算出在哪一字节,注意一个地址是16位的
x_bit = x % 16;//& 0x0f;//算出在哪一位
y_ping = y / 32;//确定在上半屏还是下半屏,0代表上半屏,1代表下半屏
y_bit = y % 32;//& 0x1f;//确定在第几行
write_com(0X80 + y_bit);//先写垂直地址(最高位必须)
write_com(0x80 + x_byte + 8 * y_ping);//水平坐标,下半屏坐标起始地址为0x88,(+8*y_ping)就是用来确定上半屏还是下半屏
read_dat();//预读取数据
tmph = read_dat();//读取当前显示高8位数据
tmpl = read_dat();//读取当前显示低8位数据
delay(1);
write_com(0x80 + y_bit);//读操作会改变AC,所以重新设置一下
write_com(0x80 + x_byte + 8 * y_ping);
delay(1);
if(x_bit < 8)
{
write_dat(tmph | (0x01 << (7 - x_bit)));//写高字节,因为坐标是从左向右的,GDRAM高位在左,低位在右
write_dat(tmpl);//原低位数据送回
}
else
{
write_dat(tmph);//原高位数据送回
write_dat(tmpl | (0x01 << (15 - x_bit)));
}
write_com(DRAW_ON); //打开绘图显示
write_com(BASIC_SET);//回到基本指令集
}
//************画水平线函数**********************************//
//x0、x1为起始点和终点的水平坐标,y为垂直坐标***************//
//**********************************************************//
void gui_hline(uchar x0, uchar x1, uchar y)
{
uchar bak;//用于对两个数互换的中间变量,使x1为大值
if(x0 > x1)
{
bak = x1;
x1 = x0;
x0 = bak;
}
do
{
lcd_set_dot(x0 , y);//从左到右逐点显示
x0 ++;
}while(x1 >= x0);
}
//***********画竖直线函数***********************************//
//x为起始点和终点的水平坐标,y0、y1为垂直坐标***************//
//**********************************************************//
void gui_rline(uchar x, uchar y0, uchar y1)
{
uchar bak;//用于对两个数互换的中间变量,使y1为大值
if(y0