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