/*******************************************************************************************************/ //程序说明:本程序为12864(st7920)驱动程序,只实现了最简单的显示功能 /*******************************************************************************************************/ #include<reg52.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 = P3^5; sbit LCD_RW = P3^6; sbit LCD_EN = P3^4; sbit wela = P2^6; sbit dula = P2^7; //************变量定义 //****************短延时 void delay(uint k) { uint i; uchar j; for(i = 0; i < k ;i ++) for(j = 0; j < 10 ;j ++); } //***********12864写指令函数 void write_com(uchar cmd) { LCD_RS = 0; LCD_RW = 0; LCD_EN = 0; P0 = cmd; delay(5); LCD_EN = 1; delay(5); LCD_EN = 0; } //********12864写数据函数 void write_dat(uchar dat) { LCD_RS = 1; LCD_RW = 0; LCD_EN = 0; P0 = dat; delay(5); LCD_EN = 1; delay(5); LCD_EN = 0; } //****************从LCD中读数据 uchar read_dat(void) { uchar temp; P0 = 0XFF; //释放数据线 LCD_RS = 1; //数据 LCD_RW = 1; //读模式 LCD_EN = 1; //为高电平进行读数据或指令 delay(1); temp = P0; 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]!=' ') { 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 > y1) { bak = y1; y1 = y0; y0 = bak; } do { lcd_set_dot(x , y0);//从上到下逐点显示 y0 ++; } while(y1 >= y0); } //*********任意两点间画直线*********************************// //x0、y0为起始点坐标,x1、y1为终点坐标**********************// //**********************************************************// void gui_line(uchar x0 , uchar y0 , uchar x1 , uchar y1) { 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);//画垂直线 return; } if(y0 == y1)//判断是否为水平线 { gui_hline(x0 , x1 , y0);//画水平线 return; } dx = x1 - x0;//求取两点之间的差值 dy = y1 - y0; //****判断增长方向,或是否为水平线、垂直线、点*// if(dx > 0)//判断x轴方向 dx_sym = 1; else { if(dx < 0) dx_sym = -1; else { gui_rline(x0 , y0 , y1); return; } } if(dy > 0)//判断y轴方向 dy_sym = 1; else { if(dy < 0) dy_sym = -1; else { gui_hline(x0 , x1 , y0); return; } } /*将dx、dy取绝对值***********/ dx = dx_sym * dx; dy = dy_sym * dy; /****计算2倍的dx、dy值*******/ dx_x2 = dx * 1;//我改为了一倍,这样才跟真实的两点对应 dy_x2 = dy * 1; /***使用bresenham法进行画直线***/ if(dx >= dy)//对于dx>=dy,使用x轴为基准 { di = dy_x2 - dx; while(x0 != x1) { lcd_set_dot(x0,y0); x0 +=dx_sym; if(di < 0) di += dy_x2;//计算出下一步的决策值 else { di += dy_x2 - dx_x2; y0 += dy_sym; } } lcd_set_dot(x0, y0);//显示最后一点 } else //对于dx<dy使用y轴为基准 { di = dx_x2 - dy; while(y0 != y1) { lcd_set_dot(x0, y0); y0 += dy_sym; if(di < 0) di += dx_x2; else { di += dx_x2 - dy_x2; x0 += dx_sym; } } lcd_set_dot(x0, y0);//显示最后一点 } } //***************************************************************************// //*******************画指定宽度的任意两点之间的直线**************************// //参数说明:x0、y0为起始点坐标,x1、y1为终点坐标,with为线宽*****************// //***************************************************************************// void gui_linewith(uchar x0 , uchar y0 , uchar x1 , uchar y1 , uchar with) { 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); 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, x1, y1); 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); 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); } 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); 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); } } //***********画矩形函数*************************************// //x0、y0为矩形左上角坐标值,x1、y1为矩形右下角坐标值********// //**********************************************************// void gui_rectangle(uchar x0 , uchar y0 , uchar x1 , uchar y1) { gui_hline(x0 , x1 , y0); gui_rline(x0 , y0 , y1); gui_rline(x1 , y0 , y1); gui_hline(x0 , x1 , y1); } //****************画填充矩形函数****************************// //x0、y0为矩形左上角坐标值,x1、y1为矩形右下角坐标值********// //**********************************************************// /*void gui_rectangle_fill(uchar x0 , uchar y0 , uchar x1 , uchar y1) { uchar i;//转换数据的中间变量,使x1、y1大 if(x0 > x1) { i = x0; x0 = x1; x1 = i; } if(y0 > y1) { i = y0; y0 = y1; y1 = i; } //***判断是否是直线***/ /* if(y0 == y1)//画水平线 { gui_hline(x0 , x1 , y0); return; } if(x0 == x1)//画竖直线 { gui_rline(x0 , y0 , y1); return; } while(y0 <= y1)//画填充矩形 { gui_hline(x0 , x1 , y0); y0 ++; } } */ //*******************画正方形函数*************************// //x0、y0为正方形左上角坐标,with正方形边长****************// //********************************************************// /*void gui_square(uchar x0 , uchar y0 , uchar with) { if(with == 0) return; if((x0 + with) > 127)//横轴超出液晶边界 return; if((y0 + with) > 63) return; gui_rectangle(x0 , y0 , x0 + with , y0 + with); } */ //****************画填充正方形函数*************************// //x0、y0为正方形左上角坐标,with正方形边长*****************// //*********************************************************// /*void gui_square_fill(uchar x0 , uchar y0 , uchar with) { if(with == 0) return; if((x0 + with) > 127)//横轴超出液晶边界 return; if((y0 + with) > 63) return; gui_rectangle_fill(x0 , y0 , x0 + with , y0 + with); } */ //****************画圆函数*********************************// //x0、y0为圆心坐标,r为圆的半径****************************// //*********************************************************// void gui_circle(uchar x0 , uchar y0 , uchar r) { char a , b; char di; if(r > 31 || r == 0)//圆大于液晶屏或者没半径则返回 return; a = 0; b = r; di = 3 - 2 * r;//判断下个点位置的标志 while(a <= b) { lcd_set_dot( x0 - b , y0 - a);//3 lcd_set_dot( x0 + b , y0 - a); //0 lcd_set_dot( x0 - a , y0 + b); //1 lcd_set_dot( x0 - b , y0 - a); //7 lcd_set_dot( x0 - a , y0 - b); //2 lcd_set_dot( x0 + b , y0 + a); //4 lcd_set_dot( x0 + a , y0 - b); //5 lcd_set_dot( x0 + a , y0 + b); //6 lcd_set_dot( x0 - b , y0 + a); a ++; //***使用bresenham算法画圆********/ if(di < 0) di += 4 * a + 6; else { di += 10 + 4 * (a - b); b --; } lcd_set_dot( x0 + a , y0 + b); } } //***************************************************************************// //***************************画正椭圆函数************************************// //说明:给定椭圆的四个点的参数,最左、最右点的x轴坐标值为x0、x1,最上、最下点 // 的y轴坐标为y0、y1. //说明:----------------------------显示效果不好 //***************************************************************************// void gui_ellipse(char x0, char x1, char y0, char y1) { 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; lcd_set_dot(draw_x0, draw_y0); // 画y轴上的两个端点 lcd_set_dot(draw_x2, draw_y2); 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--; lcd_set_dot(draw_x0, draw_y0); lcd_set_dot(draw_x1, draw_y1); lcd_set_dot(draw_x2, draw_y2); lcd_set_dot(draw_x3, draw_y3); } 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++; lcd_set_dot(draw_x0, draw_y0); lcd_set_dot(draw_x1, draw_y1); lcd_set_dot(draw_x2, draw_y2); lcd_set_dot(draw_x3, draw_y3); } } //******************************************************************* //*******画满屏图片-----本程序为逐行写,因此图片数据也应该是逐行取的 //参数: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++) { write_com(0x34); //设置为8位MPU接口,扩充指令集,关闭绘图显示 write_com(bGDRAMAddrY+j); //垂直地址Y write_com(bGDRAMAddrX+k); //水平地址X write_dat(*dat++); //写数据高字节 write_dat(*dat++); //写数据低字节 } } bGDRAMAddrX = 0x88; //写下半屏幕 } write_com(0x36); //打开绘图模式 write_com(0x30); //恢复基本指令集,关闭绘图模式 } unsigned char code DCB2HEX_TAB[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}; //****************************输出一行数据函数,此行可任意长,不必非得是8的倍数**和下个函数合用画任意大小(矩形)的图形或汉字 //参数:flag反显标志,1为反显 ,x、y为指定显示位置的起始点,*dat要输出的点阵数组,no显示此行所需的点个数,即图形一行的点数 void 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; if(y>63) return; for(i=0; i<no; i++)//超出本行所规定的点数则本行显示完成 { /* 判断是否要读取点阵数据,每字节的开始读取一次点阵数组即i为8的倍数时 */ if( (i%8)==0 ) bit_dat = *dat++; /* 对相应的点打1或打0, i&0x07意思是对8求余*/ if( (bit_dat&DCB2HEX_TAB[i&0x07])==0 )//取出i对应的位,并判断是否为0 { if(flag==0) //判断是否反显,该位取出的数据为0,反显要打为1,flag==0代表不反显 GUI_Point(x,y,0); //正常显示0,GUI_Point(x,y,0)代表在x、y处打0 else GUI_Point(x,y,1); //将0反显 } else { if(flag==0) GUI_Point(x,y,1); else GUI_Point(x,y,0); } if( (++x)>127) return;//若显示超出了液晶屏则返回 } } //*************************************************************************** //*****************在自定义大小的区域内画图或画字函数**************************** //参数说明: x、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); //比如说上一行打了2字节,此处的意思是使数据向后推进2字节,(hno>>3)意思是算出上一行有几个字节数据 if((hno&0x07)!=0) //hno&0x07意思是对8求余,因一行不满整字节时,上一句的意思就是算出上一行的整字节数,但实际上在取模时不满一个 dat++; //字节也按一个字节取,所以上一句少计算了一个字节,这里加上 } } //*********************************************************************************以上为GDRAM绘图部分************************************************************************// //**********************************************************************************以下为CGRAM自定义字库部分******************************************************************// //******************************************************** //设置CGRAM字库 //ST7920 CGRAM(用户自定义图标)空间分布 //空间1地址:40H~4FH共16个地址,一个地址对应两个字节数据;对应调用码:0000H //空间2地址:50H~5FH共16个地址,一个地址对应两个字节数据;对应调用码:0002H //空间3地址:60H~6FH共16个地址,一个地址对应两个字节数据;对应调用码:0004H //空间4地址:70H~7FH共16个地址,一个地址对应两个字节数据;对应调用码:0006H //参数说明:num为空间编号,取1、2、3、4,CGRAM_ZIKU为地址指针 void SET_CGRAM(unsigned char num,unsigned char *CGRAM_ZIKU) { unsigned char i,add; write_com(0x34); //再次设置为8位并行口,扩展指令集 write_com(0x02); //SR=0,允许设置CGRAM地址 write_com(0x30); //恢复设置为8位并行口,基本指令集 add=(num<<4)|0x40; //计算CGRAM的首地址 for(i=0;i<16;i++) { write_com(add+i); //设置CGRAM的首地址 write_dat(CGRAM_ZIKU[i*2]); //写入高8位数据 write_dat(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); //设置显示的起始地址 write_dat(0x00); //写入需要显示汉字的高八位数据 write_dat(num*2); //写入需要显示字符的低八位数据 } uchar code CGRAM_ZIKU[] = {0X03,0X80,0X00,0X80,0XF8,0X8E,0X23,0X91,0X22,0X21,0X22,0X20,0X23,0XA0,0X20,0X20, 0X20,0X20,0X20,0X20,0X20,0X20,0X20,0X21,0X20,0X11,0XF8,0X0E,0X00,0X00,0X00,0X00};//I2C //**************设置CGRAM字库并显示函数 void set_and_display() { SET_CGRAM( 1,CGRAM_ZIKU);//把自定义字库写入CGRAM,且写入空间地址1 display_CGRAM(0 , 1 , 1);//在指定的位置显示空间地址1中自定义的字符 } //***************************************************************************以上为自定义字库部分**************************************************************// //****************12864初始化函数 void lcd_init() { write_com(0x30);//基本指令操作,8位并口 delay(1); write_com(0x06);//设置为游标右移,DDRAM地址加一,画面不动 delay(1); write_com(0x0c);//显示开,关光标 delay(1); write_com(0x01);//清除lcd显示内容 delay(1); } //*****************************主函数 void main() { wela=0; dula=0; delay(1); lcd_init();//12864初始化函数 gui_clear();//画图时清屏函数 delay(10); set_and_display();//显示自定义字库 gui_circle( 86 , 32 , 30); //画圆 gui_linewith( 5 , 5 , 120 , 60 , 3);//画指定线宽直线 gui_ellipse(10 , 120 , 5 , 60);//画正椭圆 while(1); }