zhb2000 发表于 2006-3-1 10:40:49

再论Atmega8L-LCD12864,带画点函数,希望对想学点阵液晶的朋友有所帮助。(注:GCC的)

前一段时间想搞一下点阵LCD,于是就到本网站上寻找,找到了好多资料,xiaotanlan朋友的资料很好,http://www.ouravr.com/bbs/bbs_content.jsp?bbs_sn=468165&bbs_page_no=1&sub_kind_id=2065&bbs_id=1000

但是看了已后,觉得自已做的时候还是有很多要注意的地方.于是就写了下面的内容:



LCD12864液晶说明(个人跟椐datasheet的理解):

lcd12864分为左半屏和右半屏,每半个屏幕竖着排列着64(0~63)个字节,每个字节最低位在最上面,高位在最下面,一个字节的8位构成了lcd12864一页中一列的8个点,而它共有8页,即在y方向有8*8=64个点.如下图:

http://cache.amobbs.com/bbs_upload782111/files_5/armok01104631.jpg

画点的重点:

    1,通过x坐标所属的左右半屏.

    2,通过y坐标算出点所属的页,及一页内y坐标(即一个字节中一位的位置).

    3,读出原来要画点位字节内容,再设要画的点(否则会擦除原来画的点).

程序如下:

环境:ATmega8L, WinAVR GCC, LCD12864, Proteus6.7

/*

        ATmega8L LCD12864

        作者:zhb2000

*/

#include <avr/io.h>

#define uchar unsigned char

#define uintunsigned int

#define boolunsigned char

#define true1

#define false 0

#define setbit(sfr,bit) (sfr|=(1<<bit))

#define clrbit(sfr,bit) (sfr&=~(1<<bit))

#define RS   0

#define RW   1

#define CS12

#define CS23

#define E    4

#define RST5

#define DATA PORTB

#define CTRL PORTC



void init(void);

uchar getState(void);                        //得到LCD状态字

bool lcdBusy(void);

void lcdCommand(uchar command);                //发送命令字

void lcdOpen(void);                                //打开LCD

void lcdStartLine(uchar line);                //设置起始行

void lcdSetPage(uchar page);                        //设置页地址

void lcdSetRow(uchar row);                                //设置列地址

void lcdWrite(uchar dat,uchar cs);                                        //写显示数据,注'0'亮'1'暗

uchar lcdRead(uchar cs);                                                        //读数据

void pixel(uchar x,uchar y);                                        //画点

int main(void)

{

        init();

        lcdOpen();

        lcdStartLine(0);

        lcdSetPage(0);

        lcdSetRow(0);

        pixel(30,30);

        pixel(100,50);

        pixel(15,40);

        while(1)

        {

        }

        return 0;

}



void init()

{

        PORTB=0xff;

        DDRB=0xff;

        PORTC=0xff;

        DDRC=0xff;

        PORTD=0xff;

        DDRD=0xff;

}



uchar getState()

{

        PORTB=0xff;

        DDRB=0x0;

        clrbit(CTRL,CS1);

        clrbit(CTRL,CS2);

        clrbit(CTRL,RS);

        setbit(CTRL,RW);

        setbit(CTRL,E);                        //下降沿

        clrbit(CTRL,E);

        return PINB;

}



bool lcdBusy()

{

        uchar state=0;

        state=getState();

        if(state&0x80)

        {        //BUSY

                return true;

        }

        else

        {        //idle

                return false;

        }

}



void lcdCommand(uchar command)

{

        DDRB=0xff;

        clrbit(CTRL,CS1);

        clrbit(CTRL,CS2);

        clrbit(CTRL,RS);

        clrbit(CTRL,RW);

        DATA=command;

        setbit(CTRL,E);                        //下降沿

        clrbit(CTRL,E);

}



void lcdOpen()

{

        while(lcdBusy());

        lcdCommand(0x3f);

}



void lcdStartLine(uchar line)

{

        line|=0xc0;

        while(lcdBusy());

        lcdCommand(line);

}



void lcdSetPage(uchar page)

{

        page&=0x7;

        page|=0xb8;

        while(lcdBusy());

        lcdCommand(page);

}



void lcdSetRow(uchar row)

{        //设置列地址

        row&=0x3f;

        row|=0x40;

        while(lcdBusy());

        lcdCommand(row);

}



void lcdWrite(uchar dat,uchar cs)

{        //写显示数据

        while(lcdBusy());

        DDRB=0xff;

        if(cs==1)

        {        //选择左半屏

                clrbit(CTRL,CS1);

                setbit(CTRL,CS2);

        }

        else

        {        //选择右半屏

                clrbit(CTRL,CS2);

                setbit(CTRL,CS1);

        }

        setbit(CTRL,RS);

        clrbit(CTRL,RW);

        DATA=dat;

        setbit(CTRL,E);                        //下降沿

        clrbit(CTRL,E);

}



uchar lcdRead(uchar cs)

{        //读数据

        uchar dat;

        while(lcdBusy());       

        DDRB=0x00;

        PORTB=0xff;

        if(cs==1)

        {        //选择左半屏

                clrbit(CTRL,CS1);

                setbit(CTRL,CS2);

        }

        else

        {        //选择右半屏

                clrbit(CTRL,CS2);

                setbit(CTRL,CS1);

        }

        setbit(CTRL,RS);

        setbit(CTRL,RW);

        setbit(CTRL,E);                        //下降沿

        clrbit(CTRL,E);

        setbit(CTRL,E);                        //高

        dat=PINB;

        return dat;

}

       

void pixel(uchar x,uchar y)

{

        uchar page,dX,dY;

        uchar cs=2;

        uchar dot=0;

        if(x>=64)

        {

                x-=64;

        }

        else

        {

                cs=1;

        }

        dX=x;                                                                        //算出x坐标

        page=y/8;                                                        //算出页号

        dY=y%8;                                                                //算出y坐标

        lcdSetPage(page);

        lcdSetRow(dX);       

        dot=lcdRead(cs);

        clrbit(dot,dY);

        lcdSetPage(page);

        lcdSetRow(dX);       

        lcdWrite(dot,cs);

}



Proteus6.7仿真:

http://cache.amobbs.com/bbs_upload782111/files_5/armok01104628.jpg

原程序及仿真文件:

点击此处下载armok01104632.rar



希望对想学LCD12864点阵液晶的朋友有所帮助.
-----此内容被zhb2000于2006-03-01,10:56:12编辑过

benladn911 发表于 2006-3-1 12:22:37

好贴,顶。

SKYdai 发表于 2006-3-1 20:24:02

好呀!谢谢!!

zhb2000 发表于 2006-3-2 19:47:53

今天花了一整天时间才搞好LCD12863显示2色BMP图片(累啊 :) )。

自已还写了一个2色BMP图片到程序数组的转换小程序bmp2txt.exe

读取2色BMP图片,BMP的头结构我就不多说了,很多书上都有。

这里我们主要注意以下几个地方。

BMP文件偏移

0x0a      图像数据的开始位置

0x12      图像的宽度

0x16      图像的高度

0x1e      图像是否压缩

(这里我们只讨论不压缩的,用windows的画笔画一幅画存盘的时候选单色就行了)

    BMP的2色图像是倒着存放的,即第一个数据字节表示是的图像最后一行的前8

个点"1"表示白色,"0"表示黑色(当然也可跟椐调色板来设置)

    BMP图片数据每行要DWORD对齐,也是一行的字节数必须为4的倍数,如一行的数

据只有8个点为0xff 而BMP表示为 0xff 0x00 0x00 0x00



然后用bmp2txt.exe 将所画的2色图转为程序代码,copy到程序中编译就OK了。

http://cache.amobbs.com/bbs_upload782111/files_5/armok01104906.jpg



关键代码:

/*

        读BMP图像 2色 未压缩

*/



#define BMP_HEIGHT 0x16

#define BMP_WIDTH0x12

#define BMP_COMPRESSION 0x1e

#define BMP_bfOffBits 0x0a

//COMPRESSION

#define BI_RGB                                        0

#define BI_RLE8                                        1

#define BI_RLE4                                        2

#define BI_BITFIELDS                3

const unsigned char Bitmap PROGMEM={//bmp2txt.exe生成的图像数据

......

};



void drawBitmap(const uchar *bmp)

{    //画图像

        signed char x,y;

        uchar bmpHeight,bmpWidth,wByte;

        uintlpOffset;

        uchar dat;

        uchar nx=0;

        uchar i;

uintnumb;

        lpOffset=pgm_read_byte(bmp+BMP_COMPRESSION);        //bmp;

        if(lpOffset!=0) return;                                        //只处理未压缩的图像

        bmpHeight=pgm_read_byte(bmp+BMP_HEIGHT);        //bmp;

        bmpWidth=pgm_read_byte(bmp+BMP_WIDTH);                //bmp;

        lpOffset=pgm_read_byte(bmp+BMP_bfOffBits);        //bmp 得到图像数据的偏移量

       

        /*

                1.BMP图象为到着存放的:即最后一行的数据存放在最前面

                2.2色为一个字节表示一行中的8个像素点

        */

        if(bmpWidth%8!=0)

        {

                wByte=bmpWidth/8+1;

        }

        else

        {

                wByte=bmpWidth/8;

        }

        if(wByte%4!=0)

        {

                wByte=(wByte/4+1)*4;                //DWORD对齐

        }



numb=0;

        for(y=(bmpHeight-1);y>=0;y--)

        {

                for(nx=0;nx<wByte;nx++)

                {

                        dat=pgm_read_byte(bmp+lpOffset+numb);// bmp;

      numb++;

                        for(i=0;i<8;i++)

                        {

                                if(tstbit(dat,(7-i))==0)

                                {

                                        x=nx*8+i;

                                        if(x<bmpWidth)

                                        {

            pixel(x,y);

                                        }

                                }

                        }

                }

        }

}



仿真图:

http://cache.amobbs.com/bbs_upload782111/files_5/armok01104907.jpg



源程序&工具&说明:

点击此处下载armok01104908.rar

kinsey 发表于 2006-3-3 16:22:28

Proteus中有LCD12864的?以前还没有注意,晚上看看还有没有Nokia的那种48*84的LCD,可以的话先模拟实验。哪位大侠知道的请指点一下,先谢谢啦!

xuhui099 发表于 2006-5-12 16:11:31

Proteusd 在哪儿可以下载下来?

aaa233 发表于 2006-5-15 08:23:33

12864有好多种,楼主最好标明型号。

比如我用的SUNSON 12864A在读数据和忙信号时不是下降沿锁定,

而是高电平锁定的。

不同12864时序有细微差别的:)

2005xxg 发表于 2006-5-15 08:54:08

好,顶一下。

dbjdeycl 发表于 2006-5-17 10:30:58

健!顶

ahui 发表于 2006-5-17 16:45:54

不顶不行!!!!!

CODIER 发表于 2006-5-18 08:45:49

LOVEMCU 发表于 2006-5-18 10:04:41

请教用什么工具制作图案呢?

   我试着用Windows自带的画图工具来画,结果发现生成的文件好大,当用你的软件(BMP TO TXT)时,都卡死了!

zhb2000 发表于 2006-5-18 10:26:02

to 12楼 LOVEMCU:

   用windows自带的画笔来画图,注意设置图像的属性宽度最大为127,高度最大为63(你不防就设为宽127,高63).然后用黑色绘图(因为最后的图像是2色的,只有白色和黑色所以浅色会被变成白色).画好以后保存的时候选保存类型为"单色位图(*.bmp,*.dib)" 起个名字保存即可.这样的图像是不会很大的. :)

icer 发表于 2006-10-4 14:18:48

好帖当然要先顶一个!



不过我刚才看到这个论坛里对Proteus有新的规定:



http://www2.ouravr.com/es_avr_serial_software.html



小心被列入黑名单哦,呵呵

xuwukong 发表于 2006-10-5 20:50:36

顶一下,不必担心黑名单,没人会来论坛一个一个的帖子翻,那搞法律的还不累死?

xuepeng2000 发表于 2006-11-30 17:09:20

我个人认为你画的我们的AVR那个图不对

我用Ultraedit取数据的时候

图片的每一行最后一个点是亮的

你可以看取出来的数据,都0xFE.

但是你仿真的上面没有

GandF 发表于 2006-11-30 19:51:31

多谢楼主了!!

图片转换成数组成功!

转换过程:

将图片存为128*64的黑白BMP格式 -> 反色 -> 用UE编辑去掉前62(0x2e)个byte的BMP文件头,另存为BMP格式 -> 用bmp2txt.exe转换TXT格式数组

const unsigned char Bitmap PROGMEM={



有个问题:为什么转换出来1024个数组却只有1020个数值?

能不能调成每行显示16组数据?这样好看点。

xue110592 发表于 2006-12-9 16:19:31

是那种型号液晶,

wj414 发表于 2007-4-22 23:07:39

好东西,学习。

顶!!!


-----此内容被wj414于2007-04-22,23:09:35编辑过

yzlyear 发表于 2007-12-13 10:03:00

留个记号

jevenhuang 发表于 2007-12-17 16:44:22

好帖 做个记号 呵呵

Forever 发表于 2007-12-18 12:13:10

不错,记号个

xiaorenren 发表于 2007-12-19 20:39:17

点解再画竖线时,读回来的值不对。会有空格出现,是不是读函数有时间的限制?
读程序如下(TS12864):
51的:
unsigned char Read_Data(void) //读数据
{
   unsigned char adata1=0;

   //LCD_busy();
   //LCD_DATA=0XFF;
   DI=1;
   RW=1;
   
   EN=1;
   EN=0;
   EN=1;
   adata1=LCD_DATA;
   return adata1;
}

void putpixel(int x,int y)
{
    unsigned char py1,py2,adata0=0;
    py1=y/8;
    py2=y%8;
    if(x>=64) Sel_Right();   // left = 0:for right.
    else Sel_Left();   // left = 1:for left.
   
    Write_Cmad(py1 | 0xb8);
    Write_Cmad(x | 0x40);
   
    adata0=Read_Data();
    adata0|=(1<<py2);    //这个数据有问题
   
    Write_Cmad(py1 | 0xb8);
    Write_Cmad(x | 0x40);
    Write_Data(adata0);
}
画横线没什么问题,竖就会空格试了很多次了,有没有朋友遇到这种问题
或者画成功的指导下

depv 发表于 2008-1-15 10:38:47

Thanks

feiyue 发表于 2008-1-15 11:02:49

我用M16+LCM192*64,8M晶振,采取读两次的方式才能保证读LCM数据可靠!

HZZCL 发表于 2008-1-15 15:20:20

记号

calvinxxw 发表于 2008-3-18 10:44:56

好贴

abcdezh 发表于 2008-3-18 13:56:42

ding

steven 发表于 2008-3-18 14:43:36

mark and up!

heizi302 发表于 2008-3-19 08:13:47

好资料,支持楼主!

chenzelin 发表于 2008-8-23 13:29:25

谢了

mtxmxt 发表于 2008-8-23 19:53:35

谢谢楼主!

knight_avr 发表于 2008-8-23 21:16:39

mARK!

avr_appli 发表于 2008-8-24 08:05:19

mark

mc94078145 发表于 2009-3-16 21:08:31

mark

ouyangyong817 发表于 2009-3-25 21:58:50

MARK

senzh01 发表于 2009-3-25 22:16:16

很好的资料,谢谢楼上的各位!

chenzhipeng 发表于 2009-3-26 23:47:59

支持一下

huangjiyue 发表于 2009-3-27 13:53:51

标记下好好看看;不顶不行了;这么好的帖子!

zbs220 发表于 2009-3-27 16:43:48

mark

lin638 发表于 2009-3-27 21:48:12

我顶一下

ratrat 发表于 2009-3-27 21:51:26

谢谢

djl310 发表于 2009-3-30 09:17:10

jilu

naohbbq 发表于 2009-3-30 20:39:42

不错,记号

cu_ice 发表于 2009-3-30 21:24:08

MARK

xieshuangok 发表于 2009-3-30 21:54:18

标记!

deepin 发表于 2009-4-9 13:04:44

MARK
标记

zhaolj_kstar 发表于 2009-4-9 17:48:49

先收下了!

AAVVRR 发表于 2009-4-9 18:15:56

好的不行!很多书都是不负责地抄过来抄过去,像这样的细说比什么书都强!

tota2004 发表于 2009-4-29 09:57:12

顶下

toy2man 发表于 2009-5-13 20:02:52

没办法,只能顶了

tb8246 发表于 2009-5-13 22:59:08

雁过留痕

xqingfeng 发表于 2009-5-17 17:29:51

收下,谢谢!!

lanlanx 发表于 2009-5-18 02:32:38

mark,不错

ecat 发表于 2009-5-18 07:53:24

shengfeng 发表于 2009-5-19 19:00:07

mark

ts10606 发表于 2009-5-19 19:57:45

mark

suxing175 发表于 2009-5-19 21:26:22

标记

eydj2008 发表于 2009-5-23 16:39:29

GOOD 我正好学一下GCC 向前辈学习了

lgc-sdu 发表于 2009-7-12 10:57:48

ywwj5858792qd 发表于 2009-7-29 09:07:51

好帖啊!!!

lizhihuanok 发表于 2009-7-30 21:33:17

mark

apple3417 发表于 2009-8-3 18:44:18

帅气

derherstar 发表于 2009-8-4 15:21:16

三个点都画到同一行和同一列上试试看

chengyuwang 发表于 2009-9-20 11:13:26

顶顶顶

chengyuwang 发表于 2009-9-20 11:13:27

顶顶顶

chengyuwang 发表于 2009-9-20 11:13:29

顶顶顶

51hubao 发表于 2009-9-20 13:27:50

mark1

hyzqq 发表于 2009-10-17 17:52:41

最近正学12864液晶,仿楼主程序搭了一个电路(M8),发现根本不能工作(没有反应),换了三个不同的12864,查了硬件,学习了12864手册,仍不能显示。但仿真没问题。估计程序还是有问题的。
同样试了网上几个例子,发现许多程序也是仿真没问题,实际硬件使用不行。
不得已换了楼主的bool lcdBusy(void)函数,终于12864有反应了,但显示仍是一团糟。
不知是否有高手试过该程序,请指导一下!!!
多谢了!!!!!!

sange 发表于 2009-10-17 22:25:19

留个记号。。

super373 发表于 2009-10-18 18:44:37

mark
                    Oooo        

          oooO      (   )

          (   )      ) /

         \ (      (_/

            \_)

Dream_catcher 发表于 2009-11-30 02:16:39

mark

yunqian09 发表于 2009-11-30 09:53:50

mark

linjanbin 发表于 2009-12-3 09:27:47

读数据时有问题,在同一列会出现空格点啊,哪位能指出问题在哪里吗?谢谢了!

zengxy 发表于 2009-12-3 15:57:13

mark

kangkang 发表于 2009-12-3 20:23:23

mark!

eduhf_123 发表于 2009-12-3 21:23:35

MARK LCM驱动

wfbaaa 发表于 2009-12-4 11:46:17

顶一下,感谢分享

flyxiao 发表于 2009-12-18 16:45:54

好谢谢分享

gxy508 发表于 2009-12-18 20:34:38

mark

youpeng 发表于 2010-1-5 23:25:22

不得不顶!谢谢分享

youpeng 发表于 2010-1-5 23:29:29

mark,谢谢分享!

huohuansong 发表于 2010-1-6 00:09:03

mark

sunmy 发表于 2010-2-11 07:46:21

ding!

wugaohui04 发表于 2010-2-27 08:57:55

mark

thinki 发表于 2010-4-7 20:14:40

mark

xiaowangkanqiu 发表于 2010-4-8 08:59:23

mAKR

gxy508 发表于 2010-4-8 09:46:10

mark

wuliwb 发表于 2010-4-8 14:34:39

mark

fanbinhua 发表于 2010-11-7 16:27:31

mark

zxq200211 发表于 2010-11-11 16:37:58

收下,谢谢了!!

xxsc118 发表于 2010-12-14 21:57:10

学习了

dubu 发表于 2010-12-18 09:25:18

mark 12864

kandyblue 发表于 2011-3-26 19:12:44

回复【23楼】xiaorenren
-----------------------------------------------------------------------
void draw_dot(uint8 x,uint8 y)                //全屏画任意点 x:0~63 y:0~127
{
        uint8 dat,page,temp;
        page=x>>3;                                //计算所画的点在第几行(页)
        LCD12864_CS1_EN;
       
        if(y>63)                                //判断是否在右屏
       { LCD12864_CS2_EN; y=y-64;}
       LCD12864_wcmd(0xb8+page); //先读屏幕上第x/8行
       LCD12864_wcmd(0x40+y); //屏幕上第y列DRAM中的数据
       dat=LCD12864_rdata();       //读出所画点的所在行中数据
       LCD12864_wcmd(0x40+y); //屏幕上第y列DRAM中的数据
       dat=LCD12864_rdata();    //再读一次
       temp=1<<(x%8);
       dat=dat|temp;                        //将该行数据中该点的位置与1相或(即写1)
       LCD12864_wcmd(0x40+y); //读操作后列值会自动加一为了不产生一列的偏差将地写重新再写一次
              
       LCD12864_wdata(dat);
       
}   

我也出现过这样的问题 横着打点是连续的但是竖着打点是间隔的单步调试时发现下一次读出来的数据是上一次想要的 不知道为什么 然后我就试着连着再读了一次 然后再处理写进去 调试发现打点是连续的如果有人能解释一下为什么 不胜感激

kihell 发表于 2012-5-30 09:27:36

可以 不错不错

rickly_hzy 发表于 2012-8-31 19:40:25

初学者过来学习

hclin 发表于 2012-9-4 13:28:07

very good !
ding !!!

linucos 发表于 2012-9-4 13:33:44

多谢分享!

huaidan2088 发表于 2012-9-4 15:48:48

mark一下,先留着

584388726 发表于 2012-9-8 21:17:01

MARKMARKMARK
页: [1] 2
查看完整版本: 再论Atmega8L-LCD12864,带画点函数,希望对想学点阵液晶的朋友有所帮助。(注:GCC的)