LCD12864的驱动.docx

上传人:b****7 文档编号:26122219 上传时间:2023-06-17 格式:DOCX 页数:30 大小:666.56KB
下载 相关 举报
LCD12864的驱动.docx_第1页
第1页 / 共30页
LCD12864的驱动.docx_第2页
第2页 / 共30页
LCD12864的驱动.docx_第3页
第3页 / 共30页
LCD12864的驱动.docx_第4页
第4页 / 共30页
LCD12864的驱动.docx_第5页
第5页 / 共30页
点击查看更多>>
下载资源
资源描述

LCD12864的驱动.docx

《LCD12864的驱动.docx》由会员分享,可在线阅读,更多相关《LCD12864的驱动.docx(30页珍藏版)》请在冰豆网上搜索。

LCD12864的驱动.docx

LCD12864的驱动

LCD12864驱动

LCD12864在市面上主要分为两种,一种是采用st7920控制器的,它一般带有中文字库字模,价格略高一点。

另一种是采用KS0108控制器,它只是点阵模式,不带字库。

很可惜,我的这块就是KS0108控制器不带汉字库的,不过不打算用它专门显示文本,也就无所谓了。

LCD12864模块的20个引脚定义如下:

1。

Vss     逻辑电源地

2。

VDD 逻辑电源正 5v

3。

V0  LCD驱动电压

4。

RS  数据/指令选择:

高电平为数据,低电平为指令

5。

R/W 读/写选择:

高电平为读数据,低电平为写数据

6。

E  读写使能,高电平有效,下降沿锁定数据

7。

DB0 数据输入输出引脚

8。

DB1 数据输入输出引脚

9。

DB2 数据输入输出引脚

10。

DB3 数据输入输出引脚

11。

DB4 数据输入输出引脚

12。

DB5 数据输入输出引脚

13。

DB6 数据输入输出引脚

14。

DB7 数据输入输出引脚

15。

CS1 片选择号,低电平时选择前64列

16。

CS2 片选择号,低电平时选择后64列

17。

RET 复位信号,低电平有效。

18。

VEE 输出-15v电源给V0提供驱动电源

19。

A  背光电源LED正极

20。

K  背光电源LED负极

具体电路图如下:

制做如下:

接口说明:

装上12864

具体的电路还是两个电阻。

一个背光限流电阻。

一个液晶驱动电压调节电阻。

背光电阻还是任何时候在19、20脚与电源之间串上个100欧电位器接上电源。

调节电位器到合适亮度。

具体值最好是到调试完程序能够正常显示后再将阻值确定换成固定电阻。

液晶驱动电压的调整在数据线、电源线接好的前提下是在Vee(-15v)和地之间接一个电位器。

中间接V0,通过调节电位器来调节V0上的电压。

当V0上为-15V时为全暗(液晶显示为全黑)。

当V0为0V时为全亮。

调节电位器使屏幕从全暗刚好变到亮时,便可进行程序的调试。

待屏幕显示正常后,进行对比度的细调,然后测量这两边的阻值在地和V0之间、V0和Vee之间换成两个固定电阻焊上就好了。

注意在V0的电压是在一个很小的范围有效。

我的就是在-2.2——-2.5这个范围。

仔细调节V0和地之间的电阻使V0上的电压在2.3V。

更换为固定电阻后的装配图:

下面说说具体的驱动:

先来了解一下LCD12864的内部控制结构:

见图

可以看出12864屏是分为左、右两块控制的。

所有对屏幕的操作要受片选CS1、CS2来控制。

我们再来看一看对屏幕操作数据与屏幕点阵的排布关系:

见下图。

从上图可以看出数据按字节在屏幕上是竖向排列的。

上方为低位,下方为高位。

因此在横向上(也就是Y)就一共是128列数据。

分为CS1和CS2两个64列来写入。

在竖方向上(也就是X)一字节数据显示8个点,竖向64个点分为8个字节,称做8页(X=0-7)。

了解这些后我们就知道要满屏显示一张图就要从y=0…127、X=0…7一共写128×8=1024个字节的数据。

同样在AT89S51中存一张图就要1024个字节的空间。

好!

下面我们来了解对LCD12864进行操作的一些指令。

下面对上图的指作解释:

1.显示开关控制(DISPLAYON/OFF)

D=1:

开显示(DISPLAYON)   意即显示器可以进行各种显示操作

D=0:

关显示(DISPLAYOFF)意即不能对显示器进行各种显示操作

                 

2.设置显示起始行(DISPLAYSTARTLINE)

   前面在Z地址计数器一节已经描述了显示起始行是由Z地址计数器控制的。

A5~A0   6位地址自动送入Z地址计数器,起始行的地址可以是0~63的任意一行。

例如:

选择A5~A0是62,则起始行与DDRAM行的对应关系如下:

DDRAM行:

6263   0   1   2   3·················2829

屏幕显示行:

1   2   3    4   5   6·················3132

3.设置页地址(SETPAGE“XADDRESS”)

所谓页地址就是DDRAM的行地址,8行为一页,模块共64行即8页,A2~A0表示0~7页。

读写数据对地址没有影响,页地址由本指令或RST信号改变复位后页地址为0。

页地址与DDRAM的对应关系见DDRAM地址表。

4.设置Y地址(SETYADDRESS)

    此指令的作用是将A5~A0送入Y地址计数器,作为DDRAM的Y地址指针。

在对DDRAM进行读写操作后,Y地址指针自动加1,指向下一个DDRAM单元。

5.读状态(STATUSREAD)

     当R/W=1   D/I=0时,在E信号为“H”的作用下,状态分别输出到数据总线(DB7~DB0)的相应位。

BF:

      前面已叙述过(见BF标志位一节)。

ON/OFF:

表示DFF触发器的状态(见DFF触发器一节)。

RST:

     RST=1表示内部正在初始化,此时组件不接受任何指令和数据。

6.写显示数据(WRITEDISPLAYDATE)  

   D7~D0为显示数据,此指令把D7~D0写入相应的DDRAM单元,Y地址指针自动加1。

7.读显示数据(READDISPLAYDATE)  

   此指令把DDRAM的内容D7~D0读到数据总线DB7~DB0,Y地址指针自动加1。

再帖一下接口时序图

1.写操作时序

2.读操作时序

时序参数表:

又帖了这么多指令呀时序图什么的,看了就头晕。

我也和你一样不爱看这些枯燥的东西。

下面实际写些程序让屏幕亮起来。

运行:

今天将LCD12864的源代码发上来。

//LCD12864

//**********************************************************

//连线表:

CPU=89C51   SysClock=12MHz                    *

//RS=P1.0  R/W=P1.1   E=P1.2   CS1=P1.3   CS2=P1.4    *

//DB0-DB7=P0.0-P0.7      /Reset=InBoard                  *

//**********************************************************

#include

#include

#include

#include

#include

#defineucharunsignedchar

#defineuintunsignedint

/********************引脚定义********************/

#defineDataPortP3    //LCD128*64I/O信号管脚

sbit   RS=P2^0;     //数据指令

sbit   RW=P2^1;     //读写

sbit   E  =P2^2;     //使能

sbit   CSL=P2^3;     //左片选

sbit   CSR=P2^4;     //右片选

ucharPage;            //页地址

ucharCol;             //列地址

ucharcodeBMP1[];     //一幅图

ucharcodeHZK_12[];   //12×12阵点字模

ucharcodeASC_5x7[];  //5×7阵点字模

ucharstr[4];

/********************函数定义*******************/

voidBusyL(void);         //左屏检测忙

voidBusyR(void);         //右屏检测忙

voidCheckBusy(void);     //读取忙信号

voidDelay(uintMS);      //延时

voidLocatexy(void);      //将屏幕横向0-12纵向0-7转换成左、右屏的的X、Y

voidWriteCommandL(ucharCommandByte);   //向左屏写入指令

voidWriteCommandR(ucharCommandByte);   //向右屏写入指令

ucharReadData(void);      //读数据

voidWriteData(ucharDataByte);   //写数据

voidLcmClear(void);      //清屏

voidLcmInit(void);       //初始化

voidLcmPutBMP(uchar*puts);     //显示一幅图

voidLcmReverseBMP(void);        //将整屏反显

voidLcmPutHZ_12(ucharx,uchary,ucharHZcode);//在屏幕上任意点显示一个12×12汉字

uchar*uchartostr(unsignedcharunm);           //将值转成字符串

voidLcmPutAsc(ucharasc);    //显示一个5×7的ASC字符

voidLcmPutstr(ucharrow,uchary,uchar*str);      //在设定位置显示字符串

voidLcmPutpoint(ucharro,ucharlie,ucharcolour);  //在设定位置显示一个点

/***************************/

/*检查Busy                */

/***************************/

voidBusyL(void)

{

       CSL=1;

       CSR=0;

       CheckBusy();

}

voidBusyR(void)

{

       CSL=0;

       CSR=1;

       CheckBusy();

}

voidCheckBusy(void)

{

       RS=0;        //指令

       RW=1;

DataPort=0xFF;     //输出0xff以便读取正确

       E=1;

       _nop_();

       while(0); //DataPort&0x80);   //StatusReadBit7=BUSY 这地方有点问题,用了while(//DataPort&0x80)后就一直读不到0了,陷入死循环。

当用while(0) 时反而能正常工作,不知道有没有人能解释       

       E=0;

       _nop_();

}

/********************************************************/

/*根据设定的坐标数据,定位LCM上的下一个操作单元位置    */

/********************************************************/

voidLocatexy(void)

{

       ucharx,y;

       switch(Col&0xc0)      /*col.and.0xC0       */

       {                      /*条件分支执行         */

               case0:

        {BusyL();break;}/*左区*/

               case0x40:

     {BusyR();break;}/*右区*/

       }

       x=Col&0x3F|0x40;     /*col.and.0x3f.or.SetYAddress*/

       y=Page&0x07|0xB8;    /*row.and.0x07.or.setPage    */

       CheckBusy();               /*waittingforenable*/

       RS=0;                //指令

       RW=0;                //写

       DataPort=y;                //设置页面地址

       E=1;

       _nop_();

       E=0;

       _nop_();

       CheckBusy();               /*waittingforenable*/

       RS=0;

       RW=0;

       DataPort=x;                //设置列地址

       E=1;

       _nop_();

       E=0;

       _nop_();

}

/***************************/

/*写指令                  */

/***************************/

voidWriteCommandL(ucharCommandByte)

{

       BusyL();

       DataPort=CommandByte;

       RS=0;        //指令

       RW=0;

       E=1;

       _nop_();

       E=0;

       _nop_();

}

voidWriteCommandR(ucharCommandByte)

{

       BusyR();

       DataPort=CommandByte;

       RS=0;        //指令

       RW=0;

       E=1;

       _nop_();

       E=0;

       _nop_();

}

/***************************/

/*读数据                  */

/***************************/

ucharReadData(void)

{

       ucharDataByte;

       Locatexy();    /*坐标定位,返回时保留分区状态不变     */

       RS=1;        /*数据输出*/

       RW=1;        /*读入*/

       DataPort=0xFF;             //输出0xff以便读取正确

       E=1;        /*读入到LCM*/

       _nop_();

       DataByte=DataPort;/*数据读出到数据口P1*/

       E=0;

       _nop_();

       returnDataByte;

}

/***************************/

/*写数据                  */

/***************************/

voidWriteData(ucharDataByte)

{

       Locatexy();    /*坐标定位,返回时保留分区状态不变     */

       RS=1;        /*数据输出*/

       RW=0;        /*写输出*/

       DataPort=DataByte;/*数据输出到数据口*/

       E=1;        /*写入到LCM*/

       _nop_();

       E=0;

       _nop_();

}

voidLcmClear(void)

{

       Page=0;

       Col=0;

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

               for(Col=0;Col<128;Col++)

                       WriteData(0);

}

voidLcmInit(void)

{

   Delay(200);    //等待复位

       WriteCommandL(0x3f);   //开显示

       WriteCommandR(0x3f);

       

       WriteCommandL(0xc0);   //设置起始地址=0

       WriteCommandR(0xc0);

       WriteCommandL(0x3f);   //开显示

       WriteCommandR(0x3f);

       LcmClear();

       Col=0;

       Page=0;

       Locatexy();

}

voidLcmPutBMP(uchar*puts)

{

       uintX=0;

       Page=0;

       Col=0;

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

       {

               for(Col=0;Col<128;Col++)

               {

                       WriteData(puts[X]);

                       X++;

               }

       }

}

voidLcmReverseBMP(void)

{

       uchartemp;

       Page=0;

       Col=0;

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

       {

               for(Col=0;Col<128;Col++)

               {

                       temp=ReadData();     //空读一次

                       temp=ReadData();

                       temp=~temp;

                       WriteData(temp);

               }

       }

}

voidLcmPutHZ_12(ucharx,uchary,ucharHZcode)

{     

  ucharoffset,Rd,Wt,m,tmp,i;

  uintn;

  if(x<117&y<53)//x为横向起始点数0-117,超过117就显示不全一个汉字了。

y同理。

   {

   Page=(y&0x38)>>3;//将竖向的点阵数y转换成页数

  Col=x;               //横向的X就是LCD的列数。

     n=0x18*HZcode;  //一个汉字24字节(18H),HZcode为字库序号。

n就是要显示汉字的起始地址

  offset=y&0x07;    //将显示该页的竖向偏移量。

  if(offset<5)         //如果偏移量小于5,那么在竖向用两个页的范围就可显示出汉字了。

  {

            for(i=12;i>0;i--)

             {

                Rd=ReadData();

      Rd=ReadData();           //读出LCD该Page、Col位置的上半个数据。

      m=HZK_12[n];             //读出汉字模第n的数据。

            Wt=Rd&(0xff>>(8-offset))|(m<

                WriteData(Wt);    //再将Wt写回LCD

        Page++;   //页位置移到下半个汉字位置

        n++;

        tmp=m;   //将取得的上半个字模数据交给tmp

        m=HZK_12[n];  //取下半个字模数据

        Rd=ReadData();//读LCD下半个字模数据

      Rd=ReadData();

        Wt=tmp>>(8-offset)|(m<

                WriteData(Wt);//再写回LCD

                Col++;//列数增加一

                Page--;//将页数返回上半个汉字位置。

      n++;

     }

  }

  else     //如果偏移量大于或等于5,竖向就要用3个页的范围来显示一个汉字了。

  {

      for(i=12;i>0;i--)

                {

                  Rd=ReadData();

      Rd=ReadData();     //读取LCD上汉字上部位置的原来数据。

          m=HZK_12[

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 医药卫生 > 基础医学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1