本帖最后由 zhangjw258 于 2018-3-16 20:53 编辑
LCD12864液晶显示器的并行驱动
一、概述
我手里这块LCD12864液晶显示器型号是HJ12864ZW。它主要由行驱动器/列驱动器(图2中的3个黑块U1/U2/U3)及128×64全点阵液晶显示器组成。可完成图形显示,也可以显示8×4个16×16点阵大小的汉字。LCD 12864是一种图形点阵显示器,并且带有汉字库,可以很方便的显示汉字,也可以显示二值图片。我这块LCD12864的主控芯片是ST7920。另外还有一种LCD12864的主控芯片是KS0108,它只有点阵模式,不带汉字库,并且它的屏的分布方式是左右分布的,数据字节的排列方式也与本文所讲的ST7920控制器的LCD 12864不一样。有兴趣的朋友可以找来资料比较一下。先来看看它的样子(如图1):
图1
背面(如图2):
图2
在这里只研究它的并行驱动方式,因此下面的引脚定义完全是按照并行驱动方式而定义的。LCD 12864还可以进行串行驱动,引脚定义与此有些不同,串行驱动可以占用非常少的MCU资源,当然,速度会比并行驱动方式要慢一些。我将在下一篇**里讲一下LCD12864的串行驱动方法。
引脚号 名称 说明 引脚号 名称 说明
1 VSS 电源地 11 DB4 数据端口
2 VDD 电源5V 12 DB5 数据端口
3 VO LCD驱动电压 13 DB6 数据端口
4 RS 命令/数据 14 DB7 数据端口
5 RW 读/写 15 PSB 串(0V)/并(5V)口选择
6 E 使能 16 NC 无连接
7 DB0 数据端口 17 RST 复位(低电平有效)
8 DB1 数据端口 18 VOUT 倍压输出脚
9 DB2 数据端口 19 BLA 背光电源5V
10 DB3 数据端口 20 BLK 背光电源地
说明:
1.使用并口方式时,PSB接VDD。特别地,选择并口方式后,根据下文中的功能设定指令中DL标志的不同,有8位并口方式(DL=1)和4位并口方式(DL=0)。8位并口方式使用DB0……DB7数据口;4位并口方式使用DB4……DB7数据口。
2.使用串口驱动方式时,PSB接VSS,DB0……DB7悬空不接。
3.串并口选择方式:除接口第15脚(PSB)外。也可使用P S焊盘点(见图2)选择并口/串口。中间与右部焊盘短路,串口控制方式;中间与左部焊盘短路,并口控制方式。
二、时序
1.并行传输方式
当PSB脚接高电平时,模块将进入并口模式。在并口模式下,可以由下文中的指令中的DL标志来选择8位接口或4位接口。主控制系统将配合(RS、RW、E、DB0……DB7)来达成传输动作。从一个完整的流程看,当设定地址指令后(CGRAM、DDRAM),若要读取数据时需先DUMMY READ一次,才会读取到正确数据。第二次读取时则不需DUMMY READ,除非又执行设定地址指令才需再次DUMMY READ。在4位传输模式中,每一个8位的指令或数据都将被分为两个字节动作:较高4位(DB7—DB4)的资料将会被放在第一个字节(DB7—DB4)部分;而较低4位(DB3—DB0)的资料则会被放在第二个字节的(DB7—DB4)部分。至于相关的另4位则在4位传输模式中DB3—DB0接口未使用。
这是8位并行模式数据传输的时序图(如图3)
图3
这是4位并行模式数据传输的时序图(如图4)
图4
2.时序图
(1)向液晶模块写数据(如图5)
图5
(2)从液晶模块读数据(如图6)
图6
3.串行传输方式
当PSB脚接低电平时,模块进入串行传输模式。在串行传输模式中,单片机与液晶模块间传送1字节的数据需要24个时钟脉冲。首先,单片机要给出数据传输起始位,这里是5个连续的“1”作数据起始位。如模块接到5个“1”,则内部传输被重置并且串行传输将被同步。紧接着,“RW”位用于选择数据的传输方向(读或写),“RS”位用于选择内部数据寄存器或指令寄存器,最后的第8位固定为“0”。在接收到起始位及“RW”,“RS”和“0”的第一个字节后,下一个字节的数据或指令将被分为2个字节来串行传送或接收。数据或指令的高4位,被放在第2个字节串行数据的高4位,其低4位将置为“0”;数据或指令的低4位被放在第3个字节的高4位,其低4位也置为“0”。如此完成一个字节指令或数据的传送。需要注意的是,当有多个数据或指令要传送时,必须要等到一个指令完全执行完毕后再传送下一个指令或数据。否则,会造成指令或数据的丢失。这是因为液晶模块内部没有发送/接收缓冲区 (如图7所示) 。
图7
4.串行接口时序图(如图8所示)
图8
在这里要补充一下,串行传输的接口连接方式。LCD12864串行传输只需要3条引脚线:分别是第4脚片选“CS”、第5脚串行数据输入“SID”和第6脚串行时钟信号“SCLK”。在串行接口方式中DB0……DB7悬空不接。其余引脚连接方式同并行模式相同(除PSB接地)。
三、电路与内部资源
下面给出我的8位并行连接模式的电路图(如图9所示)。
图9
说明:
(1)ST7920内带倍压电路,生成2倍于VCC的电压。倍压通过VOUT脚(18脚)引出,通过电位器调节后,从VO(3脚)引回模块用来驱动LCD。直接驱动LCD的是VO,VO电压越高,对比度越深。通过调节电位器来调节VO值以改变对比度。某些模块没有VOUT脚。VOUT电压直接通过降压处理供给VO。对比度已经锁定。如果一定要调节对比度,可以通过VO对地接一可调电阻,拉低VO值。我们这个模块在出厂时已经调节好对比度,所以第3脚和第18脚可以悬空不接。如果对现在的对比度不满意,可以用一把小螺丝刀调节模块背后的电位器VR1(如图2)。
(2)因为是并行传输模式,因此,PSB直接与VCC相连。
(3)其余引脚连接方式如图9所示。
下面看看ST7920的内部资源:
A.ST7920内部固化了8192个16×16点阵的中文字型在CGROM里。
B.固化有126个16×8点阵的西文字符在HCGROM里。
C.提供4个16×16点阵自定义字符的存储空间CGRAM。
D.提供128×64的点阵绘图共1024个字节的存储空间GDRAM。
E.提供1个16×15点阵图标的存储空间IRAM(ICON RAM)。
四、显示
1.字符显示
将准备显示的西文或中文字符代码写入DDRAM即可。不同的是1个西文字符占一个字节,而1个中文字符占2个字节。字符显示时,DDRAM与液晶屏对应关系(如图10所示)。
图10
从这个图可以看出,第一行到87H完了以后就跳到了第三行接着88H了。第二行也是一样,很明显,有下面两行接在上面两行后面的迹象。如图11。
图11
2.下面来看看GDRAM图形显示与液晶屏的对应关系(如图12)
图12
从图12我们可以看出:ST7920的LCD12864在地址的排列上是分为上、下半屏来显示的。上半屏横向的列地址(X)是0—7(00h—07h),下半屏的列地址是8—15(08h—0fh)。而每一个地址都可写入两个字节的内容,它们是按高位在前低位在后排列的。垂直方向上的地址(Y)上半屏是0—31(00h—1fh),下半屏Y地址仍是0—31(00h—1fh)。可以看出,它的地址排列方式还是将下半屏接在上半屏后面的,因此这块LCD12864,虽然在点阵的物理排列上是128×64,但在地址排列上,它却是块256×32。
3.下面我们来介绍能够使用的指令(如图13所示):
图13
五、程序
说了这么多,终于到了写程序的时候了。程序要实现的功能是:先在屏幕上显示4行文字,延时一会,接着显示某品牌的**。在这里,我只使用了一些简单的指令,LCD12864有很多指令和功能,有兴趣的话,可以进一步学习。
// 文件zhangtype.h
#ifndef __ZHANGTYPE_H__
#define __ZHANGTYPE_H__
#define uint8 unsigned char
#define uint16 unsigned short int
#define uint32 unsigned long int
#define int8 signed char
#define int16 signed short int
#define int32 signed long int
#define uint64 unsigned long long int
#define int64 signed long long int
#endif
// 文件fun.h
#ifndef __FUN_H__
#define __FUN_H__
#include "ZhangType.h"
#include "String.h" //for strlen()
void Delay(uint16 time); //延时
#endif
// 文件fun.c
#include "fun.h"
void Delay(uint16 time)
{
while(time--);
}
// 文件12864.h
#ifndef __12864_H__
#define __12864_H__
#include "Reg52.h"
#include "ZhangType.h"
#include "fun.h"
#define SETMODE8 0x30 //并口8位数据接口,DL = 1,基本指令 #define SETMODE8_OFF 0x34 //并行8位数据接口,DL = 1,绘图OFF #define SETMODE8_ON 0x36 //并行8位数据接口,DL = 1,绘图ON #define SETMODE4 0x20 //并行4位数据接口,DL = 0,基本指令 #define SETMODE4_OFF 0x24 //并行4位数据接口,DL = 0,绘图OFF #define SETMODE4_ON 0x26 //并行4位数据接口,DL = 0,绘图ON #define DISOPEN 0x0C //显示开,不显示光标,光标不闪烁
#define DISMODE 0x06 //读写字符后地址加1,屏显不移动
#define SETADDR1 0x80 //设置数据地址指针第一行
#define SETADDR2 0x90 //设置数据地址指针第二行
#define SETADDR3 0x88 //设置数据地址指针第三行
#define SETADDR4 0x98 //设置数据地址指针第四行
#define CLEAR 0x01 //清屏,数据指针清零
#define RET 0x02 //回车,数据指针清零
sbit RS = P1^0;
sbit RW = P1^1;
sbit E = P1^2;
void Init12864();
void Write12864_Com(uint8 com);
void Write12864_Dat(uint8 dat);
void CheckBusy(void); //检查忙
#endif
// 文件12864.c
#include "12864.h"
void Init12864() //初始化12864
{
CheckBusy();
Write12864_Com(SETMODE8);
CheckBusy();
Write12864_Com(DISOPEN);
CheckBusy();
Write12864_Com(CLEAR);
}
void Write12864_Com(uint8 com) //写命令
{
RS=0;
RW=0;
P2=com;
E=0;
E=1;
E=0;
}
void Write12864_Dat(uint8 dat) //写数据
{
RS=1;
RW=0;
P2=dat;
E=0;
E=1;
E=0;
}
void CheckBusy(void) //检查忙
{
uint8 temp;
RS=0;
RW=1;
E=0;
while(1)
{
P2=0xFF; //数据线为输入
E=1;
temp=P2;
E=0;
if ((temp&0x80)==0)
break;
}
}
// 文件_main.c
#include "Reg52.h"
#include "12864.h"
uint8 code dis1[]="胜日寻芳泗水滨,";
uint8 code dis2[]="无边光景一时新.";
uint8 code dis3[]="等闲识得东风面,";
uint8 code dis4[]="万紫千红总是春.";
uint8 code **[1024]=
{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xFF,0x80,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xFF,0xFF,0xFF,0x80,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0xFF,0xFF,0xFF,0xF8,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x07,0xF0,0x00,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x3F,0xFF,0xE0,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x03,0xFF,0xF8,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0xFE,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x80,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0xFF,0xFF,0xFF,0xFF,0xC0,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xE0,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x01,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF8,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x07,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFC,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x1F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x3F,0xFF,0xFF,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x7F,0xFF,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x01,0xFF,0xFF,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x01,0xFF,0xFF,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x01,0xFF,0xFF,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x01,0xFF,0xFF,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x03,0xFF,0xFF,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x03,0xFF,0xFF,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x03,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x03,0xFF,0xFF,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x03,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF8,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x01,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x01,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE0,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC0,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x80,0x00,0x00,0x00,
0x00,0x00,0x00,0x10,0x00,0x07,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x08,0x00,0x00,0x7F,0xFF,0xFF,0xFF,0xFF,0xFE,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x07,0xFF,0xF8,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x03,0xC0,0x00,0x00,0x00,0x00,0x3F,0xFF,0xE0,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0xFC,0x00,0x00,0x00,0x03,0xFF,0xFF,0x80,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x3F,0xE0,0x00,0x00,0x7F,0xFF,0xFE,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xF8,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x01,0xFF,0xFF,0xFF,0xFF,0xFF,0xC0,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x3F,0xFF,0xFF,0xFF,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x03,0xFF,0xFF,0xFF,0xC0,0x08,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xFF,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1D,0x00,0x1C,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x00,0x1C,0x00,0x00,
0x01,0xFF,0x7F,0xF3,0xFF,0x3F,0xF8,0xFF,0xE7,0xFE,0x3F,0xFB,0xFF,0x3C,0xFF,0xC0,
0x03,0xC0,0x00,0x77,0x87,0xB8,0x3D,0xC0,0xE7,0x0F,0x78,0x38,0x03,0xBD,0xC1,0xC0,
0x07,0x80,0x7F,0xF7,0x07,0xB8,0x3B,0x80,0xEF,0x0F,0x70,0x7B,0xFF,0xBB,0xFF,0xC0,
0x07,0x80,0xF0,0xF7,0x07,0x78,0x3B,0xC1,0xEE,0x0E,0x70,0x77,0x87,0xBB,0xC0,0x00,
0x03,0xFE,0xFF,0xEF,0x07,0x70,0x79,0xFF,0xCE,0x0E,0x7F,0xF7,0xFF,0x79,0xFF,0x80,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x68,0x63,0x47,0x1B,0x0C,0x78,0xE0,0x22,0xC0,0x93,0xC3,0x00,
0x00,0x00,0x00,0x00,0x78,0xE3,0xCD,0x9F,0x1C,0x49,0xC0,0x67,0x80,0xB3,0xC7,0x00,
0x00,0x00,0x00,0x00,0x59,0x66,0xCF,0x1F,0x34,0x71,0xE0,0x45,0x80,0xE3,0xCB,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};
void Disp(uint8 *pic) //显示Gdram内容(显示图片)
{
uint8 x, y, i;
CheckBusy();
Write12864_Com(SETMODE8_OFF); //切换到扩充指令,
for(i = 0; i <= 8; i += 8) //写上,下半屏
for(y = 0; y < 32; y++) //第行32象素
{
for(x = 0; x < 8; x++) //每半屏8列,每列2字节
{
CheckBusy();
Write12864_Com(0x80 + y); //行地址
CheckBusy();
Write12864_Com(0x80 + x + i); //列地址
CheckBusy();
Write12864_Dat(*pic++); //写数据 D15-D8
CheckBusy();
Write12864_Dat(*pic++); //写数据 D7-D0
}
}
CheckBusy();
Write12864_Com(SETMODE8_ON); //打开图形显示
}
void main()
{
uint8 len, max, t;
Init12864();
CheckBusy();
Write12864_Com(SETADDR1);
max = strlen(dis1);
for(len = 0; len < max; len++)
{
CheckBusy();
Write12864_Dat(dis1[len]);
}
CheckBusy();
Write12864_Com(SETADDR2);
for(len = 0; len < max; len++)
{
CheckBusy();
Write12864_Dat(dis2[len]);
}
CheckBusy();
Write12864_Com(SETADDR3);
for(len = 0; len < max; len++)
{
CheckBusy();
Write12864_Dat(dis3[len]);
}
CheckBusy();
Write12864_Com(SETADDR4);
for(len = 0; len < max; len++)
{
CheckBusy();
Write12864_Dat(dis4[len]);
}
for(t = 0; t < 30; t++) Delay(50000);
CheckBusy();
Write12864_Com(0x01);
Disp(**); //填充图形
while(1);
}
//############### PROGRAM END #################
程序执行效果如下(图14、图15):
图14
图15
补充说明:
在LCD12864中,检查忙函数却可以运行得很好,所以我在程序里使用了这个函数void CheckBusy(void)。
//############### THE END #################
|