-------------12864液晶的显示-----------
----时钟:10MHZ
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity lcd12864 is
generic(
divide_500k:integer:=20;--20分频后:500KHZ:2us
cnt1_value:integer:=50
);
port(
clk,reset:in std_logic;
rs,rw,en:out std_logic;
data:out std_logic_vector(7 downto 0)
);
end entity;
architecture behavior of lcd12864 is
type word is array(0 to 3) of std_logic_vector(7 downto 0);--因为大家的习惯,数组中的左起第1个数为数组中的最低位对应的数,所以设置为array(0 to 3),而不是array(3 downto 0)。此处若不注意,容易出错。
type state is(
set_dlnf1,set_dlnf2,set_cursor,set_dcb,set_shift,
set_ddram,
write_name,
over
);
constant name:word:=("11010110","11010000","10111001","11111010");--中D6D0 国B9FA
--constant name:word:=("11010000","11101100","10111110","10101001");--徐D6D0 京B9FA
signal pr_state:state;
signal newclk:std_logic;
begin
process(clk) is
variable num:integer range 0 to divide_500k;
begin
if(clk'event and clk='1')then
num:=num+1;
if(num=divide_500k) then
num:=0;
end if;
if(num<divide_500k/2) then--设置占空比
newclk<='0';
else newclk<='1';
end if;
end if;
end process;
process(newclk,reset,pr_state) is
variable cnt1:integer range 0 to 100*cnt1_value:=0;
variable cnt2:integer range 0 to 100:=0;
begin
if(reset='0') then
pr_state<=set_dlnf1; --把状态set_dlnf1赋于pr_state
cnt1:=0;
cnt2:=0;
en<='0';
data<="ZZZZZZZZ";
elsif(newclk'event and newclk='1') then
case pr_state is
when set_dlnf1=>
cnt1:=cnt1+1;
if(cnt1<cnt1_value) then
en<='0';
rs<='0'; --命令
rw<='0'; --写
elsif(cnt1<2*cnt1_value) then
data<="00110000"; --选择8位数据基本指令集:0x30
elsif(cnt1<20*cnt1_value) then
en<='1';
elsif(cnt1=20*cnt1_value) then
en<='0';
cnt1:=0;
pr_state<=set_dlnf2;
end if;
when set_dlnf2=>
cnt1:=cnt1+1;
if(cnt1<cnt1_value) then
en<='0';
elsif(cnt1<2*cnt1_value) then
data<="00110000"; --选择8位数据基本指令集:0x30
elsif(cnt1<20*cnt1_value) then
en<='1';
elsif(cnt1=20*cnt1_value) then
en<='0';
cnt1:=0;
pr_state<=set_cursor;
end if;
when set_cursor=>
cnt1:=cnt1+1;
if(cnt1<cnt1_value) then
en<='0';
elsif(cnt1<2*cnt1_value) then
data<="00001100"; --整体显示设置:光标OFF 反光0FF:0x0c
elsif(cnt1<20*cnt1_value) then
en<='1';
elsif(cnt1=20*cnt1_value) then
en<='0';
cnt1:=0;
pr_state<=set_dcb;
end if;
when set_dcb=>
cnt1:=cnt1+1;
if(cnt1<cnt1_value) then
en<='0';
elsif(cnt1<2*cnt1_value) then
data<="00000001"; --清除显示,并且认定地址指针为00h:0x01
elsif(cnt1<20*cnt1_value) then
en<='1';
elsif(cnt1=20*cnt1_value) then
en<='0';
cnt1:=0;
pr_state<=set_shift;
end if;
when set_shift=>
cnt1:=cnt1+1;
if(cnt1<cnt1_value) then
en<='0';
elsif(cnt1<2*cnt1_value) then
data<="00000110"; --指定游标的移动方向及指定显示的移位:0x06
elsif(cnt1<20*cnt1_value) then
en<='1';
elsif(cnt1=20*cnt1_value) then
en<='0';
cnt1:=0;
pr_state<=set_ddram;
end if;
when set_ddram=>
cnt1:=cnt1+1;
if(cnt1<cnt1_value) then
en<='0';
elsif(cnt1<2*cnt1_value) then
data<="10000011"; --从第一行的第一个字开始显示:0x80
--从第一行的第四个字开始显示:0x80+3
elsif(cnt1<20*cnt1_value) then
en<='1';
elsif(cnt1=20*cnt1_value) then
en<='0';
cnt1:=0;
pr_state<=write_name;
end if;
when write_name=>
cnt1:=cnt1+1;
if cnt1<1*cnt1_value then
en<='0';
rs<='1'; ------------选择数据
rw<='0';
elsif cnt1<2*cnt1_value then
data<=name(cnt2); ------------送数据
elsif cnt1<20*cnt1_value then
en<='1'; -----在上升沿时,数据才能写入液晶,所以要先送数据,再让使能端变高
elsif cnt1=20*cnt1_value then
en<='0'; -----通过液晶的时序图知:使能端先低,送数据,使能端升高,再变低。
cnt1:=0;
cnt2:=cnt2+1;
if cnt2=4 then----倘若使能端的触发方式错误,此处也许要大于4的数才有显示
pr_state<=over;
cnt2:=0;
end if;
end if;
when over=>
null;
when others=>
en<='Z';
rs<='Z';
rw<='Z';
data<=(others=>'Z');
cnt1:=0;
cnt2:=0;
end case;
end if;
end process;
end architecture;
这个液晶程序,花了十来天的时间,今天总算与它有了了结。程序中,之所以只在第一行的第四列起,显示了“中国”两个字,主要是简单,便于网友理解。
这个程序我试过,管用的,第二篇也是管用的 是不是你的时钟频率不一样呢?