最新消息: USBMI致力于为网友们分享Windows、安卓、IOS等主流手机系统相关的资讯以及评测、同时提供相关教程、应用、软件下载等服务。

基于FPGA的LCD设计报告

IT圈 admin 38浏览 0评论

2024年2月21日发(作者:依兰)

12864点阵型液晶显示器的VHDL设计与实现

陈曦

河南科技大学电子信息工程学院信科063班

摘 要:介绍LCD12864的组成及工作原理,论述了基于VHDL语言和FPGA芯片的数字系统的设计思想和实现过程。

关键词:数字电压表;VHDL语言;FPGA

VHDL Realization of Digital Voltmeter

Abstract: The composition and working principle of Point LCD display were introduced in this

paper, the designing idea and implementation proces s based on VHDL and FPGA were also described.

Key words: digital voltmeter; VHDL; FPGA

在硬件电子电路设计领域中,电子设计自动化(EDA)工具已成为主要的设计手段,而VHDL语言则是EDA的关键技术之一,它采用自顶向下的设计方法,即从系统总体要求出发,自上至下地将设计任务分解为不同的功能模块,最后将各功能模块连接形成顶层模块,完成系统硬件的整体设计。本文用FPGA芯片和VHDL语言设计了一个数字电压表,举例说明了利用VHDL语言实现数字系统的过程。

1.系统组成及工作原理

整个LCD的硬件结构如下图所示。

本设计所用的JM12864A是一种图形点阵液晶显示器,它主要由行驱动器、列驱动器及128×64全点阵液晶显示器组成。可完成图形显示;也可以显示8×4个(16×16点阵)汉字。 1.12864点阵型液晶显示器的显示原理

12864液晶显示屏共有128×64点阵,即每行显示128点,每列显示64点。此种型号的液晶显示屏以中间间隔平均划分为左屏和右屏分别显示,均为64×64点阵,而且各自都有独立的片选信号控制选择。先显示左屏,左屏全部显示完后才能显示右屏。显示屏上的显示数据由显示数据随机存储器DDRAM提供。DDRAM每字节中的每1个bit,对应显示屏上的1个点。bit值为1,对应点显示,反之不显示。

DDRAM与显示屏的对应位置如图1所示。每半屏显示数据共有512字节的DDRAM,分为8个数据页来管理,这些页对应显示屏从上到下编号为0-7页,每页64字节,涵盖半边显示屏的64行×64列×8bit点阵数据。向显示屏写数据实际上是向DDRAM中写数据,DDRAM不同页和不同列中的字节数据唯一对应显示屏一行的8个显示点。

工作时,LCD显示电路实现分行显示“河南科技大学”、“电信科×级×班”、“姓名1和姓名2”及实际测量电压值。

2.FPGA功能模块的设计

12864点阵型液晶显示器的各个模块都是用VHDL语言编程实现的。

本设计所用的JM12864A是一种图形点阵液晶显示器,它主要由行驱动器、列驱动器及128×64全点阵液晶显示器组成。可完成图形显示;也可以显示8×4个(16×16点阵)汉字。

1.12864点阵型液晶显示器的显示原理

12864液晶显示屏共有128×64点阵,即每行显示128点,每列显示64点。此种型号的液晶显示屏以中间间隔平均划分为左屏和右屏分别显示,均为64×64点阵,而且各自都有独立的片选信号控制选择。先显示左屏,左屏全部显示完后才能显示右屏。显示屏上的显示数据由显示数据随机存储器DDRAM提供。DDRAM每字节中的每1个bit,对应显示屏上的1个点。bit值为1,对应点显示,反之不显示。

DDRAM与显示屏的对应位置如图1所示。每半屏显示数据共有512字节的DDRAM,分为8个数据页来管理,这些页对应显示屏从上到下编号为0-7页,每页64字节,涵盖半边显示屏的64行×64列×8bit点阵数据。向显示屏写数据实际上是向DDRAM中写数据,DDRAM不同页和不同列中的字节数据唯一对应显示屏一行的8个显示点。例如,向DDRAM第0页的第0列写入数据00010100B,则显示屏左上角第0列的8个显示点只有从上往下的第3和5点显示。不同页和不同列DDRAM的寻址,通过左半屏和右半屏各自的页地址计数器和列地址计数器实现,因此对显示屏DDRAM写显示数据前,需要先设置页地址和列地址。

左半屏右半屏

图1 12864液晶显示屏与内部RAM的对应关系

2.12864液晶显示器的内部结构及外部引脚

1)12864液晶显示器的内部结构

IC1控制模块的左半屏,IC2控制模块的右半屏。IC3为行驱动器。IC1,IC2为列驱动器。IC1,IC2,IC3含有如下主要功能器件。了解如下器件有利于对LCD模块的编程。

a) 指令寄存器(IR)

IR是用来寄存指令码,与数据寄存器寄存数据相对应.当D/I=1 时,在E信号下降沿的作用下,指令码写入IR。.

b) 数据寄存器(DR)

DR是用来寄存数据的,与指令寄存器寄存指令相对应.当D/I=1时,在E信号的下降沿作用下,图形显示数据写入DR,或在E信号高电平作用下由DR读到DB7~DB0 数据总线.DR 和DDRAM之间的数据传输是模块内部自动执行的。

c) 状态寄存器

有效数据位3位,用于记录“忙”信号标志位(BF),复位标志位(RST)以及开/关显示状态位(ON/OFF)。

d) XY地址计数器

XY地址计数器是一个9位计数器。高三位是X地址计数器,低6位为Y地址计数器,XY地址计数器实际上是作为DDRAM的地址指针,X地址计数器为DDRAM的页指针,Y地址计数器为DDRAM的Y地址指针。

X地址计数器是没有记数功能的,只能用指令设置。

Y地址计数器具有循环记数功能,各显示数据写入后,Y地址自动加1,Y地址指针从0到63。

e) 显示数据RAM(DDRAM)

DDRAM是存贮图形显示数据的。DDRAM与地址和显示位置的关系见图1。

f) Z地址计数器

Z地址计数器是一个6位计数器,此计数器具备循环记数功能,它是用于显示行扫描同步。当一行扫描完成,此地址计数器自动加1,指向下一行扫描数据,RST复位后Z地址计数器为0。

Z地址计数器可以用指令DISPLAY START LINE 预置。因此,显示屏幕的起始行就由此指令控制,即DDRAM的数据从哪一行开始显示在屏幕的第一行。此模块的DDRAM共64行,屏幕可以循环滚动显示64行。

2)12864液晶显示器的外部引脚

12864液晶显示模块共有20个引脚,包括8位双向数据线、6条控制线及电源线等。具体引脚功能见下表所示。

管脚号

1

2

3

4

5

管脚名称

VSS

VDD

V0

D/I

R/W

电平

0V

5.0V

-

H/L

H/L

管脚功能描述

电源地

电源电压

液晶显示器驱动电压

D/I=“H”,表示DB7~DB0为显示数据

D/I=“L”,表示DB7~DB0为显示指令数据

R/W=“H”,E=“H”,数据被读到DB7~DB0

R/W=“L”,E=“H→L”, DB7~DB0的数据被写到IR或DR

6 E H/L

使能信号:R/W=“L”,E信号下降沿锁存DB7~DB0

R/W=“H”,E=“H” DRAM数据读到

DB7~DB0(使能端,高电平有效)

7

8

9

10

管脚号

11

12

13

14

15

16

17

18

19

20

DB0

DB1

DB2

DB3

管脚名称

DB4

DB5

DB6

DB7

CS1

CS2

RESET

VEE

IED+

IED-

H/L

H/L

H/L

H/L

电平

H/L

H/L

H/L

H/L

H/L

H/L

H/L

-10V

DC+5V

DC0V

数据线

数据线

数据线

数据线

管脚功能描述

数据线

数据线

数据线

数据线

左半屏片选信号,低电平有效

右半屏片选信号,低电平有效

复位信号,低电平复位

LCD驱动负电压

背光板电源

背光板电源

3.12864液晶显示器的编程指令

1) 显示开关控制(DISPLAY ON/OFF)

代码

R/W D/I DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0

形式

0 0 0 0 1 1 1 1 1 1

设置屏幕显示开/关。D/I=1,开显示。D=0,关显示。不影响DDRAM中的内容。

2) 设置显示起始行(DISPLAY START LINE)

代码

R/W D/I DB7 DB6 DB5

形式

DB4 DB3 DB2 DB1 DB0

0 0 1 1 A5 A4 A3 A2 A1 A0

前面在介绍Z地址计数器时已经描述了显示起始行是由Z地址计数器控制的。A5~A0

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

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

DDRAM 行:62 63 0 1 2 3 ·················28 29

屏幕显示行: 1 2 3 4 5 6················· 31 32

3) 设置页地址(SET PAGE “X ADDRESS”)

代码

R/W D/I DB7 DB6 DB5 DB4 DB3 DB2

形式

0 0 1 0 1 1 1 A2

DB1 DB0

A1 A0

所谓页地址就是DDRAM的行地址,8行为一页,模块共64行即8页,A2~A0表示0~7页。读写数据对地址没有影响,页地址由本指令或RST信号改变复位后页地址为0。

4) 设置Y地址(SET Y ADDRESS)

代码

形式

R/W

0

D/I DB7

0 0

DB6

1

DB5

A5

DB4

A4

DB3

A3

DB2

A2

DB1

A1

DB0

A0

此指令的作用是将A5~A0送入Y地址计数器,作为DDRAM的Y地址指针。在对DDRAM进行读写操作后,Y地址指针自动加1,指向下一个DDRAM单元。

5) 读状态(STATUS READ)

代码

R/W D/I DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0

形式

1 0 BUSY 0 ON/OFF RET 0 0 0 0

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

BF:BF=1,内部正在进行操作,BF=0,空闲状态。

ON/OFF:ON/OFF=1,表示显示打开,ON/OFF=0,表示显示关闭。

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

6) 写显示数据(WRITE DISPLAY DATE)

代码

R/W D/I DB7 DB6 DB5

形式

0 1 D7 D6 D5

DB4

D4

DB3

D3

DB2

D2

DB1

D1

DB0

D0

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

7) 读显示数据(READ DISPLAY DATE)

代码

R/W D/I DB7 DB6 DB5

形式

DB4 DB3 DB2 DB1 DB0

1 1 D7 D6 D5 D4 D3 D2 D1 D0

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

3.

12864点阵型液晶显示器的接口电路设计

通过前面对12864显示屏引脚功能的分析可以知道,该模块有一个整体的片选信号“E”,只有当该信号为高电平时,所有的电路才会有效。另外左右半屏各有一个选择信号CS1和CS2,CS1和CS2各自为低电平时,分别选中左半屏和右半屏。为了区分读写的是数据还是指令,还设置了一个数据/指令控制线D/I。根据这些原则,设计出接口电路如图3所示。

图3 液晶显示器的接口电路

由于CS0的地址范围为280H-283H,由接口电路的设计可得液晶屏的相关地址,如下表。

操作

向左半屏写指令

向右半屏写指令

读/写左半屏数据

读/写右半屏数据

读状态寄存器

A1A0

00

10

01

11

00

端口地址

280H

282H

281H

283H

280H

4.

12864点阵型液晶显示器的软件设计

对液晶显示器的编程就是向DDRAM中写数据。在写DDRAM之前,需要先清除RAM,且左屏和右屏要分别进行清除。方法就是向RAM的所有单元写入0值。图4是液晶显示器的编程流程。图5是向LCD写显示数据的流程图。

广告字幕机是用LCD输出不同的汉字和图形。要液晶显示器显示不同的图形或汉字,就是向DDRAM中写入不同的数据。根据前面所说的液晶显示屏与DDRAM的对应关系,可以构造不同的数据来显示不同的图形和汉字。

开始系统初始化写LCD左屏数据清左屏RAM写LCD左屏数据清左屏RAM左右屏开显示

图4 液晶显示器的编程流程

将起始页地址存入BL设置页地址设置列地址LCD工作忙N写显示RAMY图5

向LCD写显示数据的流程图已显示64列?Y页地址加1N页地址已设置8次Y结束N

5.

12864点阵型液晶显示器驱动程序设计 VHDL程序源代码:

LIBRARY IEEE;

USE _LOGIC_;

USE _LOGIC_;

USE _LOGIC_;

ENTITY LCD_TEXT IS

PORT(

CLK: IN STD_LOGIC;

RS,RW,CS1,CS2,E: OUT STD_LOGIC;

Q: BUFFER STD_LOGIC_VECTOR(7 DOWNTO 0) );

END;

ARCHITECTURE BEHAV OF LCD_TEXT IS

TYPE STATES IS(ST1,ST2,ST3,ST4,ST5,ST6,ST7,ST8,ST9,ST10,ST11,ST12,ST13,ST14,ST15,

STA1,STA2,STA3,STA4,STA5,STA6,STA7,STA8,STA9,STA10,

ST16,ST17,ST18,ST19,ST20,ST21,ST22,ST23,ST24,ST25,ST26,ST27,ST28,ST29,ST30,ST31,ST32,ST33,ST34);

SIGNAL PRE_STATE,NEXT_STATE:STATES;

SIGNAL DATALOCK,EN,RST1:STD_LOGIC;

SIGNAL XPAGE:STD_LOGIC_VECTOR(7 DOWNTO 0):="10111000";

SIGNAL YADDR:STD_LOGIC_VECTOR(7 DOWNTO 0):="01000000";

BEGIN

CLOCK:PROCESS(CLK) --将时钟进行分频

VARIABLE CONT:INTEGER RANGE 0 TO 20;

BEGIN

IF CLK'EVENT AND CLK='1' THEN

CONT:=CONT+1;

IF CONT = 12 THEN DATALOCK<='0';CONT:=0; --DATALOCK是13进制

ELSIF CONT=9 THEN

DATALOCK<='1';

END IF;

END IF;

END PROCESS CLOCK;

EN<= NOT DATALOCK;

E<=EN;

DATAK:PROCESS(EN,PRE_STATE)

VARIABLE CNT : INTEGER RANGE 0 TO 255;

BEGIN

IF EN'EVENT AND EN='1' THEN

CASE PRE_STATE IS

WHEN STA1=>RS<='0';RW<='1';CS1<='0';CS2<='1';IF Q="00100000" THEN PRE_STATE<=ST1; END

IF; --CHECK BUSY

WHEN ST1=>RS<='0';RW<='0';CS1<='0';CS2<='1';Q<="00111111";PRE_STATE<=ST2; --显示开关设置

WHEN ST2=>RS<='0';RW<='0';CS1<='0';CS2<='1';Q<="11000000";PRE_STATE<=ST3; --起始行设置

--左半清屏

WHEN ST3=>RS<='0';RW<='0';CS1<='0';CS2<='1';Q<=XPAGE;PRE_STATE<=ST4; --页地址设置

WHEN ST4=>RS<='0';RW<='0';CS1<='0';CS2<='1';Q<=YADDR;PRE_STATE<=ST5; --列地址设置

WHEN ST5=>RS<='1';RW<='0';CS1<='0';CS2<='1';

IF XPAGE>"10111111" THEN

XPAGE<="10111000";

YADDR<="01000000";

PRE_STATE<=ST6; --左半清屏完毕,进入下一状态

ELSIF YADDR>"01111111" THEN

YADDR<="01000000";

XPAGE<=XPAGE+1; --清完一页,开始下一页

PRE_STATE<=ST3; --返回重新设置页地址

ELSE

Q<="00000000";YADDR<=YADDR+1;PRE_STATE<=ST5; --清完一列,开始下一列

END IF;

--右半清屏

IF;

WHEN ST6=>RS<='0';RW<='0';CS1<='1';CS2<='0';Q<=XPAGE;PRE_STATE<=ST7; --页地址设置

WHEN ST7=>RS<='0';RW<='0';CS1<='1';CS2<='0';Q<=YADDR;PRE_STATE<=ST8; --列地址设置

WHEN ST8=>RS<='1';RW<='0';CS1<='1';CS2<='0';

IF XPAGE>"10111111" THEN

XPAGE<="10111000";

YADDR<="01000000";

PRE_STATE<=ST9; ----右半清屏完毕,进入下一状态

ELSIF YADDR>"01111111" THEN

YADDR<="01000000";

XPAGE<=XPAGE+1; --清完一页,开始下一页

PRE_STATE<=ST6; --返回重新设置页地址

ELSE

Q<="00000000";YADDR<=YADDR+1;PRE_STATE<=ST8; --清完一列,开始下一列

END IF;

--清屏完毕,开始显示数据

--显示上半边

IF;

WHEN ST9=>RS<='0';RW<='0';CS1<='0';CS2<='1';Q<="00111111";PRE_STATE<=ST10; --ON/OFF

WHEN ST10=>RS<='0';RW<='0';CS1<='0';CS2<='1';Q<=XPAGE;PRE_STATE<=ST11; --SET PAGE

PAGE 0

WHEN ST11=>RS<='0';RW<='0';CS1<='0';CS2<='1';Q<=YADDR;PRE_STATE<=ST12; --SET ROW

ROW 0

WHEN ST12=>RS<='1';RW<='0';CS1<='0';CS2<='1';

Q<=UNIVERSITY(CNT);

IF CNT=16 THEN

XPAGE<="10111001";YADDR<="01000000";PRE_STATE<=ST10; --0~15

XPAGE<="10111000";YADDR<="01010000";PRE_STATE<=ST10; --16~31

XPAGE<="10111001";YADDR<="01010000";PRE_STATE<=ST10;

XPAGE<="10111000";YADDR<="01100000";PRE_STATE<=ST10; --32~47

XPAGE<="10111001";YADDR<="01100000";PRE_STATE<=ST10;

XPAGE<="10111000";YADDR<="01110000";PRE_STATE<=ST10; --48~63

XPAGE<="10111001";YADDR<="01110000";PRE_STATE<=ST10;

ELSIF CNT=32 THEN

ELSIF CNT=48 THEN

ELSIF CNT=64 THEN

ELSIF CNT=80 THEN

ELSIF CNT=96 THEN

ELSIF CNT=112 THEN

WHEN STA3=>RS<='0';RW<='1';CS1<='0';CS2<='1';IF Q="00100000" THEN PRE_STATE<=ST9;END

WHEN STA2=>RS<='0';RW<='1';CS1<='0';CS2<='1';IF Q="00100000" THEN PRE_STATE<=ST6;END

IF;

ELSIF CNT=128 THEN

XPAGE<="10111010";YADDR<="01000000";PRE_STATE<=ST13;CNT:=0;

ELSE YADDR<=YADDR+1;CNT:=CNT+1;PRE_STATE<=ST12;

END IF;

WHEN STA4=>RS<='0';RW<='1';CS1<='0';CS2<='1';IF Q="00100000" THEN PRE_STATE<=ST13;END

WHEN ST13=>RS<='0';RW<='0';CS1<='0';CS2<='1';Q<=XPAGE;PRE_STATE<=ST14; --SET PAGE

PAGE 2

WHEN ST14=>RS<='0';RW<='0';CS1<='0';CS2<='1';Q<=YADDR;PRE_STATE<=ST15; --SET ROW

ROW 0

WHEN ST15=>RS<='1';RW<='0';CS1<='0';CS2<='1';

Q<=CLASS(CNT);

IF CNT=16 THEN

XPAGE<="10111011";YADDR<="01000000";PRE_STATE<=ST13; --0~15

ELSIF CNT=32 THEN

XPAGE<="10111010";YADDR<="01010000";PRE_STATE<=ST13; --16~31

XPAGE<="10111011";YADDR<="01010000";PRE_STATE<=ST13;

XPAGE<="10111010";YADDR<="01100000";PRE_STATE<=ST13; --32~47

XPAGE<="10111011";YADDR<="01100000";PRE_STATE<=ST13;

XPAGE<="10111010";YADDR<="01110000";PRE_STATE<=ST13; --48~63

XPAGE<="10111011";YADDR<="01110000";PRE_STATE<=ST13;

XPAGE<="10111100";YADDR<="01000000";PRE_STATE<=ST16;CNT:=0;

ELSIF CNT=48 THEN

ELSIF CNT=64 THEN

ELSIF CNT=80 THEN

ELSIF CNT=96 THEN

ELSIF CNT=112 THEN

ELSIF CNT=128 THEN

ELSE YADDR<=YADDR+1;CNT:=CNT+1;PRE_STATE<=ST15;

END IF;

WHEN STA5=>RS<='0';RW<='1';CS1<='0';CS2<='1';IF Q<="00100000" THEN PRE_STATE<=ST16;

WHEN ST16=>RS<='0';RW<='0';CS1<='0';CS2<='1';Q<=XPAGE;PRE_STATE<=ST17; --SET PAGE

END IF;

PAGE 4

WHEN ST17=>RS<='0';RW<='0';CS1<='0';CS2<='1';Q<=YADDR;PRE_STATE<=ST18; --SET ROW

ROW 0

WHEN ST18=>RS<='1';RW<='0';CS1<='0';CS2<='1';

Q<=NAME(CNT);

IF CNT=16 THEN

XPAGE<="10111101";YADDR<="01000000";PRE_STATE<=ST16; --0~15

XPAGE<="10111100";YADDR<="01010000";PRE_STATE<=ST16; --16~31

XPAGE<="10111101";YADDR<="01010000";PRE_STATE<=ST16;

ELSIF CNT=32 THEN

ELSIF CNT=48 THEN

ELSIF CNT=64 THEN

XPAGE<="10111100";YADDR<="01100000";PRE_STATE<=ST16; --32~47

ELSIF CNT=80 THEN

XPAGE<="10111101";YADDR<="01100000";PRE_STATE<=ST16;

XPAGE<="10111100";YADDR<="01110000";PRE_STATE<=ST16; --48~63

XPAGE<="10111101";YADDR<="01110000";PRE_STATE<=ST16;

XPAGE<="10111110";YADDR<="01000000";PRE_STATE<=ST19;CNT:=0;

ELSIF CNT=96 THEN

ELSIF CNT=112 THEN

ELSIF CNT=128 THEN

ELSE YADDR<=YADDR+1;CNT:=CNT+1;PRE_STATE<=ST18;

END IF;

WHEN STA6=>RS<='0';RW<='1';CS1<='0';CS2<='1';IF Q="00100000" THEN PRE_STATE<=ST19;

WHEN ST19=>RS<='0';RW<='0';CS1<='0';CS2<='1';Q<=XPAGE;PRE_STATE<=ST20; --SET PAGE

END IF;

PAGE 6

WHEN ST20=>RS<='0';RW<='0';CS1<='0';CS2<='1';Q<=YADDR;PRE_STATE<=ST21; --SET ROW

ROW 0

WHEN ST21=>RS<='1';RW<='0';CS1<='0';CS2<='1';

Q<=VOLTAGE(CNT);

IF CNT=16 THEN

XPAGE<="10111111";YADDR<="01000000";PRE_STATE<=ST19; --0~15

XPAGE<="10111110";YADDR<="01010000";PRE_STATE<=ST19; --16~31

XPAGE<="10111111";YADDR<="01010000";PRE_STATE<=ST19;

XPAGE<="10111110";YADDR<="01100000";PRE_STATE<=ST19; --32~47

XPAGE<="10111111";YADDR<="01100000";PRE_STATE<=ST19;

XPAGE<="10111110";YADDR<="01110000";PRE_STATE<=ST19; --48~63

XPAGE<="10111111";YADDR<="01110000";PRE_STATE<=ST19;

XPAGE<="10111000";YADDR<="01000000";PRE_STATE<=ST22;

ELSIF CNT=32 THEN

ELSIF CNT=48 THEN

ELSIF CNT=64 THEN

ELSIF CNT=80 THEN

ELSIF CNT=96 THEN

ELSIF CNT=112 THEN

ELSIF CNT=128 THEN

ELSE YADDR<=YADDR+1;CNT:=CNT+1;PRE_STATE<=ST21;

END IF;

--next print

WHEN STA7=>RS<='0';RW<='1';CS1<='0';CS2<='1';IF Q="00100000" THEN PRE_STATE<=ST22;

END IF;

WHEN ST22=>RS<='0';RW<='0';CS1<='1';CS2<='0';Q<="00111111";PRE_STATE<=ST23; --ON/OFF

WHEN ST23=>RS<='0';RW<='0';CS1<='1';CS2<='0';Q<=XPAGE;PRE_STATE<=ST24; --SET PAGE

PAGE 0

WHEN ST24=>RS<='0';RW<='0';CS1<='1';CS2<='0';Q<=YADDR;PRE_STATE<=ST25; --SET ROW

ROW 0

WHEN ST25=>RS<='1';RW<='0';CS1<='1';CS2<='0';

Q<=UNIVERSITY(CNT);

IF CNT=144 THEN

XPAGE<="10111001";YADDR<="01000000";PRE_STATE<=ST23; --0~15

XPAGE<="10111000";YADDR<="01010000";PRE_STATE<=ST23; --16~31

XPAGE<="10111001";YADDR<="01010000";PRE_STATE<=ST23;

XPAGE<="10111000";YADDR<="01100000";PRE_STATE<=ST23; --32~47

XPAGE<="10111001";YADDR<="01100000";PRE_STATE<=ST23;

XPAGE<="10111000";YADDR<="01110000";PRE_STATE<=ST23; --48~63

XPAGE<="10111001";YADDR<="01110000";PRE_STATE<=ST23;

XPAGE<="10111010";YADDR<="01000000";PRE_STATE<=ST26;CNT:=128;

ELSIF CNT=160 THEN

ELSIF CNT=176 THEN

ELSIF CNT=192 THEN

ELSIF CNT=208 THEN

ELSIF CNT=224 THEN

ELSIF CNT=240 THEN

ELSIF CNT=256 THEN

ELSE YADDR<=YADDR+1;CNT:=CNT+1;PRE_STATE<=ST25;

END IF;

WHEN STA8=>RS<='0';RW<='1';CS1<='0';CS2<='1';IF Q="00100000" THEN PRE_STATE<=ST26;

END IF;

WHEN ST26=>RS<='0';RW<='0';CS1<='1';CS2<='0';Q<=XPAGE;PRE_STATE<=ST27; --SET PAGE

PAGE 2

WHEN ST27=>RS<='0';RW<='0';CS1<='1';CS2<='0';Q<=YADDR;PRE_STATE<=ST28; --SET ROW

ROW 0

WHEN ST28=>RS<='1';RW<='0';CS1<='1';CS2<='0';

Q<=CLASS(CNT);

IF CNT=144 THEN

XPAGE<="10111011";YADDR<="01000000";PRE_STATE<=ST26; --0~15

XPAGE<="10111010";YADDR<="01010000";PRE_STATE<=ST26; --16~31

XPAGE<="10111011";YADDR<="01010000";PRE_STATE<=ST26;

XPAGE<="10111010";YADDR<="01100000";PRE_STATE<=ST26; --32~47

XPAGE<="10111011";YADDR<="01100000";PRE_STATE<=ST26;

XPAGE<="10111010";YADDR<="01110000";PRE_STATE<=ST26; --48~63

ELSIF CNT=160 THEN

ELSIF CNT=176 THEN

ELSIF CNT=192 THEN

ELSIF CNT=208 THEN

ELSIF CNT=224 THEN

ELSIF CNT=240 THEN

XPAGE<="10111011";YADDR<="01110000";PRE_STATE<=ST26;

XPAGE<="10111100";YADDR<="01000000";PRE_STATE<=ST29;CNT:=128;

ELSIF CNT=256 THEN

ELSE YADDR<=YADDR+1;CNT:=CNT+1;PRE_STATE<=ST28;

END IF;

WHEN STA9=>RS<='0';RW<='1';CS1<='0';CS2<='1';IF Q="00100000" THEN PRE_STATE<=ST29;

WHEN ST29=>RS<='0';RW<='0';CS1<='1';CS2<='0';Q<=XPAGE;PRE_STATE<=ST30; --SET PAGE

END IF;

PAGE 4

WHEN ST30=>RS<='0';RW<='0';CS1<='1';CS2<='0';Q<=YADDR;PRE_STATE<=ST31; --SET ROW

ROW 0

WHEN ST31=>RS<='1';RW<='0';CS1<='1';CS2<='0';

Q<=NAME(CNT);

IF CNT=144 THEN

XPAGE<="10111101";YADDR<="01000000";PRE_STATE<=ST29; --0~15

ELSIF CNT=160 THEN

XPAGE<="10111100";YADDR<="01010000";PRE_STATE<=ST29; --16~31

XPAGE<="10111101";YADDR<="01010000";PRE_STATE<=ST29;

XPAGE<="10111100";YADDR<="01100000";PRE_STATE<=ST29; --32~47

XPAGE<="10111101";YADDR<="01100000";PRE_STATE<=ST29;

XPAGE<="10111100";YADDR<="01110000";PRE_STATE<=ST29; --48~63

XPAGE<="10111101";YADDR<="01110000";PRE_STATE<=ST29;

XPAGE<="10111110";YADDR<="01000000";PRE_STATE<=ST32;CNT:=128;

ELSIF CNT=176 THEN

ELSIF CNT=192 THEN

ELSIF CNT=208 THEN

ELSIF CNT=224 THEN

ELSIF CNT=240 THEN

ELSIF CNT=256 THEN

ELSE YADDR<=YADDR+1;CNT:=CNT+1;PRE_STATE<=ST31;

END IF;

STA10=>RS<='0';RW<='1';CS1<='0';CS2<='1';IF Q="00100000" THEN WHEN

PRE_STATE<=ST32;END IF;

WHEN ST32=>RS<='0';RW<='0';CS1<='1';CS2<='0';Q<=XPAGE;PRE_STATE<=ST33; --SET PAGE

PAGE 6

WHEN ST33=>RS<='0';RW<='0';CS1<='1';CS2<='0';Q<=YADDR;PRE_STATE<=ST34; --SET ROW

ROW 0

WHEN ST34=>RS<='1';RW<='0';CS1<='1';CS2<='0';

Q<=VOLTAGE(CNT);

IF CNT=144 THEN

XPAGE<="10111111";YADDR<="01000000";PRE_STATE<=ST32; --0~15

ELSIF CNT=160 THEN

XPAGE<="10111110";YADDR<="01010000";PRE_STATE<=ST32; --16~31

ELSIF CNT=176 THEN

XPAGE<="10111111";YADDR<="01010000";PRE_STATE<=ST32;

XPAGE<="10111110";YADDR<="01100000";PRE_STATE<=ST32; --32~47

XPAGE<="10111111";YADDR<="01100000";PRE_STATE<=ST32;

XPAGE<="10111110";YADDR<="01110000";PRE_STATE<=ST32; --48~63

XPAGE<="10111111";YADDR<="01110000";PRE_STATE<=ST32;

YADDR<="01000000";CNT:=128;

ELSIF CNT=192 THEN

ELSIF CNT=208 THEN

ELSIF CNT=224 THEN

ELSIF CNT=240 THEN

ELSIF CNT=256 THEN

ELSE YADDR<=YADDR+1;CNT:=CNT+1;PRE_STATE<=ST34;

END IF;

WHEN OTHERS=>PRE_STATE<=STA1;

END CASE;

END IF;

END PROCESS DATAK;

END BEHA

6.

软件仿真和硬件验证结果波形

检忙 显示开关设置 起始行设置 清左屏

开始淸左屏

左屏清除完毕清右屏

右屏清除

按页按列清右屏

写左屏

写右屏

7. 结束语

本文设计的VHDL语言程序已在MAXPLUSⅡ工具软件上进行了编译、仿真和调试,并通过编程器下载到了EP1K100QC208-3芯片。经过实验验证,设计正确,其各项显示数据正常。本文给出的设计思想也适用于其他基于PLD芯片的系统设计。

8. 心得体会

通过此次12864LCD驱动程序的编写,我知道了12864驱动程序有七个指令,它们分别是:“检忙” “写指令” “写数据” “写显示开关”“写页”“写列”“写初始行”。12864分左右两屏,像素点为128*64个像素点,行有128个像素点,列有64个像素点,行又设置为8页,在12864默认状态下中文字体都是16*16的大小,每个页包含8个像素行,所以要显示一个中文就需要2页+两行;初始行的设定可以使得你要显示的字出现在任意你想要的位置。12864跟1602不一样,1602写指令和写数据就可以了,12864就不行,它还有控制到CS1 和 CS2两个脚,通过HD61203对整个液晶进行控制

参考文献

[1]潘松.EDA技术实用教程[M].北京:科学出版社,2003.

[2]卢毅.VHDL与数字电路设计[M].北京:科学出版社,2001.

[3]林敏.VHDL数字系统设计与高层次综合[M].北京:电子工业出版社,2001.

[4]齐洪喜.VHDL电路设计[M].北京:清华大学出版社,2004.

[5]A novel dynamic frame rate control algorithm for H.264 low-bit-rate video coding - 高技术通讯:英文版 - 杨静 Fang Xiangzhong

[6]/post/ , 2007-09-10

[7]/s/blog_, 2009-04-02

2024年2月21日发(作者:依兰)

12864点阵型液晶显示器的VHDL设计与实现

陈曦

河南科技大学电子信息工程学院信科063班

摘 要:介绍LCD12864的组成及工作原理,论述了基于VHDL语言和FPGA芯片的数字系统的设计思想和实现过程。

关键词:数字电压表;VHDL语言;FPGA

VHDL Realization of Digital Voltmeter

Abstract: The composition and working principle of Point LCD display were introduced in this

paper, the designing idea and implementation proces s based on VHDL and FPGA were also described.

Key words: digital voltmeter; VHDL; FPGA

在硬件电子电路设计领域中,电子设计自动化(EDA)工具已成为主要的设计手段,而VHDL语言则是EDA的关键技术之一,它采用自顶向下的设计方法,即从系统总体要求出发,自上至下地将设计任务分解为不同的功能模块,最后将各功能模块连接形成顶层模块,完成系统硬件的整体设计。本文用FPGA芯片和VHDL语言设计了一个数字电压表,举例说明了利用VHDL语言实现数字系统的过程。

1.系统组成及工作原理

整个LCD的硬件结构如下图所示。

本设计所用的JM12864A是一种图形点阵液晶显示器,它主要由行驱动器、列驱动器及128×64全点阵液晶显示器组成。可完成图形显示;也可以显示8×4个(16×16点阵)汉字。 1.12864点阵型液晶显示器的显示原理

12864液晶显示屏共有128×64点阵,即每行显示128点,每列显示64点。此种型号的液晶显示屏以中间间隔平均划分为左屏和右屏分别显示,均为64×64点阵,而且各自都有独立的片选信号控制选择。先显示左屏,左屏全部显示完后才能显示右屏。显示屏上的显示数据由显示数据随机存储器DDRAM提供。DDRAM每字节中的每1个bit,对应显示屏上的1个点。bit值为1,对应点显示,反之不显示。

DDRAM与显示屏的对应位置如图1所示。每半屏显示数据共有512字节的DDRAM,分为8个数据页来管理,这些页对应显示屏从上到下编号为0-7页,每页64字节,涵盖半边显示屏的64行×64列×8bit点阵数据。向显示屏写数据实际上是向DDRAM中写数据,DDRAM不同页和不同列中的字节数据唯一对应显示屏一行的8个显示点。

工作时,LCD显示电路实现分行显示“河南科技大学”、“电信科×级×班”、“姓名1和姓名2”及实际测量电压值。

2.FPGA功能模块的设计

12864点阵型液晶显示器的各个模块都是用VHDL语言编程实现的。

本设计所用的JM12864A是一种图形点阵液晶显示器,它主要由行驱动器、列驱动器及128×64全点阵液晶显示器组成。可完成图形显示;也可以显示8×4个(16×16点阵)汉字。

1.12864点阵型液晶显示器的显示原理

12864液晶显示屏共有128×64点阵,即每行显示128点,每列显示64点。此种型号的液晶显示屏以中间间隔平均划分为左屏和右屏分别显示,均为64×64点阵,而且各自都有独立的片选信号控制选择。先显示左屏,左屏全部显示完后才能显示右屏。显示屏上的显示数据由显示数据随机存储器DDRAM提供。DDRAM每字节中的每1个bit,对应显示屏上的1个点。bit值为1,对应点显示,反之不显示。

DDRAM与显示屏的对应位置如图1所示。每半屏显示数据共有512字节的DDRAM,分为8个数据页来管理,这些页对应显示屏从上到下编号为0-7页,每页64字节,涵盖半边显示屏的64行×64列×8bit点阵数据。向显示屏写数据实际上是向DDRAM中写数据,DDRAM不同页和不同列中的字节数据唯一对应显示屏一行的8个显示点。例如,向DDRAM第0页的第0列写入数据00010100B,则显示屏左上角第0列的8个显示点只有从上往下的第3和5点显示。不同页和不同列DDRAM的寻址,通过左半屏和右半屏各自的页地址计数器和列地址计数器实现,因此对显示屏DDRAM写显示数据前,需要先设置页地址和列地址。

左半屏右半屏

图1 12864液晶显示屏与内部RAM的对应关系

2.12864液晶显示器的内部结构及外部引脚

1)12864液晶显示器的内部结构

IC1控制模块的左半屏,IC2控制模块的右半屏。IC3为行驱动器。IC1,IC2为列驱动器。IC1,IC2,IC3含有如下主要功能器件。了解如下器件有利于对LCD模块的编程。

a) 指令寄存器(IR)

IR是用来寄存指令码,与数据寄存器寄存数据相对应.当D/I=1 时,在E信号下降沿的作用下,指令码写入IR。.

b) 数据寄存器(DR)

DR是用来寄存数据的,与指令寄存器寄存指令相对应.当D/I=1时,在E信号的下降沿作用下,图形显示数据写入DR,或在E信号高电平作用下由DR读到DB7~DB0 数据总线.DR 和DDRAM之间的数据传输是模块内部自动执行的。

c) 状态寄存器

有效数据位3位,用于记录“忙”信号标志位(BF),复位标志位(RST)以及开/关显示状态位(ON/OFF)。

d) XY地址计数器

XY地址计数器是一个9位计数器。高三位是X地址计数器,低6位为Y地址计数器,XY地址计数器实际上是作为DDRAM的地址指针,X地址计数器为DDRAM的页指针,Y地址计数器为DDRAM的Y地址指针。

X地址计数器是没有记数功能的,只能用指令设置。

Y地址计数器具有循环记数功能,各显示数据写入后,Y地址自动加1,Y地址指针从0到63。

e) 显示数据RAM(DDRAM)

DDRAM是存贮图形显示数据的。DDRAM与地址和显示位置的关系见图1。

f) Z地址计数器

Z地址计数器是一个6位计数器,此计数器具备循环记数功能,它是用于显示行扫描同步。当一行扫描完成,此地址计数器自动加1,指向下一行扫描数据,RST复位后Z地址计数器为0。

Z地址计数器可以用指令DISPLAY START LINE 预置。因此,显示屏幕的起始行就由此指令控制,即DDRAM的数据从哪一行开始显示在屏幕的第一行。此模块的DDRAM共64行,屏幕可以循环滚动显示64行。

2)12864液晶显示器的外部引脚

12864液晶显示模块共有20个引脚,包括8位双向数据线、6条控制线及电源线等。具体引脚功能见下表所示。

管脚号

1

2

3

4

5

管脚名称

VSS

VDD

V0

D/I

R/W

电平

0V

5.0V

-

H/L

H/L

管脚功能描述

电源地

电源电压

液晶显示器驱动电压

D/I=“H”,表示DB7~DB0为显示数据

D/I=“L”,表示DB7~DB0为显示指令数据

R/W=“H”,E=“H”,数据被读到DB7~DB0

R/W=“L”,E=“H→L”, DB7~DB0的数据被写到IR或DR

6 E H/L

使能信号:R/W=“L”,E信号下降沿锁存DB7~DB0

R/W=“H”,E=“H” DRAM数据读到

DB7~DB0(使能端,高电平有效)

7

8

9

10

管脚号

11

12

13

14

15

16

17

18

19

20

DB0

DB1

DB2

DB3

管脚名称

DB4

DB5

DB6

DB7

CS1

CS2

RESET

VEE

IED+

IED-

H/L

H/L

H/L

H/L

电平

H/L

H/L

H/L

H/L

H/L

H/L

H/L

-10V

DC+5V

DC0V

数据线

数据线

数据线

数据线

管脚功能描述

数据线

数据线

数据线

数据线

左半屏片选信号,低电平有效

右半屏片选信号,低电平有效

复位信号,低电平复位

LCD驱动负电压

背光板电源

背光板电源

3.12864液晶显示器的编程指令

1) 显示开关控制(DISPLAY ON/OFF)

代码

R/W D/I DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0

形式

0 0 0 0 1 1 1 1 1 1

设置屏幕显示开/关。D/I=1,开显示。D=0,关显示。不影响DDRAM中的内容。

2) 设置显示起始行(DISPLAY START LINE)

代码

R/W D/I DB7 DB6 DB5

形式

DB4 DB3 DB2 DB1 DB0

0 0 1 1 A5 A4 A3 A2 A1 A0

前面在介绍Z地址计数器时已经描述了显示起始行是由Z地址计数器控制的。A5~A0

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

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

DDRAM 行:62 63 0 1 2 3 ·················28 29

屏幕显示行: 1 2 3 4 5 6················· 31 32

3) 设置页地址(SET PAGE “X ADDRESS”)

代码

R/W D/I DB7 DB6 DB5 DB4 DB3 DB2

形式

0 0 1 0 1 1 1 A2

DB1 DB0

A1 A0

所谓页地址就是DDRAM的行地址,8行为一页,模块共64行即8页,A2~A0表示0~7页。读写数据对地址没有影响,页地址由本指令或RST信号改变复位后页地址为0。

4) 设置Y地址(SET Y ADDRESS)

代码

形式

R/W

0

D/I DB7

0 0

DB6

1

DB5

A5

DB4

A4

DB3

A3

DB2

A2

DB1

A1

DB0

A0

此指令的作用是将A5~A0送入Y地址计数器,作为DDRAM的Y地址指针。在对DDRAM进行读写操作后,Y地址指针自动加1,指向下一个DDRAM单元。

5) 读状态(STATUS READ)

代码

R/W D/I DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0

形式

1 0 BUSY 0 ON/OFF RET 0 0 0 0

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

BF:BF=1,内部正在进行操作,BF=0,空闲状态。

ON/OFF:ON/OFF=1,表示显示打开,ON/OFF=0,表示显示关闭。

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

6) 写显示数据(WRITE DISPLAY DATE)

代码

R/W D/I DB7 DB6 DB5

形式

0 1 D7 D6 D5

DB4

D4

DB3

D3

DB2

D2

DB1

D1

DB0

D0

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

7) 读显示数据(READ DISPLAY DATE)

代码

R/W D/I DB7 DB6 DB5

形式

DB4 DB3 DB2 DB1 DB0

1 1 D7 D6 D5 D4 D3 D2 D1 D0

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

3.

12864点阵型液晶显示器的接口电路设计

通过前面对12864显示屏引脚功能的分析可以知道,该模块有一个整体的片选信号“E”,只有当该信号为高电平时,所有的电路才会有效。另外左右半屏各有一个选择信号CS1和CS2,CS1和CS2各自为低电平时,分别选中左半屏和右半屏。为了区分读写的是数据还是指令,还设置了一个数据/指令控制线D/I。根据这些原则,设计出接口电路如图3所示。

图3 液晶显示器的接口电路

由于CS0的地址范围为280H-283H,由接口电路的设计可得液晶屏的相关地址,如下表。

操作

向左半屏写指令

向右半屏写指令

读/写左半屏数据

读/写右半屏数据

读状态寄存器

A1A0

00

10

01

11

00

端口地址

280H

282H

281H

283H

280H

4.

12864点阵型液晶显示器的软件设计

对液晶显示器的编程就是向DDRAM中写数据。在写DDRAM之前,需要先清除RAM,且左屏和右屏要分别进行清除。方法就是向RAM的所有单元写入0值。图4是液晶显示器的编程流程。图5是向LCD写显示数据的流程图。

广告字幕机是用LCD输出不同的汉字和图形。要液晶显示器显示不同的图形或汉字,就是向DDRAM中写入不同的数据。根据前面所说的液晶显示屏与DDRAM的对应关系,可以构造不同的数据来显示不同的图形和汉字。

开始系统初始化写LCD左屏数据清左屏RAM写LCD左屏数据清左屏RAM左右屏开显示

图4 液晶显示器的编程流程

将起始页地址存入BL设置页地址设置列地址LCD工作忙N写显示RAMY图5

向LCD写显示数据的流程图已显示64列?Y页地址加1N页地址已设置8次Y结束N

5.

12864点阵型液晶显示器驱动程序设计 VHDL程序源代码:

LIBRARY IEEE;

USE _LOGIC_;

USE _LOGIC_;

USE _LOGIC_;

ENTITY LCD_TEXT IS

PORT(

CLK: IN STD_LOGIC;

RS,RW,CS1,CS2,E: OUT STD_LOGIC;

Q: BUFFER STD_LOGIC_VECTOR(7 DOWNTO 0) );

END;

ARCHITECTURE BEHAV OF LCD_TEXT IS

TYPE STATES IS(ST1,ST2,ST3,ST4,ST5,ST6,ST7,ST8,ST9,ST10,ST11,ST12,ST13,ST14,ST15,

STA1,STA2,STA3,STA4,STA5,STA6,STA7,STA8,STA9,STA10,

ST16,ST17,ST18,ST19,ST20,ST21,ST22,ST23,ST24,ST25,ST26,ST27,ST28,ST29,ST30,ST31,ST32,ST33,ST34);

SIGNAL PRE_STATE,NEXT_STATE:STATES;

SIGNAL DATALOCK,EN,RST1:STD_LOGIC;

SIGNAL XPAGE:STD_LOGIC_VECTOR(7 DOWNTO 0):="10111000";

SIGNAL YADDR:STD_LOGIC_VECTOR(7 DOWNTO 0):="01000000";

BEGIN

CLOCK:PROCESS(CLK) --将时钟进行分频

VARIABLE CONT:INTEGER RANGE 0 TO 20;

BEGIN

IF CLK'EVENT AND CLK='1' THEN

CONT:=CONT+1;

IF CONT = 12 THEN DATALOCK<='0';CONT:=0; --DATALOCK是13进制

ELSIF CONT=9 THEN

DATALOCK<='1';

END IF;

END IF;

END PROCESS CLOCK;

EN<= NOT DATALOCK;

E<=EN;

DATAK:PROCESS(EN,PRE_STATE)

VARIABLE CNT : INTEGER RANGE 0 TO 255;

BEGIN

IF EN'EVENT AND EN='1' THEN

CASE PRE_STATE IS

WHEN STA1=>RS<='0';RW<='1';CS1<='0';CS2<='1';IF Q="00100000" THEN PRE_STATE<=ST1; END

IF; --CHECK BUSY

WHEN ST1=>RS<='0';RW<='0';CS1<='0';CS2<='1';Q<="00111111";PRE_STATE<=ST2; --显示开关设置

WHEN ST2=>RS<='0';RW<='0';CS1<='0';CS2<='1';Q<="11000000";PRE_STATE<=ST3; --起始行设置

--左半清屏

WHEN ST3=>RS<='0';RW<='0';CS1<='0';CS2<='1';Q<=XPAGE;PRE_STATE<=ST4; --页地址设置

WHEN ST4=>RS<='0';RW<='0';CS1<='0';CS2<='1';Q<=YADDR;PRE_STATE<=ST5; --列地址设置

WHEN ST5=>RS<='1';RW<='0';CS1<='0';CS2<='1';

IF XPAGE>"10111111" THEN

XPAGE<="10111000";

YADDR<="01000000";

PRE_STATE<=ST6; --左半清屏完毕,进入下一状态

ELSIF YADDR>"01111111" THEN

YADDR<="01000000";

XPAGE<=XPAGE+1; --清完一页,开始下一页

PRE_STATE<=ST3; --返回重新设置页地址

ELSE

Q<="00000000";YADDR<=YADDR+1;PRE_STATE<=ST5; --清完一列,开始下一列

END IF;

--右半清屏

IF;

WHEN ST6=>RS<='0';RW<='0';CS1<='1';CS2<='0';Q<=XPAGE;PRE_STATE<=ST7; --页地址设置

WHEN ST7=>RS<='0';RW<='0';CS1<='1';CS2<='0';Q<=YADDR;PRE_STATE<=ST8; --列地址设置

WHEN ST8=>RS<='1';RW<='0';CS1<='1';CS2<='0';

IF XPAGE>"10111111" THEN

XPAGE<="10111000";

YADDR<="01000000";

PRE_STATE<=ST9; ----右半清屏完毕,进入下一状态

ELSIF YADDR>"01111111" THEN

YADDR<="01000000";

XPAGE<=XPAGE+1; --清完一页,开始下一页

PRE_STATE<=ST6; --返回重新设置页地址

ELSE

Q<="00000000";YADDR<=YADDR+1;PRE_STATE<=ST8; --清完一列,开始下一列

END IF;

--清屏完毕,开始显示数据

--显示上半边

IF;

WHEN ST9=>RS<='0';RW<='0';CS1<='0';CS2<='1';Q<="00111111";PRE_STATE<=ST10; --ON/OFF

WHEN ST10=>RS<='0';RW<='0';CS1<='0';CS2<='1';Q<=XPAGE;PRE_STATE<=ST11; --SET PAGE

PAGE 0

WHEN ST11=>RS<='0';RW<='0';CS1<='0';CS2<='1';Q<=YADDR;PRE_STATE<=ST12; --SET ROW

ROW 0

WHEN ST12=>RS<='1';RW<='0';CS1<='0';CS2<='1';

Q<=UNIVERSITY(CNT);

IF CNT=16 THEN

XPAGE<="10111001";YADDR<="01000000";PRE_STATE<=ST10; --0~15

XPAGE<="10111000";YADDR<="01010000";PRE_STATE<=ST10; --16~31

XPAGE<="10111001";YADDR<="01010000";PRE_STATE<=ST10;

XPAGE<="10111000";YADDR<="01100000";PRE_STATE<=ST10; --32~47

XPAGE<="10111001";YADDR<="01100000";PRE_STATE<=ST10;

XPAGE<="10111000";YADDR<="01110000";PRE_STATE<=ST10; --48~63

XPAGE<="10111001";YADDR<="01110000";PRE_STATE<=ST10;

ELSIF CNT=32 THEN

ELSIF CNT=48 THEN

ELSIF CNT=64 THEN

ELSIF CNT=80 THEN

ELSIF CNT=96 THEN

ELSIF CNT=112 THEN

WHEN STA3=>RS<='0';RW<='1';CS1<='0';CS2<='1';IF Q="00100000" THEN PRE_STATE<=ST9;END

WHEN STA2=>RS<='0';RW<='1';CS1<='0';CS2<='1';IF Q="00100000" THEN PRE_STATE<=ST6;END

IF;

ELSIF CNT=128 THEN

XPAGE<="10111010";YADDR<="01000000";PRE_STATE<=ST13;CNT:=0;

ELSE YADDR<=YADDR+1;CNT:=CNT+1;PRE_STATE<=ST12;

END IF;

WHEN STA4=>RS<='0';RW<='1';CS1<='0';CS2<='1';IF Q="00100000" THEN PRE_STATE<=ST13;END

WHEN ST13=>RS<='0';RW<='0';CS1<='0';CS2<='1';Q<=XPAGE;PRE_STATE<=ST14; --SET PAGE

PAGE 2

WHEN ST14=>RS<='0';RW<='0';CS1<='0';CS2<='1';Q<=YADDR;PRE_STATE<=ST15; --SET ROW

ROW 0

WHEN ST15=>RS<='1';RW<='0';CS1<='0';CS2<='1';

Q<=CLASS(CNT);

IF CNT=16 THEN

XPAGE<="10111011";YADDR<="01000000";PRE_STATE<=ST13; --0~15

ELSIF CNT=32 THEN

XPAGE<="10111010";YADDR<="01010000";PRE_STATE<=ST13; --16~31

XPAGE<="10111011";YADDR<="01010000";PRE_STATE<=ST13;

XPAGE<="10111010";YADDR<="01100000";PRE_STATE<=ST13; --32~47

XPAGE<="10111011";YADDR<="01100000";PRE_STATE<=ST13;

XPAGE<="10111010";YADDR<="01110000";PRE_STATE<=ST13; --48~63

XPAGE<="10111011";YADDR<="01110000";PRE_STATE<=ST13;

XPAGE<="10111100";YADDR<="01000000";PRE_STATE<=ST16;CNT:=0;

ELSIF CNT=48 THEN

ELSIF CNT=64 THEN

ELSIF CNT=80 THEN

ELSIF CNT=96 THEN

ELSIF CNT=112 THEN

ELSIF CNT=128 THEN

ELSE YADDR<=YADDR+1;CNT:=CNT+1;PRE_STATE<=ST15;

END IF;

WHEN STA5=>RS<='0';RW<='1';CS1<='0';CS2<='1';IF Q<="00100000" THEN PRE_STATE<=ST16;

WHEN ST16=>RS<='0';RW<='0';CS1<='0';CS2<='1';Q<=XPAGE;PRE_STATE<=ST17; --SET PAGE

END IF;

PAGE 4

WHEN ST17=>RS<='0';RW<='0';CS1<='0';CS2<='1';Q<=YADDR;PRE_STATE<=ST18; --SET ROW

ROW 0

WHEN ST18=>RS<='1';RW<='0';CS1<='0';CS2<='1';

Q<=NAME(CNT);

IF CNT=16 THEN

XPAGE<="10111101";YADDR<="01000000";PRE_STATE<=ST16; --0~15

XPAGE<="10111100";YADDR<="01010000";PRE_STATE<=ST16; --16~31

XPAGE<="10111101";YADDR<="01010000";PRE_STATE<=ST16;

ELSIF CNT=32 THEN

ELSIF CNT=48 THEN

ELSIF CNT=64 THEN

XPAGE<="10111100";YADDR<="01100000";PRE_STATE<=ST16; --32~47

ELSIF CNT=80 THEN

XPAGE<="10111101";YADDR<="01100000";PRE_STATE<=ST16;

XPAGE<="10111100";YADDR<="01110000";PRE_STATE<=ST16; --48~63

XPAGE<="10111101";YADDR<="01110000";PRE_STATE<=ST16;

XPAGE<="10111110";YADDR<="01000000";PRE_STATE<=ST19;CNT:=0;

ELSIF CNT=96 THEN

ELSIF CNT=112 THEN

ELSIF CNT=128 THEN

ELSE YADDR<=YADDR+1;CNT:=CNT+1;PRE_STATE<=ST18;

END IF;

WHEN STA6=>RS<='0';RW<='1';CS1<='0';CS2<='1';IF Q="00100000" THEN PRE_STATE<=ST19;

WHEN ST19=>RS<='0';RW<='0';CS1<='0';CS2<='1';Q<=XPAGE;PRE_STATE<=ST20; --SET PAGE

END IF;

PAGE 6

WHEN ST20=>RS<='0';RW<='0';CS1<='0';CS2<='1';Q<=YADDR;PRE_STATE<=ST21; --SET ROW

ROW 0

WHEN ST21=>RS<='1';RW<='0';CS1<='0';CS2<='1';

Q<=VOLTAGE(CNT);

IF CNT=16 THEN

XPAGE<="10111111";YADDR<="01000000";PRE_STATE<=ST19; --0~15

XPAGE<="10111110";YADDR<="01010000";PRE_STATE<=ST19; --16~31

XPAGE<="10111111";YADDR<="01010000";PRE_STATE<=ST19;

XPAGE<="10111110";YADDR<="01100000";PRE_STATE<=ST19; --32~47

XPAGE<="10111111";YADDR<="01100000";PRE_STATE<=ST19;

XPAGE<="10111110";YADDR<="01110000";PRE_STATE<=ST19; --48~63

XPAGE<="10111111";YADDR<="01110000";PRE_STATE<=ST19;

XPAGE<="10111000";YADDR<="01000000";PRE_STATE<=ST22;

ELSIF CNT=32 THEN

ELSIF CNT=48 THEN

ELSIF CNT=64 THEN

ELSIF CNT=80 THEN

ELSIF CNT=96 THEN

ELSIF CNT=112 THEN

ELSIF CNT=128 THEN

ELSE YADDR<=YADDR+1;CNT:=CNT+1;PRE_STATE<=ST21;

END IF;

--next print

WHEN STA7=>RS<='0';RW<='1';CS1<='0';CS2<='1';IF Q="00100000" THEN PRE_STATE<=ST22;

END IF;

WHEN ST22=>RS<='0';RW<='0';CS1<='1';CS2<='0';Q<="00111111";PRE_STATE<=ST23; --ON/OFF

WHEN ST23=>RS<='0';RW<='0';CS1<='1';CS2<='0';Q<=XPAGE;PRE_STATE<=ST24; --SET PAGE

PAGE 0

WHEN ST24=>RS<='0';RW<='0';CS1<='1';CS2<='0';Q<=YADDR;PRE_STATE<=ST25; --SET ROW

ROW 0

WHEN ST25=>RS<='1';RW<='0';CS1<='1';CS2<='0';

Q<=UNIVERSITY(CNT);

IF CNT=144 THEN

XPAGE<="10111001";YADDR<="01000000";PRE_STATE<=ST23; --0~15

XPAGE<="10111000";YADDR<="01010000";PRE_STATE<=ST23; --16~31

XPAGE<="10111001";YADDR<="01010000";PRE_STATE<=ST23;

XPAGE<="10111000";YADDR<="01100000";PRE_STATE<=ST23; --32~47

XPAGE<="10111001";YADDR<="01100000";PRE_STATE<=ST23;

XPAGE<="10111000";YADDR<="01110000";PRE_STATE<=ST23; --48~63

XPAGE<="10111001";YADDR<="01110000";PRE_STATE<=ST23;

XPAGE<="10111010";YADDR<="01000000";PRE_STATE<=ST26;CNT:=128;

ELSIF CNT=160 THEN

ELSIF CNT=176 THEN

ELSIF CNT=192 THEN

ELSIF CNT=208 THEN

ELSIF CNT=224 THEN

ELSIF CNT=240 THEN

ELSIF CNT=256 THEN

ELSE YADDR<=YADDR+1;CNT:=CNT+1;PRE_STATE<=ST25;

END IF;

WHEN STA8=>RS<='0';RW<='1';CS1<='0';CS2<='1';IF Q="00100000" THEN PRE_STATE<=ST26;

END IF;

WHEN ST26=>RS<='0';RW<='0';CS1<='1';CS2<='0';Q<=XPAGE;PRE_STATE<=ST27; --SET PAGE

PAGE 2

WHEN ST27=>RS<='0';RW<='0';CS1<='1';CS2<='0';Q<=YADDR;PRE_STATE<=ST28; --SET ROW

ROW 0

WHEN ST28=>RS<='1';RW<='0';CS1<='1';CS2<='0';

Q<=CLASS(CNT);

IF CNT=144 THEN

XPAGE<="10111011";YADDR<="01000000";PRE_STATE<=ST26; --0~15

XPAGE<="10111010";YADDR<="01010000";PRE_STATE<=ST26; --16~31

XPAGE<="10111011";YADDR<="01010000";PRE_STATE<=ST26;

XPAGE<="10111010";YADDR<="01100000";PRE_STATE<=ST26; --32~47

XPAGE<="10111011";YADDR<="01100000";PRE_STATE<=ST26;

XPAGE<="10111010";YADDR<="01110000";PRE_STATE<=ST26; --48~63

ELSIF CNT=160 THEN

ELSIF CNT=176 THEN

ELSIF CNT=192 THEN

ELSIF CNT=208 THEN

ELSIF CNT=224 THEN

ELSIF CNT=240 THEN

XPAGE<="10111011";YADDR<="01110000";PRE_STATE<=ST26;

XPAGE<="10111100";YADDR<="01000000";PRE_STATE<=ST29;CNT:=128;

ELSIF CNT=256 THEN

ELSE YADDR<=YADDR+1;CNT:=CNT+1;PRE_STATE<=ST28;

END IF;

WHEN STA9=>RS<='0';RW<='1';CS1<='0';CS2<='1';IF Q="00100000" THEN PRE_STATE<=ST29;

WHEN ST29=>RS<='0';RW<='0';CS1<='1';CS2<='0';Q<=XPAGE;PRE_STATE<=ST30; --SET PAGE

END IF;

PAGE 4

WHEN ST30=>RS<='0';RW<='0';CS1<='1';CS2<='0';Q<=YADDR;PRE_STATE<=ST31; --SET ROW

ROW 0

WHEN ST31=>RS<='1';RW<='0';CS1<='1';CS2<='0';

Q<=NAME(CNT);

IF CNT=144 THEN

XPAGE<="10111101";YADDR<="01000000";PRE_STATE<=ST29; --0~15

ELSIF CNT=160 THEN

XPAGE<="10111100";YADDR<="01010000";PRE_STATE<=ST29; --16~31

XPAGE<="10111101";YADDR<="01010000";PRE_STATE<=ST29;

XPAGE<="10111100";YADDR<="01100000";PRE_STATE<=ST29; --32~47

XPAGE<="10111101";YADDR<="01100000";PRE_STATE<=ST29;

XPAGE<="10111100";YADDR<="01110000";PRE_STATE<=ST29; --48~63

XPAGE<="10111101";YADDR<="01110000";PRE_STATE<=ST29;

XPAGE<="10111110";YADDR<="01000000";PRE_STATE<=ST32;CNT:=128;

ELSIF CNT=176 THEN

ELSIF CNT=192 THEN

ELSIF CNT=208 THEN

ELSIF CNT=224 THEN

ELSIF CNT=240 THEN

ELSIF CNT=256 THEN

ELSE YADDR<=YADDR+1;CNT:=CNT+1;PRE_STATE<=ST31;

END IF;

STA10=>RS<='0';RW<='1';CS1<='0';CS2<='1';IF Q="00100000" THEN WHEN

PRE_STATE<=ST32;END IF;

WHEN ST32=>RS<='0';RW<='0';CS1<='1';CS2<='0';Q<=XPAGE;PRE_STATE<=ST33; --SET PAGE

PAGE 6

WHEN ST33=>RS<='0';RW<='0';CS1<='1';CS2<='0';Q<=YADDR;PRE_STATE<=ST34; --SET ROW

ROW 0

WHEN ST34=>RS<='1';RW<='0';CS1<='1';CS2<='0';

Q<=VOLTAGE(CNT);

IF CNT=144 THEN

XPAGE<="10111111";YADDR<="01000000";PRE_STATE<=ST32; --0~15

ELSIF CNT=160 THEN

XPAGE<="10111110";YADDR<="01010000";PRE_STATE<=ST32; --16~31

ELSIF CNT=176 THEN

XPAGE<="10111111";YADDR<="01010000";PRE_STATE<=ST32;

XPAGE<="10111110";YADDR<="01100000";PRE_STATE<=ST32; --32~47

XPAGE<="10111111";YADDR<="01100000";PRE_STATE<=ST32;

XPAGE<="10111110";YADDR<="01110000";PRE_STATE<=ST32; --48~63

XPAGE<="10111111";YADDR<="01110000";PRE_STATE<=ST32;

YADDR<="01000000";CNT:=128;

ELSIF CNT=192 THEN

ELSIF CNT=208 THEN

ELSIF CNT=224 THEN

ELSIF CNT=240 THEN

ELSIF CNT=256 THEN

ELSE YADDR<=YADDR+1;CNT:=CNT+1;PRE_STATE<=ST34;

END IF;

WHEN OTHERS=>PRE_STATE<=STA1;

END CASE;

END IF;

END PROCESS DATAK;

END BEHA

6.

软件仿真和硬件验证结果波形

检忙 显示开关设置 起始行设置 清左屏

开始淸左屏

左屏清除完毕清右屏

右屏清除

按页按列清右屏

写左屏

写右屏

7. 结束语

本文设计的VHDL语言程序已在MAXPLUSⅡ工具软件上进行了编译、仿真和调试,并通过编程器下载到了EP1K100QC208-3芯片。经过实验验证,设计正确,其各项显示数据正常。本文给出的设计思想也适用于其他基于PLD芯片的系统设计。

8. 心得体会

通过此次12864LCD驱动程序的编写,我知道了12864驱动程序有七个指令,它们分别是:“检忙” “写指令” “写数据” “写显示开关”“写页”“写列”“写初始行”。12864分左右两屏,像素点为128*64个像素点,行有128个像素点,列有64个像素点,行又设置为8页,在12864默认状态下中文字体都是16*16的大小,每个页包含8个像素行,所以要显示一个中文就需要2页+两行;初始行的设定可以使得你要显示的字出现在任意你想要的位置。12864跟1602不一样,1602写指令和写数据就可以了,12864就不行,它还有控制到CS1 和 CS2两个脚,通过HD61203对整个液晶进行控制

参考文献

[1]潘松.EDA技术实用教程[M].北京:科学出版社,2003.

[2]卢毅.VHDL与数字电路设计[M].北京:科学出版社,2001.

[3]林敏.VHDL数字系统设计与高层次综合[M].北京:电子工业出版社,2001.

[4]齐洪喜.VHDL电路设计[M].北京:清华大学出版社,2004.

[5]A novel dynamic frame rate control algorithm for H.264 low-bit-rate video coding - 高技术通讯:英文版 - 杨静 Fang Xiangzhong

[6]/post/ , 2007-09-10

[7]/s/blog_, 2009-04-02

发布评论

评论列表 (0)

  1. 暂无评论