jackielau 发表于 2009-6-28 23:01:30

发一个ST7920控制器LCD12864源代码,有画点、画线功能

最近做个项目,要用到一块12864的液晶CM12864-12,使用ST7920控制器,这款控制器内置了汉字库显示字符汉字方便,但是汉字库是16*16点阵的,我要显示点别的怎么??可以用图形RAM画图。我想显示12*12的汉子,这样就能显示五行了!我的实现思路是实现画点函数,画点函数需要对GDRAM读,不然显示一团糟!这里用7920的并行模式,串行模式虽然节省IO口,但是不能读出数据!那就开始吧!
在网上找了7、8个版本的7920驱动,发现几乎都只用了基本的显示字符汉字功能,即使使用的画图,也没有画点!!
自己写!看着液晶手册写,但是显示乱七八糟,怎么改都不行,以前也过KS0108的画点函数不难啊??怎么这个就不行了!一点点着,发现读GDRAM数据有问题,读出的数据不正确!液晶手册不是很详细,还是看7920的手册!
终于找到问题所在:原来7920读出数据时,需要DUMMY READ,就是要读两次!!液晶手册很害人,就说个大概!看来以后要注意啊,要从跟上看!!!
简单一改,就OK了!!
现在把照片,电路(非常简单),源码都亮出来!!希望阿莫给个COOL!(7920的实现画点的代码网上可能没有啊,反正我没找到!嘿嘿)


电路
http://cache.amobbs.com/bbs_upload782111/files_16/ourdev_456694.JPG
(原文件名:12864.JPG)
显示效果
http://cache.amobbs.com/bbs_upload782111/files_16/ourdev_456647.JPG
(原文件名:IMG_3244.JPG)
实验板
http://cache.amobbs.com/bbs_upload782111/files_16/ourdev_456648.JPG
(原文件名:IMG_3245.JPG)
源码
点击此处下载 ourdev_456695.rar(文件大小:424K) (原文件名:OM_test.rar)

ecat 发表于 2009-6-28 23:04:41

cool!

simond 发表于 2009-6-28 23:20:56

cool

vv3g 发表于 2009-6-28 23:27:22

这么长时间了,我抢了靠前的位置,哈哈,板凳学习

sdjackal 发表于 2009-6-29 01:15:13

源码。。。。。。。

jackielau 发表于 2009-6-29 07:43:35

昨晚忘传代码了,不好意思,现在已经补上了!!!

xiaowei0588 发表于 2009-6-29 08:01:02

好!

0620221 发表于 2009-6-29 08:18:15

dddddddddddd

jackielau 发表于 2009-6-29 08:44:59

程序的基本操作,是从51中移植过来的,感谢原作者!
程序还不是特别完善,请大家多提建议!
目前程序支持8bit并行和串行操作(串行不能读)
下一步看看手中的模块是否支持4bit并行,争取弄出来,继续公布源码!

liudeee 发表于 2009-6-29 10:23:52

无语,我发过两次ST7920芯片的程序,
http://www.ouravr.com/bbs/bbs_content.jsp?bbs_sn=3349967&bbs_page_no=1&search_mode=3&search_text=liudeee&bbs_id=9999
上面这个事第一发,有几处有问题。
http://www.ouravr.com/bbs/bbs_content.jsp?bbs_sn=3411711&bbs_page_no=1&search_mode=3&search_text=liudeee&bbs_id=9999
这个是后来修改又发的,

画线,画点,画圆,用绘图方法写任意大小的字体,函数都有,LZ怎么说没找到。无语,绝对方便在AVR上移植

同样是并行

http://cache.amobbs.com/bbs_upload782111/files_16/ourdev_456715.jpg
画图方法写任意大小字体 (原文件名:ourdev_445191.jpg)

jackielau 发表于 2009-6-29 10:34:00

真的没找到啊!在这个坛子就找了5、6个版本呢!呵呵,用搜索找的,大海捞针呢,不一定就捞得到想要的啊!

zhseedling 发表于 2009-6-29 21:45:23

能否放出GUI里面的画点程序阿,为什么网上找的东西都是不完全的呢?

不过楼主的程序真漂亮,呵呵,我觉得用漂亮来形容比较合适.我现在写的东西还是很乱那,不过以后争取写得规范些.

liudeee 发表于 2009-6-30 00:38:16

//**********************************************************
// 名称:GUI_Point(unsigned char y,unsigned char x,unsigned colour)
// 功能:在指定位置上画点。
// 入口参数:x                指定点所在行的位置
//         y                指定点所在列的位置
//          color           显示颜色(对于黑白色LCD12864,为0时灭,为1时显示)
// 出口参数:无
//**********************************************************
void GUI_Point(unsigned char y,unsigned char x,unsigned colour)
{
    unsigned char GDRAM_hbit,GDRAM_lbit;
    unsigned char x_Dyte,x_byte;               //定义列地址的字节位,及在字节中的哪1位
    unsigned char y_Dyte,y_byte;      
    x--;y--;                                                                       //定义为上下两个屏(取值为0,1),行地址(取值为0~31)
    /***X,Y坐标互换,即普通的X,Y坐标***/
    x_Dyte=y/16;                                       //计算在16个字节中的哪一个
    x_byte=y&0x0f;                                     //计算在该字节中的哪一位
    y_Dyte=x/32;                                       //0为上半屏,1为下半屏
    y_byte=x&0x1f;                                     //计算在0~31当中的哪一行
   
    LCD12864_Write(COMMAND,0x80+y_byte);                     //设定行地址(y坐标)
    LCD12864_Write(COMMAND,0x80+x_Dyte+8*y_Dyte);         //设定列地址(x坐标),并通过8*y_Dyte选定上下屏
                           
    LCD12864_Read();
    GDRAM_hbit=LCD12864_Read();                         //读取当前显示高8位数据
    GDRAM_lbit=LCD12864_Read();                         //读取当前显示低8位数据
    Delay_nus(1);
   
    if(colour==1)
    {
                LCD12864_Write(COMMAND,0x80+y_byte);                     //设定行地址(y坐标)
                LCD12864_Write(COMMAND,0x80+x_Dyte+8*y_Dyte);         //设定列地址(x坐标),并通过8*y_Dyte选定上下屏
                Delay_nus(1);

      if(x_byte<8)                                             //判断其在高8位,还是在低8位
                {
                        LCD12864_Write(DATA,GDRAM_hbit|(0X01<<(7-x_byte)));   //显示GDRAM区高8位数据
                        LCD12864_Write(DATA,GDRAM_lbit);                           //显示GDRAM区低8位数据
      }
      else
      {
                        LCD12864_Write(DATA,GDRAM_hbit);
                        LCD12864_Write(DATA,GDRAM_lbit|(0x01<<(15-x_byte)));
      }
    }
    else
    {
                LCD12864_Write(COMMAND,0x80+y_byte);                     //设定行地址(y坐标)
                LCD12864_Write(COMMAND,0x80+x_Dyte+8*y_Dyte);         //设定列地址(x坐标),并通过8*y_Dyte选定上下屏
                Delay_nus(1);

      if(x_byte<8)                                             //判断其在高8位,还是在低8位
                {
                        LCD12864_Write(DATA,GDRAM_hbit & ~(0X01<<(7-x_byte)));   //显示GDRAM区高8位数据
                        LCD12864_Write(DATA,GDRAM_lbit);                           //显示GDRAM区低8位数据
      }
      else
      {
                        LCD12864_Write(DATA,GDRAM_hbit);
                        LCD12864_Write(DATA,GDRAM_lbit & ~(0x01<<(15-x_byte)));
      }
        }
       
}


/***********************************************************
* 名称:GUI_Line(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char colour)
* 功能:在指定位置上画线。
* 入口参数:x0                指定线起点所在行的位置
*         y0           指定线起点所在列的位置
*         x1                指定线终点所在行的位置
*         y1           指定线终点所在列的位置
*          color           显示颜色(对于黑白色LCM,为0时灭,为1时显示)
* 出口参数:无
/**********************************************************/
void GUI_Line(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char colour)
{
    int temp;
    int dx,dy;               //定义起点到终点的横、纵坐标增加值
    int s1,s2,status,i;
    int Dx,Dy,sub;

    dx = x1 - x0;
    if(dx >= 0)               //X的方向是增加的
      s1 = 1;
    else                     //X的方向是降低的
      s1 = -1;   
    dy = y1 - y0;               //判断Y的方向是增加还是降到的
    if(dy >= 0)
      s2 = 1;
    else
      s2 =- 1;

    Dx = abs(x1-x0);             //计算横、纵标志增加值的绝对值
    Dy = abs(y1-y0);
      
    if(Dy > Dx)                              
    {                     //以45度角为分界线,靠进Y轴是status=1,靠近X轴是status=0
      temp = Dx;
      Dx = Dy;
      Dy = temp;
    status = 1;
    }
    else
      status = 0;


/*********Bresenham算法画任意两点间的直线********/
    sub = Dy + Dy - Dx;               //第1次判断下个点的位置
    for(i = 0;i < Dx;i ++)
    {
      GUI_Point(x0,y0,colour);         //画点
      if(sub >= 0)                              
      {
            if(status == 1)               //在靠近Y轴区,x值加1
                x0 += s1;
            else                     //在靠近X轴区,y值加1               
                y0 += s2;
            sub -= (Dx + Dx);               //判断下下个点的位置
      }
      if(status == 1)
            y0 += s2;
      else      
            x0 += s1;
      sub += Dy + Dy;
      
    }
}


       

/****************************************************************************
* 名称:plotC(int x,int y,int xc,int yc,unsigned char colour)
* 功能:八分点画圆函数
* 入口参数:x                指定线起点所在行的位置
*         y           指定线起点所在列的位置
*          color           显示颜色(对于黑白色LCM,为0时灭,为1时显示)
* 出口参数:无
****************************************************************************/
void plotC(int x,int y,int xc,int yc,unsigned char colour)
{
    GUI_Point(xc+x,yc+y,colour);
    GUI_Point(xc+x,yc-y,colour);
    GUI_Point(xc-x,yc+y,colour);
    GUI_Point(xc-x,yc-y,colour);
    GUI_Point(xc+y,yc+x,colour);
    GUI_Point(xc+y,yc-x,colour);
    GUI_Point(xc-y,yc+x,colour);
    GUI_Point(xc-y,yc-x,colour);
}

/****************************************************************************
* 名称:GUI_Circle(int xc,int yc,int r,unsigned char colour)
* 功能:画圆
* 入口参数:xc                圆心的行坐标
*         yc           圆心的列坐标
*         r                半径
*          color           显示颜色(对于黑白色LCM,为0时灭,为1时显示)
* 出口参数:无
****************************************************************************/
void GUI_Circle(int xc,int yc,int r,unsigned char colour)
{
    int x,y,d;
    y = r;
    d = 3 - (r + r);
    x = 0;
    while(x <= y)
    {
      plotC(x,y,xc,yc,colour);
      if(d < 0)
            d += (x + x + x + x) + 6;
      else
      {
            d+=((x - y) + (x - y) + (x - y) + (x - y)) + 10;
            y = y - 1;
      }
      x = x + 1;
    }
}

/****************************************************************************
* 名称:GUI_Full(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char colour)
* 功能:用绘图的方法填充一个矩形
* 入口参数:x0                起始点横坐标
*         y0           起始点纵坐标
*         x1                终止点横坐标
*         y1      终止点纵坐标
*          color           显示颜色(对于黑白色LCM,为0时灭,为1时显示)
* 出口参数:无
****************************************************************************/
void GUI_Full(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char colour)
{
    unsigned char i,j;
        for(j = y0;j <= y1;j ++)
          for(i = x0;i <= x1;i ++)
                  GUI_Point(i,j,colour);
}

jackielau 发表于 2009-6-30 08:39:12

//******************************************************************************
//*函数名称:void LCD_Point(unsigned char x,unsigned char y,unsigned char color)*
//*函数功能:使用绘图的方法,在(x,y)处画一个16*16点阵的图案,也可以是字符                   *
//*形式参数:unsigned char x,unsigned char y,unsigned char color                *
//*                        x取值范围:0~127                                                                                                           *
//*                        y取值范围:0~63 (针对CM12864-12型液晶)                                                     *
//*形参说明:坐标水平位置,坐标垂直位置                                                                    *
//*液晶屏坐标说明:                                                                                                                           *
//*      ________________128个像素______________________            *
//*      |(0,0)                                    (7,0)|             *
//*      |                                              |             *
//*   64 |                                              |             *
//*   个 |(0,31)                                  (7,31)|             *
//*   像 |(8,0)                                 (15,0)|             *
//*   素 |                                              |             *
//*      |                                              |             *
//*      |(8,31)                                 (15,31)|             *
//*      |______________________________________________|             *
//*                                                                   *
//*返回参数:无                                                            *
//*使用说明:此函数适用于CM12864-12型液晶                        *
//******************************************************************************
void LCD_Point(unsigned char x,unsigned char y,unsigned char color)
{
        unsigned char i,AddrX,AddrY;        //寄存器地址
        unsigned char BitTemp;                //该点在16bit的位置
        unsigned char DataH,DataL;

        AddrX = x>>4;                                // x/16
        AddrY = y&0x3F;                                // y%64
        if(y > 31)
        {
                AddrX += 8;
                AddrY -= 32;
        }
        BitTemp = x&0x0F;                        // x%16

       
        LCD_GraphModeSet(0x00);                //先关闭图形显示功能
    //LCD_Write(LCD_COMMAND,LCD_EXTEND_FUNCTION);
       
        for(i=0;i<4;i++)
        {
        LCD_GDRAM_AddressSet(0x80+AddrY);
        LCD_GDRAM_AddressSet(0x80+AddrX);
        //LCD_Write(LCD_COMMAND,LCD_BASIC_FUNCTION);                        //基本指令集
        DataH = LCD_ReadData();
        DataH = LCD_ReadData();
        DataL = LCD_ReadData();
        //DataH = LCD_ReadData();
        //DataL = LCD_ReadData();
        }

        if(color == LCD_COLOR_BLACK)
        {
                if(BitTemp > 7)
                {
                        DataL |= (0x80>>(BitTemp-8));
                }
                else
                {
                        DataH |= (0x80>>(BitTemp));
                }
        }
        else
        {
        }

        LCD_GDRAM_AddressSet(0x80+AddrY);
        LCD_GDRAM_AddressSet(0x80+AddrX);
        LCD_Write(LCD_DATA,DataH);
        LCD_Write(LCD_DATA,DataL);
       
        LCD_GraphModeSet(0x01);                                //最后打开图形显示功能
}

jackielau 发表于 2009-6-30 08:40:34

【11楼】 zhseedling
谬赞了!我写的一般,比起高手差很多啊!不过一直在学习呢!

zhseedling 发表于 2009-7-1 19:32:51

我用楼主的程序写的,呵呵,研究了好多天呢,终于会用了。

我想用12864作为屏幕做魏坤示波器(本论坛里的开源项目)的屏,楼主有没有好建议啊

只是图片,没有实质的东西

http://cache.amobbs.com/bbs_upload782111/files_16/ourdev_457519.jpg
(原文件名:1.jpg)

http://cache.amobbs.com/bbs_upload782111/files_16/ourdev_457520.jpg
(原文件名:2.jpg)

http://cache.amobbs.com/bbs_upload782111/files_16/ourdev_457521.jpg
(原文件名:3.jpg)

jackielau 发表于 2009-7-1 21:30:32

【15楼】 zhseedling
刚刚才用7920的LCD,是从一个一起上拆下的,呵呵!明天就要给人家装上了,要拿走!
所以就玩了这几天!
我的感觉如果显示图形,特别是需要频繁刷新图形(示波器恰恰如此),7920并不适合,因为他需要频繁的关闭显示,这样感觉闪烁,不如KS0108方便!7920更适合显示字符!

以上愚见,请高手指正!

zhseedling 发表于 2009-7-1 23:58:29

为了这个示波器,12864已经是我买的第二个屏了,之前买了一个320240的tft,hx8347主控的,也研究了好些天,首先是没资料,后来东凑西凑的终于找到一些资料,可始终点不亮那个屏,没办法,才买了12864,后来才发现,12864画图可真够费劲的了

jackielau 发表于 2009-7-2 09:59:31

如果做示波器还是320240比较好,分辨率高,27元那个液晶就不错,有驱动和示例代码,好像没有资料!现在好像35元了!
在 淘宝超值推荐论坛有他的连接,你可以看看!

hfd999 发表于 2009-7-4 18:55:48

能留下联系方式么?
hfd2k@qq.com

根据你的程序改写后,画长的斜线是一节一节的。
垂线和水平线就没问题

wanghengzhi 发表于 2009-7-4 20:00:23

很好!
标记!

sabergg 发表于 2009-7-4 20:31:53

哇。。。。帅气。。。。。。。。。。。

wuyuwuqi 发表于 2009-7-10 16:13:27

楼主 我怎么把你的程序复制到我的界面下 怎么好多错误的呀我用的CVAVR 可以把你的源程序 给我看看嘛?我的QQ 619089960 谢了
zhseedling你是怎么移植的呀?你用的什么编译软件?

jackielau 发表于 2009-7-10 17:32:16

【19楼】 hfd999
估计是读数据有问题!
我的EMAIL:jackielau1980@sohu.com
欢迎交流,最近在外地!
【22楼】 wuyuwuqi
当然了我用的GCC,呵呵看看什么错误,改改就好了
我不懂CVAVR啊

haozi_1989 发表于 2009-7-11 08:52:45

头文件看了一下,好像原有的设计应该是并行、串行都可以用的,不知为什么串行的没用出来,那我就花点功夫看看并行的吧。

yu_studio 发表于 2009-7-11 08:58:13

好东西,留名

lanlanx 发表于 2009-7-13 10:29:09

mark一个,回头继续看

jackielau 发表于 2009-7-14 09:14:52

【24楼】 haozi_1989
本来打算把串行的弄出来,但是手上LCD拿走了,再加上最近出差没空,也就一直没写!!
这个控制器有个缺点,就是串行不能读操作,这样花点画线就很难实现,(除非在RAM中开辟一块1024B的缓存,我用的M16,好像只有1KRAM,所以比较难实现了),所以就尽头不大了!!

jackielau 发表于 2009-7-14 09:18:51

通用24CXXX读写程序(GCC),兼容24C系列存储器(24C01到24C1024),支持跨器件跨页读写,支持连续读写32K字节
http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=3444492&bbs_page_no=1&search_mode=3&search_text=jackielau&bbs_id=9999
也是我也写的,呵呵,欢迎提出意见

haozi_1989 发表于 2009-7-16 21:12:09

同文件兼顾了串行和并行两种方式,但是发的好像有问题,头文件里的函数和测试程序里的好像不匹配,不知是何原因

jackielau 发表于 2009-7-17 11:15:11

【29楼】 haozi_1989
呵呵,找到问题了,你看的是main。c,测试程序不是这个文件!!是OM_test.c.c
重新上传!!!

点击此处下载 ourdev_462016.rar(文件大小:421K) (原文件名:ourdev_456695.rar)

ouyangyong817 发表于 2009-7-25 20:32:00

受教了!

sange 发表于 2009-7-28 14:28:53

jihao

jackielau 发表于 2009-7-28 15:32:41

字符汉字显示用7920很方便,但是画图还是KS0108的感觉好一些

vipxuliang 发表于 2009-7-29 10:35:05

我的7920屏有个问题:一进入图形模式就花屏(黑白点乱乱的),害得我每次都要全屏写零一次。不知道是啥原因?
请高手帮忙找找原因。

ggyyll8683 发表于 2009-7-29 13:33:13

mark!

jackielau 发表于 2009-7-29 15:29:05

【35楼】 vipxuliang
应该是屏RAM数据没有全部变零。你的是不是有大电容或者掉电时间很多才出啊?关机很长时间也出这个问题吗?
另外,我觉得开机对屏RAM清零是必要的!

tota2004 发表于 2009-7-29 16:27:16

记号

coolc 发表于 2009-7-31 18:51:00

我用楼主的程序,怎么画一条竖线时会同时出现三条竖线呢?环境:M16,studio 4.16,(GCC)WinAVR-20080610,金鹏OCMJ4X8C型12864液晶,一直没搞明白哪地方错了,希望楼主能帮忙看一下...本人在校生...QQ:897772871,同时欢迎各位朋友加友交流,注明avr论坛...

程序自己稍稍改了一下,如下:
#include<avr/io.h>
#include<delay.h>
#include<math.h>
#include <string.h>

#define uchar unsigned char
#define uint unsigned int
#define CTRL_PORTPORTA
#define CTRL_DDRDDRA
#define CTRL_PINPINA
#define RS 5                         //CS   第四引脚
#define RW 6                        //SIO第五引脚
#define E7                        //SCK第六引脚
   
#define DATA_DDR DDRD
#define DATA_PIN PIND
#define DATA_PORT PORTD

#define CTRL_OUT() CTRL_DDR |= (1<<(RS))|(1<<(RW))|(1<<(E))

#defineCLR_RS() CTRL_PORT &= ~(1<<RS)
#defineSET_RS() CTRL_PORT |= (1<<RS)

#define CLR_RW() CTRL_PORT &= ~(1<<RW)
#define SET_RW() CTRL_PORT |= (1<<RW)

#define CLR_E()CTRL_PORT &= ~(1<<E)
#define SET_E()   CTRL_PORT |= (1<<E)


#define DATA_IN() DATA_DDR &= ~0xFF
#define DATA_OUT() DATA_DDR |= 0xFF
#define DATA_GET() DATA_PIN

//液晶基本参数
#define X_MAX 127
#define Y_MAX 63

//每行的首地址
#define ONE   0x80
#define TWO   0x90
#define THREE 0x88
#define FOUR0x98

//基本指令集预定义
#define DATA                1          //数据位
#define COMMAND             0         //命令位
#define CLEAR_SCREEN      0x01      //清屏
#define ADDRESS_RESET       0x02      //地址归零   
#define BASIC_FUNCTION      0x30       //基本指令集
#define EXTEND_FUNCTION   0x34      //扩充指令集

//扩展指令集预定义
#define AWAIT_MODE 0x01                //待命模式
#define ROLLADDRESS_ON 0x03         //允许输入垂直卷动地址
#define IRAMADDRESS_ON 0x02         //允许输入IRAM地址
#define SLEEP_MODE 0x08               //进入睡眠模式
#define NO_SLEEP_MODE 0x0c         //脱离睡眠模式
#define GRAPH_ON 0x36               //打开绘图模式
#define GRAPH_OFF 0x34               //关闭绘图模式

#ifndef COLOR
#define BLACK      1
#define WHITE      0
#endif


void SendByte(unsigned char a)
{
unsigned char i,d;
SET_RS();
CLR_RW();
for(i=0;i<8;i++)
{
CLR_E();         //clrbit(LCD_CTRL,E);   
d = a&0x80;
if(d)
SET_RW(); //setbit(LCD_CTRL,RW);
else
CLR_RW(); //clrbit(LCD_CTRL,RW);
a<<=1;
SET_E();         //setbit(LCD_CTRL,E); //上升弦发送
}
CLR_RS();
}



void CheckBusy(void)
{
unsigned char temp;
DATA_IN();   
CLR_RS();             //RS = 0;指令
SET_RW();             //RW = 1;读模式
delay3us();         //延时
delay3us();            //延时
SET_E();            //E= 1,使能
do
{
temp = DATA_GET();                     //temp = BUSY;
}
while( 0x80==(temp&0x80) );         //等待不忙,temp=0x00时不忙
CLR_E();                                 //E= 0;
}



void Write( unsigned char Data_Command , unsigned char uc_Content )
{
CheckBusy();
DATA_OUT();

if(Data_Command==COMMAND)
{
CLR_RS();               //RS = 0;指令
}
else
{
SET_RS();                //RS = 1; 数据
}
CLR_RW();                //RW = 0;   //写模式
DATA_PORT = uc_Content;
SET_E();                   //E = 1;
delay3us();               //延时
CLR_E();               //E = 0;
}



unsigned char ReadData(void)
{
unsigned char uc_Content;
CheckBusy();
DATA_PORT = 0xff ;
DATA_IN();                     //P1 = 0xff;//输入前置1
SET_RS();                  //RS = 1;   //数据
SET_RW();                  //RW = 1; //读模式
SET_E();                  //E = 1; //使能
delay3us();                     //延时很重要
uc_Content = DATA_GET();    //uc_Content = P1;    //P1口的内容放到变量中
CLR_E();                  //E = 0;
delay3us();               //延时很重要
return uc_Content;
}

void DDRAM_AddressSet(unsigned char ucDDramAdd)
{
Write(COMMAND,BASIC_FUNCTION);          //基本指令集
Write(COMMAND,ucDDramAdd);            //设定DDRAM地址到地址计数器AC
}

void CGRAM_AddressSet(unsigned char ucCGramAdd)
{
Write(COMMAND,BASIC_FUNCTION); //基本指令集
Write(COMMAND,ucCGramAdd); //设定CGRAM地址到地址计数器AC
}

void GDRAM_AddressSet(unsigned char ucGDramAdd)
{
Write(COMMAND,EXTEND_FUNCTION); //扩展指令集
Write(COMMAND,ucGDramAdd);
}

void Init(void)
{
CTRL_OUT();
Write(COMMAND,BASIC_FUNCTION); //基本指令动作   
delay50us();
Write(COMMAND,CLEAR_SCREEN);   //清屏,地址指针指向00H
delay50us();
Write(COMMAND,0x06);       //光标的移动方向
delay50us();
Write(COMMAND,0x0C);   //开显示,关游标
}


void ClearRam(void)
{
Write(COMMAND,BASIC_FUNCTION); //基本指令集
Write(COMMAND,CLEAR_SCREEN); //清屏
}

void GraphModeSet(unsigned char Select)
{
Write(COMMAND,EXTEND_FUNCTION); //扩展指令集
if(Select==1)
{
Write(COMMAND,GRAPH_ON); //打开绘图模式
}
else
{
Write(COMMAND,GRAPH_OFF); //关闭绘图模式
}
}


void DisplayCLR()
{
unsigned char i,j;
GraphModeSet(0); //先关闭图形显示功能
for(j=0;j<32;j++)
    {
   for(i=0;i<8;i++)
       {
       Write(COMMAND,0x80+j); //设定垂直坐标
       Write(COMMAND,0x80+i); //设定水平坐标
         Write(DATA,0x00); //放入数据高字节
       Write(DATA,0x00); //放入数据低字节
      }
    }
   for(j=32;j<64;j++)
    {
   for(i=0;i<8;i++)
      {
       Write(COMMAND,0x80+j-32);
       Write(COMMAND,0x88+i);
       Write(DATA,0x00);
       Write(DATA,0x00);
      }
    }
GraphModeSet(1);//最后打开图形显示功能
}

void LCD_Point(unsigned char x,unsigned char y,unsigned char color)
{
        unsigned char i,AddrX,AddrY;                //寄存器地址
        unsigned char BitTemp;                //该点在16bit的位置
        unsigned char DataH,DataL;
        AddrX = x>>4;                                // x/16
        AddrY = y&0x3F;                                // y%64
        if(y > 31)
        {
                AddrX += 8;
                AddrY -= 32;
        }
        BitTemp = x&0x0F;                        // x%16
        GraphModeSet(0x00);                        //先关闭图形显示功能          
        for(i=0;i<4;i++)
        {
        GDRAM_AddressSet(0x80+AddrY);
        GDRAM_AddressSet(0x80+AddrX);
        DataH = ReadData();
        DataH = ReadData();
        DataL = ReadData();
        }
        if(color == BLACK)
        {
                if(BitTemp > 7)
                {
                        DataL |= (0x80>>(BitTemp-8));
                }
                else
                {
                        DataH |= (0x80>>(BitTemp));
                }
        }
        else
        {
        }
        GDRAM_AddressSet(0x80+AddrY);
        GDRAM_AddressSet(0x80+AddrX);
        Write(DATA,DataH);
        Write(DATA,DataL);       
        GraphModeSet(0x01);                                //最后打开图形显示功能
}


int main()
{
    uchar i;
    Init();                                                 //液晶屏初始化
    ClearRam();                                             //清除显示存储区内的内容
    DisplayCLR();
   
    for(i=0;i<50;i++)
        {   
          LCD_Point(0,i,1);
        }
}

cyr_hongfeng 发表于 2009-7-31 23:23:47

先做个记号,,,,,

Huaan 发表于 2009-7-31 23:40:57

【39楼】 coolc : ReadData 有错哦~
unsigned char ReadData(void)
{
unsigned char uc_Content;
CheckBusy();

/*!!*/
DATA_PORT = 0xff ; /*!!*/
/*!!*/

DATA_IN();                     //P1 = 0xff;//输入前置1
SET_RS();                  //RS = 1;   //数据
SET_RW();                  //RW = 1; //读模式
SET_E();                  //E = 1; //使能
delay3us();                     //延时很重要   
uc_Content = DATA_GET();    //uc_Content = P1;    //P1口的内容放到变量中
CLR_E();                  //E = 0;
delay3us();               //延时很重要   
return uc_Content;
}

应改为
unsigned char ReadData(void)
{
unsigned char uc_Content;
CheckBusy();

DATA_IN();                  //P1设置为输入

DATA_IN();                     
SET_RS();                  //RS = 1;   //数据
SET_RW();                  //RW = 1; //读模式
SET_E();                  //E = 1; //使能
delay3us();                     //延时很重要   
uc_Content = DATA_GET();    //uc_Content = P1;    //P1口的内容放到变量中
CLR_E();                  //E = 0;
delay3us();               //延时很重要   

DATA_OUT();                //P1设置为输出

return uc_Content;
}

coolc 发表于 2009-8-1 09:20:59

谢了!!楼上的,这个地方确实有点问题,但是我改过了,还是在(0,0)写一点在其后又出现两点,画一条竖线出现三条竖线的情况啊!!附上12864连接图,PSB接的是高电平,不会是连接的问题或是液晶屏的问题吧....
还有楼主的程序:这里为什么要循环读四次呢?
for(i=0;i<4;i++)
{
GDRAM_AddressSet(0x80+AddrY);
GDRAM_AddressSet(0x80+AddrX);
DataH = ReadData();
DataH = ReadData();
DataL = ReadData();
}
http://cache.amobbs.com/bbs_upload782111/files_17/ourdev_466339.jpg
(原文件名:12864.jpg)

zxy1217 发表于 2009-8-1 10:41:24

mark

jackielau 发表于 2009-8-3 08:55:40

【42楼】 coolc
那个实在最初试验时加的,当时没有明白“假读”,用多循环几次解决问题!现在说应该是没用的

“在(0,0)写一点在其后又出现两点,画一条竖线出现三条竖线的情况”
估计是读数据出的问题,画点需要读数据,如果有足够的RAM,建议不用他,在RAM建立镜像BUF

vgbird 发表于 2009-8-4 12:53:36

..嗯 不错 学习了

gzcc 发表于 2009-8-8 11:24:25

谢谢啊

jiang0603 发表于 2009-8-9 17:10:18

【42楼】 coolc
那个实在最初试验时加的,当时没有明白“假读”,用多循环几次解决问题!现在说应该是没用的

“在(0,0)写一点在其后又出现两点,画一条竖线出现三条竖线的情况”
估计是读数据出的问题,画点需要读数据,如果有足够的RAM,建议不用他,在RAM建立镜像BUF


我也出现类似的问题,读数据出现什么问题了,能否具体说明!!!!!!!!

jiang0603 发表于 2009-8-9 19:00:07

//读数据
unsigned char Lcd_Readdata()
{
idata uchar dudata ;
   wait();
   RS=1;
   RW=1;
   E=0;
   delay_us(1);          
   dudata=LcdData;
   E=1;
   delay_us(1);       
   E=0;               
   return dudata;
}



void GUI_Point(uchar x,uchar y)
{   
   
   uchar x_Dyte,x_byte; //定义列地址的字节位,及在字节中的哪1位
   uchar y_Dyte,y_byte;//定义为上下两个屏(取值为0,1),行地址(取值为0~31)
   uchar GDRAM_hbit,GDRAM_lbit;                     
   /***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当中的哪一行

   Lcd_WriteCmd(0x36); //绘图模式命令
   Lcd_WriteCmd(0x80+y_byte);//设定行地址(y坐标)
   Lcd_WriteCmd(0x80+x_Dyte+8*y_Dyte);//设定列地址(x坐标),并通过8*y_Dyte选定上下屏
   
   Lcd_Readdata();
   GDRAM_hbit=Lcd_Readdata();
   GDRAM_lbit=Lcd_Readdata();
           
    Lcd_WriteCmd(0x80+y_byte);//设定行地址(y坐标)
    Lcd_WriteCmd(0x80+x_Dyte+8*y_Dyte); //设定列地址(x坐标),并通过8*y_Dyte选定上下屏
       
         if(x_byte<8)//判断其在高8位,还是在低8位
         {
          Lcd_Writedata(GDRAM_hbit|(0X01<<(7-x_byte))); //显示GDRAM区高8位数据
          Lcd_Writedata(GDRAM_lbit); //显示GDRAM区低8位数据
         }
         else
         {
          Lcd_Writedata(GDRAM_hbit);
          Lcd_Writedata(GDRAM_lbit|(0x01<<(15-x_byte)));
         }

   Lcd_WriteCmd(0x30);      
}


这是我的画点函数,用的是12楼的程序,不知哪里有错啊!!!!!知道的兄弟请指点!!!!!

Huaan 发表于 2009-8-9 19:15:13

【49楼】 jiang0603
读函数错了,首先读时序就错了,
应该是置位E再读延时后E清零
还有如果是AVR等真正双向I/O口(51是伪双向的)LcdData的方向要改为输入

jiang0603 发表于 2009-8-9 20:08:17

我试过这种写法,用的是STC的51单片机
//读数据
unsigned char Lcd_Readdata()
{
idata uchar dudata ;
   wait();//判忙
   RS=1;
   RW=1;
   E=1;       
   delay_us(1);          
   dudata=LcdData;
   delay_us(1);       
   E=0;               
   return dudata;
}
但问题还是没有解决啊!!!!!!

qzzz 发表于 2009-8-9 20:15:46

好东西 ,谢谢

Huaan 发表于 2009-8-9 20:32:13

【51楼】 jiang0603
你问题是什么啊??现象呢

jiang0603 发表于 2009-8-9 21:12:01

现象是:不能写直线,写直线时二个字节只能写一个点,写斜线和竖线没问题,所以我觉得问题应该是没有把上一次的数据给读会来!!
不知道各位高手有没其它意见啊!!!!!

jiang0603 发表于 2009-8-9 21:13:34

ps:
   也就是这里:
    Lcd_Readdata();
   GDRAM_hbit=Lcd_Readdata();
   GDRAM_lbit=Lcd_Readdata();

zxy1217 发表于 2009-8-14 10:39:56

用过 顶个

ad001 发表于 2009-8-14 10:57:20

好东西,留名

jackielau 发表于 2009-8-14 17:19:16

【54楼】 jiang0603

从现象上看,应该是读数据有问题!
你可以具体试一试,比如向某一位置写入数据(例如0x55),然后读出看看还是不是这个值啊?!
你说的问题,没出现,试了多次!可能器件不同有点差别!

hxjsini 发表于 2009-8-15 19:59:16

jiang0603,我的也是这样,“写直线时二个字节只能写一个点,写斜线和竖线没问题”
不知道你的问题解决了没有哇?

hxjsini 发表于 2009-8-15 20:04:05

为什么水平画线就会出现 一个字只能显示一个点?而竖直画线也只能在特定的列画出来。有没有高手指点下?

wowu 发表于 2009-8-16 08:16:41

十五楼你好。请问你现在示波器做怎么样了?我也在也做。遇到点问题。可以交流下吗?

jiang0603 发表于 2009-8-16 17:19:17

jiang0603,我的也是这样,“写直线时二个字节只能写一个点,写斜线和竖线没问题”
不知道你的问题解决了没有哇?


问题已经发现了,确实出现在读数据上面啊!!!!把我的对数据函数贴出来你看看:
//读数据
unsigned char Lcd_Readdata()
{
idata uchar dudata ;
   wait();
   LcdData=0xff;//关键!!!!!      就是要加这一句就ok了!!!!!!!!!!
   RS=1;
   RW=1;
   E=1;       
   delay_us(1) ;          
   dudata=LcdData;       
   E=0;               
   return dudata;
}

jackielau 发表于 2009-8-17 09:31:17

【62楼】 jiang0603
你用的不是AVR?是51吗??

jiang0603 发表于 2009-8-17 13:21:47

用的不是avr单片机,用的是51(stc)

jackielau 发表于 2009-8-17 15:34:22

【64楼】 jiang0603
知道了,51的IO口做输入时,必须输出高,它没有IO方向控制!呵呵,我一直以为用的AVR呢!

song1km 发表于 2009-8-17 16:22:15

标个记

xiaobei520 发表于 2009-8-20 18:51:01

很好 很强大

bhxyzel 发表于 2009-8-22 14:28:08

先标记一个!以后肯定用的着!

hxjsini 发表于 2009-8-22 14:29:10

鱼和熊掌不能兼得,我用串行弄了半天却发现串行不能读数据。得买个可位操作的液晶。

jackielau 发表于 2009-8-27 15:30:11

【69楼】 hxjsini 似泥
呵呵,这也是我为什么不在更新程序了!!
7920这个片子不咋地,所以写着没劲了!

xhero 发表于 2009-9-18 15:06:15

真棒 我正需要 谢谢楼主 共享

58180698 发表于 2009-9-22 00:14:37

好贴啊.这几天正在做12864相关的实验....
谢谢LZ共享

12F675 发表于 2009-10-18 22:59:51

MARK

382383706 发表于 2009-11-2 23:25:08

mark

wangyi1e 发表于 2009-11-26 18:59:59

mark

huwenhui 发表于 2009-11-26 19:38:24

mark~

i387DX 发表于 2009-11-26 21:26:04

mark~

fang45 发表于 2009-11-27 11:20:48

mark

Dream_catcher 发表于 2009-11-30 02:30:34

mark

zhangjw 发表于 2009-12-29 00:07:57

mark。

wuxinping 发表于 2010-2-9 12:13:59

thanks 。

wugaohui04 发表于 2010-2-24 11:49:45

mark

byin 发表于 2010-2-24 13:55:31

mark

wugaohui04 发表于 2010-2-26 16:11:55

回复【12楼】liudeee 小菜
-----------------------------------------------------------------------

我想请教下:Dx = abs(x1-x0);             //计算横、纵标志增加值的绝对值 次句中abs是什么意思?????


新手来着!!!

vipxuliang 发表于 2010-4-8 12:25:26

mark

chahu1227 发表于 2010-5-11 16:03:45

mark

AAVVRR 发表于 2010-5-18 14:10:13

一年了。很有用,适合于金鹏的12864OCMJ4X8C,套用楼主程序,文字,图片都可以,就是画点是出现花屏,点已经画上去了就是花屏,不知什么原因。

jikoliu 发表于 2010-6-4 16:03:27

我以前写过12864的驱动,觉得很奇怪,如果显示一小块图形的时候,其它的地方就是花的,害我一次就得刷整块屏,
楼主有没有写过TFT的,最近写一块2.6"的TFT,几天过去了,还没初始化,

jackielau 发表于 2010-6-29 17:26:23

回复【88楼】AAVVRR
一年了。很有用,适合于金鹏的12864ocmj4x8c,套用楼主程序,文字,图片都可以,就是画点是出现花屏,点已经画上去了就是花屏,不知什么原因。
-----------------------------------------------------------------------

估计是读屏幕数据时有问题

hero751 发表于 2010-6-29 18:21:17

好像mark过

yxeglxl 发表于 2010-7-6 15:47:32

cuikai12345 发表于 2010-7-6 21:16:24

mark

jxa19890929 发表于 2010-7-25 19:30:17

多谢 多谢!!

twlkzxy 发表于 2010-8-12 15:13:32

谢谢   我很汗用了串行方式 难怪测试了这么多次 就是读不出来,还准备加上周立功的gui了,看来 要改改了

xtaens 发表于 2010-9-30 20:15:34

mark,谢谢了

wj414 发表于 2010-9-30 23:13:20

收藏了,正想画圆呢。

liujinyong 发表于 2010-10-9 21:58:19

很好 学习了...

YanGaruruga 发表于 2010-10-11 21:12:47

mark

wzxavr 发表于 2010-11-13 14:06:11

MARK

edaworld 发表于 2010-11-13 18:02:49

mark

shaxiao163 发表于 2010-11-17 22:23:13

请问楼主 怎么会出现这样的提示信息
Build started 17.11.2010 at 22:21:57
      0 sh.exe" 3264 fork_copy: user/cygwin data pass 0 failed, 0x46F000..0x474434, done 1776, windows pid 2400, Win32 error 5
"D:/Program Files/WinAVR-20090313/utils/bin/sh.exe": fork: Resource temporarily unavailable
avr-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" --change-section-lma .eeprom=0 --no-change-warnings -O ihex OM_test.elf OM_test.eep || exit 0
      0 sh.exe" 1824 fork_copy: user/cygwin data pass 0 failed, 0x46F000..0x474434, done 1784, windows pid 3816, Win32 error 5
"D:/Program Files/WinAVR-20090313/utils/bin/sh.exe": fork: Resource temporarily unavailable
make: Error 128 (ignored)
avr-objdump -h -S OM_test.elf > OM_test.lss
      0 sh.exe" 1252 fork_copy: user/cygwin data pass 0 failed, 0x46F000..0x474434, done 1784, windows pid 1364, Win32 error 5
"D:/Program Files/WinAVR-20090313/utils/bin/sh.exe": fork: Resource temporarily unavailable
make: *** Error 128
Build failed with 1 errors and 0 warnings...
页: [1] 2
查看完整版本: 发一个ST7920控制器LCD12864源代码,有画点、画线功能