zoukankan      html  css  js  c++  java
  • STC8A—基于JLX12864的简易图形编辑器

      STC8A小制作:基于JLX12864的简易图形编辑器,本文将介绍JLX12864的驱动程序,以及Bresenham直线算法和画圆算法的实现。

      一、制作背景:

      在学习12864显示屏时,经常会使用取模软件,对于字符,取模软件可以说相当方便;对于图片,如果有合适的图片进行转换,也挺方便的,但是有一种情况,使用取模软件相当不方便,那就是需要自己进行规则图形的绘制时,在电脑上使用大像素点进行绘制没有那么直观,而且操作上也只能一个点一个点的绘制,于是可以制作一个图形编辑器,直接在12864上操作,并像取模软件一样输出字模。

      二、功能:

      1)设置光标的坐标值,并移动到设定值;

      2)绘制点、直线、圆;

      3)绘制和擦除模式;

      4)通过串口将字模数据按照规定格式输出;

      三、驱动程序:

      1)JLX12864的SPI时序;

      程序如下:

    void cog_writebyte(uchar byte,uchar cmd)        //write byte to cog,cmd=0:cmd,cmd=1:data
    {
        uchar i;
        if(cmd)
            COG_RS=1;
        else
            COG_RS=0;
        COG_CS=0;
        for(i=0;i<8;i++)
        {
            COG_SCLK=0;
            if(byte&0x80)
                COG_SDA=1;
            else
                COG_SDA=0;
            _nop_();
            _nop_();
            COG_SCLK=1;
            byte=byte<<1;
        }
        COG_CS=1;
        COG_RS=1;
    }

      2)JLX12864初始化;

        初始化操作实际就是根据显示屏控制芯片手册上的要求,写入一些设置、初始化的指令,这款显示屏的控制芯片是UC1701X,这里不做详细介绍。

    void cog_init()        //init cog
    {
        COG_CS=1;
        COG_RESET=1;
        delay_ms(100);
        COG_RESET=0;
        delay_ms(100);
        COG_RESET=1;        //reset
        
        cog_writebyte(0xe2,COG_CMD);        //soft reset
        delay_ms(5);
        cog_writebyte(0x2c,COG_CMD);        //boost1
        delay_ms(5);
        cog_writebyte(0x2e,COG_CMD);        //boost2
        delay_ms(5);
        cog_writebyte(0x2f,COG_CMD);        //boost3
        delay_ms(5);
        cog_writebyte(0x23,COG_CMD);        //set contrast(0x20~0x27)
        cog_writebyte(0x81,COG_CMD);        //set contrast control register
        cog_writebyte(0x28,COG_CMD);        //(0x00~0x3f)
        cog_writebyte(0xa2,COG_CMD);        //set bias
        cog_writebyte(0xc8,COG_CMD);        //set com/row scan direction    0xc0--normal 0xc8--reverse
        cog_writebyte(0xa0,COG_CMD);        //set seg/column mapping    0xa0--normal 0xa1--reverse
        cog_writebyte(0x40,COG_CMD);        //set start line address(0x40~0x7f)
        cog_writebyte(0xaf,COG_CMD);        //turn on cog panel
    }

      3)设置起始位置;

        这里注意X坐标的范围为0—127,Y坐标的范围为0—7。

    void cog_setposition(uchar x,uchar y)        //set startting position on panel(x : 0~127 , y : 0~7)
    {
        cog_writebyte(0xb0+y,COG_CMD);
        cog_writebyte(x&0x0f,COG_CMD);
        cog_writebyte(((x&0xf0)>>4)|0x10,COG_CMD);
    }

      4)填充屏幕;

        接下来就是对屏幕显示内容的具体操作函数,首先需要说明,通常在使用字库或者字模来进行显示操作时,都是直接将相关的数据写入对应的位置,原来的显示内容就完全被替换掉了,但是当你需要实现打点、画线等操作时,往往不能这样操作,举个例子,假设需要在指定位置的打点,只需要在原来显示数据data的基础上,将对应为置1或置0,如data&0xfe或者data|0x01即可,这就要求我们能够获取原来的显示数据。

        采用并口通讯方式(8080、6800)的显示屏,比较熟悉的如LCD1602和LCD12864,是能够实现内部寄存器读取的,所以只需在操作前先将对应位置的寄存器数据读出,修改,再写入就能实现,而采用串口通讯方式(IIC,SPI)的显示屏,是无法实现读内部寄存器的,这就需要在程序中建一个数组(大小为1024)用来作为显示缓存,于是显示操作就变为修改数组对应位置的数据,将此数据写入寄存器,这个大数组需要可以修改,所以只能定义在RAM中,所以RAM要足够大才行。

        以下是填充屏幕的函数实现。

    void cog_fillpanel(uchar color)        //fill panel with color(also can clear panel when color is 0x00)
    {
        uchar i,j;
        for(i=0;i<8;i++)
        {
            cog_writebyte(0xb0+i,COG_CMD);
            cog_writebyte(0x00,COG_CMD);
            cog_writebyte(0x10,COG_CMD);
            for(j=0;j<128;j++)
            {
                display_cache[i*128+j]=color;
                cog_writebyte(color,COG_DATA);
            }
        }
    }

      5)显示BMP图片;

        图片显示其实和填充屏幕差不多,前者不断写入图片数组中的数据,后者不断写入同一数据。

    void cog_drawbmp(uchar x0,uchar y0,uchar x1,uchar y1,uchar *array)        //draw bmp : start (x0,y0) , end (x1,y1) , (x : 0~127 , y : 0~7)
    {
        uchar x,y;
        for(y=y0;y<=y1;y++)
        {
            cog_setposition(x0,y);
            for(x=x0;x<=x1;x++)
            {
                display_cache[y*128+x]=*array;
                cog_writebyte(*array++,COG_DATA);
            }
        }
    }

      6)打点函数;

        打点是实现画线,画圆的基础,任何形状都是由点构成的。

    void cog_drawpixel(uchar x,uchar y,uchar color)        //draw pixel(x : 0~127 , y : 0~63) , color : 0/1
    {
        uchar y_position,byte;
        y_position=y/8;
        byte=0x01<<(y%8);
        if(color)
        {
            byte=byte|display_cache[y_position*128+x];
        }
        else
        {
            byte=~byte;
            byte=byte&display_cache[y_position*128+x];
        }
        cog_writebyte(0xb0+y_position,COG_CMD);
        cog_writebyte(x&0x0f,COG_CMD);
        cog_writebyte(((x&0xf0)>>4)|0x10,COG_CMD);
        display_cache[y_position*128+x]=byte;
        cog_writebyte(byte,COG_DATA);
    }

      7)画线、画圆函数;

        这里不详细介绍Bresenham直线算法和画圆算法的原理,想了解的可以自行搜索。

    void cog_drawline(uchar x0,uchar x1,uchar y,uchar color)        //draw line(x : 0~127 , y : 0~63) , color : 0/1
    {
        uchar x;
        if(x1>x0)
        {
            for(x=x0;x<=x1;x++)
            {
                cog_drawpixel(x,y,color);
            }
        }
        else
        {
            for(x=x1;x<=x0;x++)
            {
                cog_drawpixel(x,y,color);
            }
        }
    }
    
    void cog_drawcolumn(uchar x,uchar y0,uchar y1,uchar color)        //draw column(x : 0~127 , y : 0~63) , color : 0/1
    {
        uchar y;
        if(y1>y0)
        {
            for(y=y0;y<=y1;y++)
            {
                cog_drawpixel(x,y,color);
            }
        }
        else
        {
            for(y=y1;y<=y0;y++)
            {
                cog_drawpixel(x,y,color);
            }
        }
    }
    
    void cog_drawstraight(uchar x0,uchar y0,uchar x1,uchar y1,uchar color)        //draw straight line(x : 0~127 , y : 0~63) , color : 0/1
    {
        int err=0,x,y,dx,dy;
        int incx,incy;
        if(x1>x0)
            incx=1;
        else if(x1==x0)
            incx=0;
        else
            incx=-1;
        if(y1>y0)
            incy=1;
        else if(y1==y0)
            incy=0;
        else
            incy=-1;
        if(incx==0)
            cog_drawcolumn(x0,y0,y1,color);
        else if(incy==0)
            cog_drawline(x0,x1,y0,color);
        else
        {
            dx=abs((int)x1-(int)x0);
            dy=abs((int)y1-(int)y0);
            if(dx>=dy)
            {
                dx=(int)x1-(int)x0;
                dy=(int)y1-(int)y0;
                dx=dx*incx;
                dy=dy*incy;
                err=0-dx;
                for(x=(int)x0,y=(int)y0;x!=(int)x1+incx;x=x+incx)
                {
                    cog_drawpixel((uchar)x,(uchar)y,color);
                    err=err+2*dy;
                    if(err>0)
                    {
                        y=y+incy;
                        err=err-2*dx;
                    }
                }
            }
            else
            {
                dx=(int)x1-(int)x0;
                dy=(int)y1-(int)y0;
                dx=dx*incx;
                dy=dy*incy;
                err=0-dy;
                for(x=(int)x0,y=(int)y0;y!=(int)y1+incy;y=y+incy)
                {
                    cog_drawpixel((uchar)x,(uchar)y,color);
                    err=err+2*dx;
                    if(err>0)
                    {
                        x=x+incx;
                        err=err-2*dy;
                    }
                }
            }
        }
    }
    
    void cog_drawcircle(uchar x0,uchar y0,uchar r,uchar color)        //draw circle(x : 0~127 , y : 0~63) , r : 1~32 , color : 0/1
    {
        int x=0,y=r,d;
        d=3-2*r;
        while(x<=y)
        {
            cog_drawpixel(x0+x,y0+y,color);
            cog_drawpixel(x0-x,y0+y,color);
            cog_drawpixel(x0+x,y0-y,color);
            cog_drawpixel(x0-x,y0-y,color);
            cog_drawpixel(x0+y,y0+x,color);
            cog_drawpixel(x0-y,y0+x,color);
            cog_drawpixel(x0+y,y0-x,color);
            cog_drawpixel(x0-y,y0-x,color);
            if(d<0)
                d=d+4*x+6;
            else
            {
                d=d+4*(x-y)+10;
                y--;
            }
            x++;
        }
    }

      8)显示字符和字符串;

        字符可以用取模软件生成,可以生成不同大小的字符,一般都是遵循ASCII码的顺序,这样方便编程。

    void cog_showchar(uchar x,uchar y,uchar size_char,uchar chr)        //show char(x : 0~127 , y : 0~7) , size_char : 8/16/32
    {
        uchar i;
        chr=chr-' ';
        if(size_char==8)
        {
            cog_setposition(x,y);
            for(i=0;i<6;i++)
            {
                display_cache[y*128+x+i]=font6x8[chr*6+i];
                cog_writebyte(font6x8[chr*6+i],COG_DATA);
            }
        }
        else if(size_char==16)
        {
            cog_setposition(x,y);
            for(i=0;i<8;i++)
            {
                display_cache[y*128+x+i]=font8x16[chr*16+i];
                cog_writebyte(font8x16[chr*16+i],COG_DATA);
            }
            cog_setposition(x,y+1);
            for(;i<16;i++)
            {
                display_cache[(y+1)*128+x+i-8]=font8x16[chr*16+i];
                cog_writebyte(font8x16[chr*16+i],COG_DATA);
            }
        }
        else
        {
            cog_setposition(x,y);
            for(i=0;i<16;i++)
            {
                display_cache[y*128+x+i]=font16x32[chr*4][i];
                cog_writebyte(font16x32[chr*4][i],COG_DATA);
            }
            cog_setposition(x,y+1);
            for(i=0;i<16;i++)
            {
                display_cache[(y+1)*128+x+i]=font16x32[chr*4+1][i];
                cog_writebyte(font16x32[chr*4+1][i],COG_DATA);
            }
            cog_setposition(x,y+2);
            for(i=0;i<16;i++)
            {
                display_cache[(y+2)*128+x+i]=font16x32[chr*4+2][i];
                cog_writebyte(font16x32[chr*4+2][i],COG_DATA);
            }
            cog_setposition(x,y+3);
            for(i=0;i<16;i++)
            {
                display_cache[(y+3)*128+x+i]=font16x32[chr*4+3][i];
                cog_writebyte(font16x32[chr*4+3][i],COG_DATA);
            }
        }
    }
    
    void cog_showstring(uchar x,uchar y,uchar size_char,uchar *string)        //show string(x : 0~127 , y : 0~7) , size_char : 8/16
    {
        uchar i=0;
        while(string[i]!='')
        {
            cog_showchar(x,y,size_char,string[i]);
            x=x+8;
            if(x>120)
            {
                if(size_char==8)
                {
                    x=0;
                    y=y+1;
                }
                else
                {
                    x=0;
                    y=y+2;
                }
            }
            i++;
        }
    }

      既然是要进行图形编辑,那么在进行设置等需要显示其他内容是,显示缓存里关于图形的内容就被覆盖掉了,最直接的解决方法就是再建一个缓存数组,实时保存编辑的图形,在设置完需要切回图形时显示这个数组就可以了。

      整个程序不是很复杂,但是也无法在这里一一介绍,所以将程序整个打包,需要的自取。

     https://files.cnblogs.com/files/sk3241/%E5%9F%BA%E4%BA%8EJLX12864%E7%9A%84%E7%AE%80%E6%98%93%E5%9B%BE%E5%BD%A2%E7%BC%96%E8%BE%91%E5%99%A8.rar

      最后将电路板用木板包装装饰一下,就是以下的样子:

       

      接上USB线后就可以进行图形编辑,比如画一个温度计;

      绘制完成之后,在电脑端打开任意串口调试工具,设置波特率115200,打开串口,按下图形编辑器的“上传”按钮,绘制的图形就以字符形式发送到了电脑;

      将接收到的图形数据保存为txt文件,就可以用在别的程序里了,很方便。

  • 相关阅读:
    Activity使用startActivityForResult时出现onActivityResult()不执行的问题
    Android AppWidget
    linux 条件变量
    effective c++:private继承
    effective c++:virtual函数的替代方案
    effective c++:inline函数,文件间编译依存关系
    effective c++:dynamic_cast,避免返回handles指向对象内部
    effective c++:引用传递与值传递,成员函数与非成员函数
    effective c++:资源管理
    effective c++:对象的赋值运算
  • 原文地址:https://www.cnblogs.com/sk3241/p/13038374.html
Copyright © 2011-2022 走看看