整理菜鸟学习lcd编程的起步.docx

上传人:b****2 文档编号:13963367 上传时间:2023-06-19 格式:DOCX 页数:25 大小:28.54KB
下载 相关 举报
整理菜鸟学习lcd编程的起步.docx_第1页
第1页 / 共25页
整理菜鸟学习lcd编程的起步.docx_第2页
第2页 / 共25页
整理菜鸟学习lcd编程的起步.docx_第3页
第3页 / 共25页
整理菜鸟学习lcd编程的起步.docx_第4页
第4页 / 共25页
整理菜鸟学习lcd编程的起步.docx_第5页
第5页 / 共25页
整理菜鸟学习lcd编程的起步.docx_第6页
第6页 / 共25页
整理菜鸟学习lcd编程的起步.docx_第7页
第7页 / 共25页
整理菜鸟学习lcd编程的起步.docx_第8页
第8页 / 共25页
整理菜鸟学习lcd编程的起步.docx_第9页
第9页 / 共25页
整理菜鸟学习lcd编程的起步.docx_第10页
第10页 / 共25页
整理菜鸟学习lcd编程的起步.docx_第11页
第11页 / 共25页
整理菜鸟学习lcd编程的起步.docx_第12页
第12页 / 共25页
整理菜鸟学习lcd编程的起步.docx_第13页
第13页 / 共25页
整理菜鸟学习lcd编程的起步.docx_第14页
第14页 / 共25页
整理菜鸟学习lcd编程的起步.docx_第15页
第15页 / 共25页
整理菜鸟学习lcd编程的起步.docx_第16页
第16页 / 共25页
整理菜鸟学习lcd编程的起步.docx_第17页
第17页 / 共25页
整理菜鸟学习lcd编程的起步.docx_第18页
第18页 / 共25页
整理菜鸟学习lcd编程的起步.docx_第19页
第19页 / 共25页
整理菜鸟学习lcd编程的起步.docx_第20页
第20页 / 共25页
亲,该文档总共25页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

整理菜鸟学习lcd编程的起步.docx

《整理菜鸟学习lcd编程的起步.docx》由会员分享,可在线阅读,更多相关《整理菜鸟学习lcd编程的起步.docx(25页珍藏版)》请在冰点文库上搜索。

整理菜鸟学习lcd编程的起步.docx

整理菜鸟学习lcd编程的起步

 

(6)环境影响评价结论的科学性。

(6)评价结论。

首先再次声明我是菜鸟,我写出来的目的是给没有接触过lcd的朋友看得,我本人水平有限,错误在所难免,欢迎指出    

之所以产生写这个东西的想法,是因为趁着寒假这段时间看了看学习板的源程序,在看lcd的时候很不顺利,花了五个晚上才看完(白天偷懒了^_^!

,毕竟在春节嘛)。

联想起还有很多水平和我差不多甚至可能还低一点的菜鸟,就觉得有义务把五个晚上的学习心得写出来,顺便也给自己整理整理思路,嘿嘿。

这个心得是针对学习板上的lcd 驱动芯片SSD181X系列写的,当然思想应该是相通的。

其实是我没有用过其他系列lcd(众人呕吐ing……)。

首先你要去网上下载一个SSD181X系列的PDF文件,这种文件网上到处都是,偶就不多说了。

刚开始需要借用51论坛电子白菜大虾的文章作为总领,因为偶比较懒,不想写这么多拉~~~(不要飞鸡蛋……)当然还是有部分内容增加的拉。

我介绍的这个是MOTO的手机屏,大小为96*54(96列54行)。

不过这个小小的LCD屏也是很不错的。

对比度可调,而且还有背光:

)具体驱动器是:

SSD1815,是黑白点阵驱动芯片,最多支持132个SEG和64个COM,还有一个ICON(功能设置)行。

说起SEG,COM,也许很多人没接触过,其实玻璃屏的LCD都是使用SEG,COM的扫描来驱动的,为使需要点亮的内容呈显示状态,须将交流驱动电压加在LCD的段电极与公共电极之间。

原理涉及物理化学问题,这里就不多说,只打个比喻:

一个‘井’字,是两行两列组成的,共有四个交点,其实就好比是2个SEG,2个COM,要驱动一个固定的点,要相应的一条COM和一条SEG都有效如果要几个点亮,几个点灭,就需要用到扫描的原理,还记得行列键盘的原理吗?

其实它的驱动原理就差不多了:

    上面说的它支持132个SEG,64个COM,所以它支持最多132*64个点的LCD。

但实际上如果我们的LCD没有那么多个点话,就需要在上电的时候对1815进行初始化,指定COM和SEG的数目,还有BIAS数,说到BIAS,唉,又是个专业问题了,LCD的驱动波形由几级电平组成,为防止对比度不均匀,在不点亮象素对应的电极上仍加有一定电压,这对降低点亮象素产生 的交叉干扰和防止对比度不均匀很重要。

LCD中非点亮象素(非选点)的电压有效值与点亮象素(选择点)电压有效值之比(1/n)称为偏压比。

确实比较难以理解,你可以这样看:

BIAS是电平强度,和COM有关的东西。

以上这些都要在LCD上电的时候初始化好,才能正确地显示图文。

    1815还自带显示RAM,英文是Graphic Display Data Ram就是图象显示数据存储器,简称GDRAM。

对于现在很多现成的LCM屏来说,控制芯片都带有了GDRAM的,大小就和他的最大显示点数相当。

我估计你看到现在还是一头雾水,呵呵,没关系,当初我看的时候也是一头雾水,看到后面你就会明白他们的原理了。

    接着是1815的接口问题了,它支持8080,6800,I2C总线。

8080,就是和我们51一样的总线,有CS,WR,RD,然后是数据地址线;6800又叫摩托罗拉总线,有R/W,E,然后是地址数据线;I2C总线,呵呵,当然就是I2C总线咯,还用说么?

由于这个是摩托罗拉的LCD屏,出厂的时候已经配置为6800总线了,所以我们不能用正常的51总线来驱动,但实际上6800是可以兼容8080总线的,先等我介绍下这个总线吧:

    R/W脚:

读写脚,为1的时候是读,0的时候是写。

    E脚:

使能脚,功能如同51总线的CS,也是低有效的,但数据D0-D7在高的时候锁存。

    D/C脚,这个是数据,命令选择脚,1的时候代表总线传输的是数据(不论是读还是写),0的时候代表总线传输命令(不论是读还是写)。

    D0-D7:

理所当然的数据脚咯。

驱动原理很简单,在E为低的时候对R/W脚输入读写信号,读就是1,写就是0;然后选择你读写的是数据还是命令,D/C脚1为数据,0为命令;最后就是数据脚的数据了。

    以上原理,用单片机IO做是很简单的事情,不过使用IO的缺点就是不能复用,浪费了很多的资源,所以在学习板上是使用总线驱动LCD的。

之前说了,某些6800总线是可以用8080总线模拟的,而这个LCD就是可以使用8080总线的了。

6800总线读写控制只需要1只脚R/W,1为读0为写,而8080总线是两只脚RD,WR,其中的某个脚为低就对应响应功能。

根据这个逻辑关系,我们很容易就猜想到为什么6800的R/W脚可以直接接上8080的WR了。

这些都是垫场的开场白拉。

接下来我就以丁丁编写的1815的使用程序,来介绍使用1815驱动lcd的详细步骤。

为了让大家能够理解清楚,我绝对按照分段的形式,一段一段解释。

当然由于本菜鸟水平有限,如果解释错误还请大家不吝赐教。

开始的程序我会讲的很细,后面的我就讲个大概了,只要理解了这个过程就不难了。

注意哦,这个程序是来自"51单片机世界",作者版主丁丁(聂小猛),未经允许,不得抄袭作为商业用途。

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

#define uchar unsigned char

#define uint  unsigned int

#define ulong unsigned long

#include 

#include 

#include "study.h"

#define LCMD       XBYTE[0xAf00]           // 液晶数据口

#define LCMC       XBYTE[0xAb00]           // 液晶命令口

#define  LCD_DOT_X 98 // lcd 的宽点数

#define  LCD_DOT_Y 54 //lcd 的高点数

#define LCD_MAX_X 11 //每行字符, ( LCD_MAX_X +1 ) * 8 点

#define LCD_MAX_Y 5 //共多少行,( LCD_MAX_Y +1 ) * 8  点

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

如果你写过单片机程序,就会知道任何程序的初始化阶段都是这么些步骤,定义再定义,最后是某些功能的初始化函数。

这些就是刚开始的声明定义过程。

前面的几个define,include我就不多说了,如果你连这个都看不懂,只能先去补习补习c语言了。

#define LCMD       XBYTE[0xAf00]和#define LCMC XBYTE[0xAb00]两句是用来定义外部总线接口地址的。

0xAf00用来传递数据,0xAb00用来传递命令,之前说过,是传输命令还是数据主要是取决于A10的,上面两个地址对应的A10其实就是0xaf00->A10=1,0xab00->A10=0。

照电子白菜大虾的话说,地址的取值只要确保在A000~AFFF 之间就可以了,所以以下定义一样能正确驱动LCD:

    #define LCMD XBYTE[0xA400] // 液晶数据口

    #define LCMC XBYTE[0xA000] // 液晶命令口

    虽然地址不同了,但对A10的作用依然不变。

接下来的两句则是用LCD_DOT_X来表示lcd 的宽点数,LCD_DOT_Y表示高点数。

想象坐标轴,呵呵,是不是好理解了?

这就说明我们现在用的lcd是LCD_DOT_X宽LCD_DOT_Y高的。

最后两句则是告诉我们,这个lcd可以显示5行,每行11个字符。

这些参数都是可以根据lcd不同而变化的。

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

struct cursortype

{

   uchar x;

   uchar y;

};

struct cursortype cursor;

void wridata(uchar ch)

{

       LCMD=ch;

}

void wricmd(uchar ch)

{

       LCMC=ch;

}

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

这几句也都属于初始化步骤。

首先struct cursortype这个结构体是用来定义光标的,光标在屏幕上当然可以用x和y两个值表示,这样我们到时候用cursor.x或者 cursor.y确定光标位置就方便多了。

Wridata和 wricmd两个函数则是写数据和写命令功能。

仔细看,LCMD就是液晶数据口,LCMC就是液晶命令口,我们对他们进行的操作实际上就是对0xAf00或0xA000地址进行操作。

例如我们用wridata(0x33),也就是说我们把0x33这个数据通过0xAf00这个外部总线接口地址送到SSD181X中。

由于是0xAf00的地址,A10必然为1,控制器就知道此时你要传递的是数据拉~怎么样?

很方便吧。

void light(uchar n)

{

       LCMC=0x81;

       LCMC=n;

}

把这个程序单独列出来是因为想讲讲程序如何传递能够作用的有效参数。

首先这是一个调节lcd亮度(其实更加严格得说是对比度)的函数。

我们看到他用的LCMC,说明此时我们是发送程序给lcd,让他知道我们要调整亮度了。

那么究竟传递什么东西,控制器才能知道我们的意图呢?

不用担心,pdf上会告诉你按什么格式发送指令给控制器才有效。

这是SSD181X pdf上面的格式之一:

为了方便我只截取其中一个功能设置来进行说明。

最左边的数字表示你发送的命令必须是这样的格式,中间的英文表示该格式命令所起的作用,右边的文字表示这些XXXX,也就是不确定数字的值该如何选取才能获得我们想要的效果。

就以这个方框为例吧,首先我们看中间这个小方框,它告诉我们这条指令的作用是设置对比度寄存器,也就是说我们可以通过对该寄存器的修改来实现调节对比度得调整。

那么具体如何调整呢?

我们再来看看最左边的方框,这个内容告诉我们,我们需要用LCMC发送两个字节数据,其中一个字节是固定的10000001就是0x81,第二个字节则是自己决定。

怎么决定呢?

再看看第三个小方框吧。

如果你e文好,马上就能看懂它的意思。

如果你e文不好……嘿嘿,建议金山词霸!

(倒,谁扔的香蕉皮?

?

?

?

!

这里的意思就是说,对比度分为64个等级,这样XXXXXX6位二进制数就可以表示完,那么我们需要用哪个等级就设置哪个数,比如现在我们需要等级n的对比度,因此程序中出现了LCMC=n。

这个n哪里来的?

void light(uchar n),嘿嘿,主函数传递进来的。

呵呵,现在明白命令是怎么传送的了吧?

一会儿还有例子,如果不明白不要慌张。

  

 

(三)环境影响评价的原则

建设项目所处环境的敏感性质和敏感程度是确定建设项目环境影响评价类别的重要依据,环境影响评价文件应当就该项目对环境的影响做重点分析。

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

void cls(uchar ch)

{

       uchar i,j;

       for(j=0x0;j

       {

              

              wricmd(0xb0+j);//set page   //1011xxxx 

              wricmd(0x10);//set column msb

              wricmd(0x0);//set column lsb

              wricmd(0xe0);//set modify-read mode

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

              {

                     

                     wridata(0x00);  //填满0即清屏

        }

              wricmd(0xee);//reset modify-read mode

       }

}

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

这里就开始进入实质性的编程部分了。

这是一个清屏函数,传递的参数ch=9就表示连带ICON一起清除,如果ch=8则表示不清除ICON。

这里的ch实质上表示GDDRAM中的page页面值。

这里有点难以理解。

先看看GDDRAM是怎么构成的。

这是pdf中关于GDDRAM地址分布图的说明,我们可以从这里清晰看到page的概念:

一个page实际上是一个拥有8个高点的行,64点高的屏幕就有8个page,每个page的宽度都是和整个RAM宽度是一样的。

从pdf的最开始我们就可以看到1815的特性是132×64+1 icon line,也就是说高为64,换算过来就是8个page。

而GDDRAM的数据分布图与lcd实际的数据显示图是完全一致的,实际上lcd的显示的就是GDDRAM的映射。

因此我们清屏的目的就是为了清除GDDRAM中的值。

因此从for(j=0x0;j语句中我们得知,循环次数是由ch决定的。

如果ch=8,那么循环8次,就只能清除这8个page(页面)。

只有ch=9,才能清除最后的那一个1 icon line。

好,我们接着往下看。

进入循环之后,程序要做的事就是一个page一个page得清除信息。

首先wricmd(0xb0+j),翻翻pdf,找到相关信息:

这下知道了,这个语句的意思就是选择要进行读写操作的页面。

因为总共只有8个页面,所以4个不确定位就够拉。

这也就是wricmd() 的参数是“0xb0+j”的原因:

page数只由j,也就是ch控制。

接下来两句wricmd(0x10)和wricmd(0x0),我们同样可以通过pdf的信息得知,作用时用来设置列的低地址和列的高地址。

参数高四位为0001的表示设置高地址,0000的表示设置低地址。

默认情况下高低地址均为0X0000。

接下来就是设置工作模式wricmd(0xe0)。

这个语句的作用是set read-modify-read mode,就是设置成读-改-写模式。

最后把本次循环我们选择的page填0,也就达到了请零的目的。

需要注意的是I的范围是0-97,为什么?

因为我们现在举例用的lcd宽点数只有98。

wridata(0x00)的作用是把某一列写入0。

没想到吧?

呵呵,因为液晶上一个字节的显示是竖的一排排的,存储在GDDRAM中当然也是竖着拉~也就是一列代表一个字节8位^_^。

刚才我们把工作模式设置为读-改-写,现在当然要结束这个模式拉,这就是wricmd(0xee)这个语句所起的作用。

最后继续循环。

Cls的工作就完成了~

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

show_asc(uchar ch);

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

//初始化液晶

uchar lcdlight=32; 

void initlcd(void)

{   P2=0x00;     //P2作为总线时,其寄存器的值对总线没有影响。

                 //初始化为0,是为了更好的配合液晶的6800总线。

motorola的液晶内部固定了6800总线方式。

                             //如果液晶是8080总线,则无需这样做。

     

       wricmd(0x2f);//SET POWER CONTROL,开启一系列与电源有关的功能

       wricmd(0x20);//REGULATOR RESISTOR SELECT,内部反馈增益最小

       wricmd(0x81);

       wricmd(lcdlight);设置对比度值

       wricmd(0x40);//设置初始显示线,从哪里开始是玻璃上的布线决定的

       wricmd(0xa0);//ADC=0(SEG1~SEG132) 

       wricmd(0xc8);//SHL=0(COM1~COM64) 

       wricmd(0xa2);//设置LCD BIAS为1/9

       cls(9);//全部清除,包括icon

       wricmd(0xaf);//开启显示,也就是把GDRAM上的数值显示到屏上

       setcursor(0,0);//设置光标到左上角

}

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

到这里,就正是进入我们的初始化了。

什么?

弄了半天你还没有讲初始化啊?

各位看官不要着急,此初始化非彼初始化也。

刚才我们讲的都是整个程序的初始化,而现在我们进入的是液晶屏的初始化。

让我们看看这个过程吧。

首先是uchar lcdlight=32,顾名思义,这个参数的作用就是调节lcd对比度的拉。

motorola的液晶默认对比度为32。

先让lcdlight=32,到时候利用wricmd函数,直接一个wricmd(lcdlight)语句,多方便~^_^。

闲话少说,接着往下看。

下面是一个initlcd函数,这是可是如假包换的液晶初始化函数。

液晶在每次上电使用都需要初始化,而大多数初始化程序我们都可以不去理会,因为那些都是按照说明书所说的,用于设置COM数和SEG数还有BIAS值的。

这里再解释一下P2=0x00;的作用。

开始的时候我们就说过,这个液晶使用的是6800总线,这段,其实是为了兼容6800总线加上的,LCD的D/C脚在一开始的时候应该设为0,也就是写成:

P22=0;就可以了,P22就是接到LCD的D/C脚上的。

另外再提醒一点,一些必须的值,如COM,SEG,BIAS,显示模式等,在使用中这些设置用户是不应该改变的。

到这里,LCD初始化正式完成,已经可以供用户正常使用了。

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

show_asc(uchar ch)

{

       uint addr;

       uchar hzdata[16];

       uchar xdot,i;

       addr=16*ch;  

       readeprom(addr,hzdata,16); //读出16个字节的点阵数据

       xdot=cursor.x*8;                  

       wricmd(0xb0+cursor.y);    //将y位置送入液晶

       wricmd(xdot & 0x0f);          //将x位置送入液晶

       wricmd( 0x10 | (xdot >> 4 ));   

       wricmd(0xe0);

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

       {

              wridata(hzdata[i]);                //写上半个字符

       }

       wricmd(0xee);

       wricmd(0xb0+cursor.y+1); 

       wricmd(xdot & 0x0f);

       wricmd(0x10 | (xdot >> 4 ));   

       wricmd(0xe0);

       for(;i<16;i++)                      //写下半个字符

       {

              wridata(hzdata[i]);

       }

       wricmd(0xee);

}

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

要理解这段程序,必须先知道点阵表示的含义。

我们知道,字母和汉字是按字模位信息显示的,那如何得到汉字的字模信息呢?

难道要我们自己去做?

NO。

DOS前辈们经过艰辛的努力,将制作好的字模放到了一个个标准的库中以免去后辈的麻烦,这就是点阵字库文件。

一般我们使用16*16的点阵宋体字库,所谓16*16,是每一个汉字在纵、横各16点的区域内显示的,前一个16表示列,后一个十六表示行。

不过后来又有了HZK12、HZK24,HZK32和HZK48字库及黑体、楷体和隶书字库。

这段程序是用来在当前光标位置显示一个6×12 点阵的ASC码字符的。

其实标准的ASC码字符应该是8×16点阵区域表示,这也就是为什么我们常说“一个汉字占据两个字符位”的原因。

Ch表示的是asc字符的值。

首先说明一点,一个ASC字符分两部分显示,也就是说,把分为上下两个“半ASC码字符”。

汉字同样应该如此显示。

当然这只是我们目前介绍的这个lcd的特性。

如果你使用的是别的种类,千万不要生搬硬套,一定要仔细阅读说明书。

再回头看程序。

首先就是一堆定义,无符号整形数addr表示的是点阵在flash中的物理位置,表示ASC码字符‘1’的字符点阵占据的物理位置是0-15。

为什么?

你看,16*8点阵区域,一个点用1bit表示,‘0’就是灭,‘1’就是亮,那么总共128bit,是不是就是16byte?

同理,字符‘2’是16-30,以此类推。

所以addr=16*ch。

比如我传递进来的ch是4,则addr为64。

而hzdata这个数组是用来存储读出的数据的。

Xdot表示的是横向点位置,在下面我们可以知道它的计算公式是cursor.x*8,就是光标横坐标值乘以8。

由于之前我们将光标设置在左上角,所以cursor.x为0,因此此时横向点位置也为0。

如果我们已经显示了一个ASC字符,此时的cursor.x就应该为1,那么xdot就应该为8:

这应该很好理解,从点阵区域的大小我们可以知道一个ASC码字符从横坐标上看占用的是8个点(0-7),下一个ASC码字符当然应该从8开始拉。

接下来是readeprom(addr,hzdata,16)这个函数。

什么意思呢?

由于它是属于另外一个.c文件,

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

当前位置:首页 > 考试认证 > 公务员考试

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2