12864lcd显示部分试验总结报告
管岱2014.12.19 【实验目的】
在12864液晶显示屏上能够显示出在4×4小键盘上输入的激励源频率值,如输入“789HZ”、“8MHZ”、“2.3KHZ”,显示出“789H”、“8M”、“2.3K”。并且要求此部分程序有较好的可移植性,在最后对电阻率值的显示上能够较好的应用。
【实验原理】
12864-3A接口说明表:
在12864液晶显示原理的基础上,通过在ise上编写vhdl语言,使之能够在fpga学习板上顺利显示数据。
【实验内容】
12864的显示原理并不难理解,并且在以前也用汇编语言实现过,所以本次实验的难点不在于显示原理的理解,而在于VHDL语言的编写。
在实验初期,由于对vhdl语言的不熟练,我们“类比”汇编语言的显示程序,编写出如下的程序:
发现编译时就出现了问题,出现如“multi-source in unit on signal ”的报错。在仔细调试检查后发现,我们错误的原因在于:在不同的进程中对同一个信号赋值。例如,在写指令的进程中,将rs信号置‘0’,而在后面写数据的进程中又将rs置‘1’,由于在vhdl中各进程之间是并行的关系,因此这样编写程序会出现在同一时刻对同一个引脚赋高电平和低电平,从而出现矛盾。虽然在程序实际运行中,写指令进程在系统一上电就会完成,远早于写数据进程,但是在逻辑上这样编写是不符合VHDL语言的规则的。
因此,我们利用状态机的思想,将写指令和写数据的两个进程合二为一。程序片段如下:
利用状态机,将写指令和写数据的各个步骤分为一个一个分立的状态,顺序执行。这样编写将对同一个引脚信号的变化放在一个进程中,很好的解决了之前存在的问题。
并且受此启发,在写数据的程序段,对百位、十位、个位以及单位的译码程序中,将原本分别对各自数位信号敏感的四个单独进程改成了受一个的时钟上升沿敏感的一个进程,从而较好的保证了程序的时序性和同步性,经实验验证效果良好。
【实验改进】
最初的设想是三位有效数字(k
1、k
2、k3),加上一个单位(hz、khz、mhz)就能够满足大部分数字范围。但是后来发现这样不能实现例如“1200HZ”的数据。因此改进实验程序,加入小数点。
在十位的译码程序中加入对小数点的译码,这样当输入第二位时按下小数点的按键,就能在显示屏上显示出小数点,且不影响其它位显示。因此若要显示“1200HZ”的频率,则可显示出“1.2 K”。
【实验体会】
对不熟悉的编程语言,我们不能拿别的语言的相关程序来生搬硬套,不能用别的语言的思维来考虑本语言的编程。在VHDL语言中,“进程”的思想十分重要,进程之间相互并行的特点既可以帮助我们利用模块化的思想编写程序,但同时也给不熟悉VHDL的人带来了困难。多阅读程序,多练习编程,多理解本语言的思想,不仅对VHDL语言是这样,在今后学习其他语言也是同样的道理。
【实验代码】
library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; use ieee.std_logic_arith.all; use ieee.numeric_std.all;
ENTITY lcd12864 IS
PORT (
clk
--reset
rs
rw
en
dat
DOWNTO 0);
--rst
: IN std_logic;
: IN std_logic;
: OUT std_logic;
: OUT std_logic;
: OUT std_logic_vector(7 : OUT std_logic);
: OUT std_logic;
LCD_N
: OUT std_logic;
LCD_P
: OUT std_logic;
PSB
: OUT std_logic;
LCD_RST
: OUT std_logic; --------------
k1
: in std_logic_vector(7 downto 0);
k2
: in std_logic_vector(7 downto 0); 0); 0)
);
------------
END lcd12864;
ARCHITECTURE fun OF lcd12864 IS k4
: in std_logic_vector(7 downto k3
: in std_logic_vector(7 downto
--//状态定义
SIGNAL e
: std_logic;
SIGNAL counter
: std_logic_vector(15 DOWNTO 0);
SIGNAL current
DOWNTO 0);
SIGNAL clkr
SIGNAL cnt
DOWNTO 0);
CONSTANT set0
DOWNTO 0) := \"00000000\";
CONSTANT set1
DOWNTO 0) := \"00000001\";
CONSTANT set2
DOWNTO 0) := \"00000010\";
CONSTANT set3
DOWNTO 0) := \"00000011\";
CONSTANT set4
DOWNTO 0) := \"00100101\";
CONSTANT set5
DOWNTO 0) := \"00100110\";
: std_logic_vector(7 : std_logic;
: std_logic_vector(1
: std_logic_vector(7
: std_logic_vector(7
: std_logic_vector(7
: std_logic_vector(7
: std_logic_vector(7
: std_logic_vector(7
CONSTANT dat0
: std_logic_vector(7 DOWNTO 0) := \"00000100\";
CONSTANT dat1
: std_logic_vector(7 DOWNTO 0) := \"00000101\";
CONSTANT dat2
: std_logic_vector(7 DOWNTO 0) := \"00000110\";
CONSTANT dat3
DOWNTO 0) := \"00000111\";
CONSTANT dat4
DOWNTO 0) := \"00001000\";
CONSTANT dat5
DOWNTO 0) := \"00001001\";
CONSTANT dat6
DOWNTO 0) := \"00001010\";
CONSTANT dat7
DOWNTO 0) := \"00001011\";
CONSTANT dat8
DOWNTO 0) := \"00001100\";
CONSTANT dat9
DOWNTO 0) := \"00001101\";
CONSTANT dat10
DOWNTO 0) := \"00001110\";
: std_logic_vector(7 : std_logic_vector(7 : std_logic_vector(7 : std_logic_vector(7 : std_logic_vector(7 : std_logic_vector(7 : std_logic_vector(7 : std_logic_vector(7
CONSTANT dat11
: std_logic_vector(7 DOWNTO 0) := \"00001111\";
CONSTANT dat12
: std_logic_vector(7 DOWNTO 0) := \"00010000\";
CONSTANT dat13
: std_logic_vector(7 DOWNTO 0) := \"00010001\";
CONSTANT dat14
: std_logic_vector(7 DOWNTO 0) := \"00010010\";
CONSTANT nul
: std_logic_vector(7 DOWNTO 0) := \"00110000\";
SIGNAL dat_r
: std_logic_vector(7 DOWNTO 0);
SIGNAL rs_r
: std_logic;
SIGNAL rw_r
: std_logic;
SIGNAL en_r
: std_logic;
---
SIGNAL k1_r
: std_logic_vector(7 DOWNTO 0); SIGNAL k2_r
: std_logic_vector(7 DOWNTO 0);
SIGNAL k3_r
: std_logic_vector(7 DOWNTO 0);
SIGNAL k4_r
: std_logic_vector(7 DOWNTO 0);
SIGNAL a :
std_logic_vector (7 DOWNTO 0); SIGNAL b :
std_logic_vector (7 DOWNTO 0); SIGNAL c :
std_logic_vector (7 DOWNTO 0); SIGNAL d :
std_logic_vector (7 DOWNTO 0); ----------- BEGIN
dat
rs
rw
en
k1_r
k2_r
k3_r
k4_r
PSB
LCD_RST
LCD_N
LCD_P
分频
PROCESS(clk)
BEGIN
IF(clk\'EVENT AND clk = \'1\') THEN
counter
IF (counter = \"0000000000001111\") THEN
clkr
END IF;
END IF;
END PROCESS;
PROCESS(clkr)
BEGIN
IF(clkr\'EVENT AND clkr = \'1\') THEN
CASE current IS
--时钟
WHEN set0 =>
rs_r
dat_r
--初始化 --基本指令集
current
WHEN set1 =>
rs_r
dat_r
current
WHEN set2 =>
rs_r
dat_r
current
WHEN set3 =>
rs_r
dat_r
current
WHEN set4 =>
rs_r
dat_r
current
--开显示 --光标右移 --清屏
--设置坐标位置
WHEN dat0 =>
rs_r
dat_r
--发送第一行数据
current
WHEN dat1 =>
rs_r
dat_r
current
WHEN dat2 =>
rs_r
dat_r
current
WHEN dat3 =>
rs_r
dat_r
current
WHEN nul =>
--这段保证前段显示部分至少执行一遍
--然后把液晶的En脚拉高,完成一次读写过程
rs_r
dat_r
IF (cnt /= \"10\") THEN
e
current
cnt
ELSE
current
e
cnt
END IF;
WHEN OTHERS =>
current
END CASE;
END IF;
END PROCESS;
en_r
rw_r
-- rst
--------------------
proce(clkr)
begin
IF(clkr\'EVENT AND clkr = \'1\') THEN
case k1_r is
--百位 when \"00000000\"=>a
when \"00000001\"=>a
when \"00000010\"=>a
when \"00000011\"=>a
when \"00000100\"=>aaaaaaa
case k2_r is
when \"00000000\"=>b
when \"00000001\"=>bbbbbbbbbb
--十位
case k3_r is
--个位
when \"00000000\"=>c
when \"00000001\"=>c
when \"00000010\"=>c
when \"00000011\"=>c
when \"00000100\"=>c
when \"00000101\"=>c
when \"00000110\"=>c
when \"00000111\"=>c
when \"00001000\"=>c
when \"00001001\"=>c
when others =>c
case k4_r is
when \"00001010\"=>d
when \"00001011\"=>d
when \"00001100\"=>d
when others =>d
--单位--H --K --M
end if; end proce; END fun;