• 12864 显示多种图形


    /*******************************************************************************************************/
    //程序说明:本程序为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);
    }

  • 相关阅读:
    Android控件Editext、TextView属性详解
    修改Android签名证书keystore的密码、别名alias以及别名密码
    android 中如何限制 EditText 最大输入字符数
    keytool 错误 java.io.IOException: incorrect AVA format
    Android打包常见错误之Export aborted because fatal lint errors were found
    正则表达式之判断用户注册信息是否为汉字、字母和数字
    Android Dialog 系统样式讲解及透明背景
    Android中自定义Activity和Dialog的位置大小背景和透明度等
    字体在Android View中的输出 drawText
    怎么用CIFilter给图片加上各种各样的滤镜_1
  • 原文地址:https://www.cnblogs.com/alan666/p/8311959.html
Copyright © 2020-2023  润新知