📄 lcd.vhd
字号:
-- -----------------------------------------------------------------------------
--
-- 文件名 : lcd.vhd
--
-- 功能 : 液晶 1602 lcd 的模块.
--
-- 端口 : CLK_Z : in 25MHz , 50% 占空比的时钟信号.
-- pulse1K : in 1KHz 的 脉冲信号, 占空比很小.
-- pulse1M : in 1MHz 的 脉冲信号, 占空比很小.
-- RESET : in 大于671.08864ms的 复位 信号.
--
-- enable : in 写显示寄存器的使能信号.
-- wren : in 写显示寄存器的使能信号.
-- writeAddr : in 写显示寄存器的地址.
-- writeData : in 写显示寄存器的数据.
--
-- lcd_RS : out PIN_176, 1602 LCD 的 RS 管脚.
-- lcd_RW : out PIN_179, 1602 LCD 的 RW 管脚.
-- lcd_E : out PIN_178, 1602 LCD 的 E 管脚.
-- lcd_D0 : out PIN_177, 1602 LCD 的 D0 管脚.
-- lcd_D1 : out PIN_174, 1602 LCD 的 D1 管脚.
-- lcd_D2 : out PIN_175, 1602 LCD 的 D2 管脚.
-- lcd_D3 : out PIN_170, 1602 LCD 的 D3 管脚.
-- lcd_D4 : out PIN_173, 1602 LCD 的 D4 管脚.
-- lcd_D5 : out PIN_168, 1602 LCD 的 D5 管脚.
-- lcd_D6 : out PIN_169, 1602 LCD 的 D6 管脚.
-- lcd_D7 : out PIN_166, 1602 LCD 的 D7 管脚.
--
-- 笔记 : 1. LCD写操作的 状态机 采用 格雷码 是由于 常用实现方式的仿真 中 lcd_RS, lcd_RW 会产生毛刺.
-- 2. 在 LCD 上显示8个数据, 每个数据占4个显示字符.
-- 在LCD的显示起始地址值为: lcdWriteAddr. 分别为 0x00, 0x04, 0x08, 0x0C, 0x40, 0x44, 0x48, 0x4C.
--
-- Total logic elements: 206/12,060 ( 2%)
-- -----------------------------------------------------------------------------
-- 建立日期 : 2007/4/15
-- -----------------------------------------------------------------------------
-- 修改日期 :
-- 修改内容 :
-- -----------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity lcd is
port (
CLK_Z : in std_logic;
pulse1K : in std_logic;
pulse1M : in std_logic;
RESET : in std_logic;
enable : in std_logic;
wren : in std_logic;
writeAddr : in std_logic_vector(2 downto 0);
writeData : in std_logic_vector(15 downto 0);
lcd_RS : out std_logic;
lcd_RW : out std_logic;
lcd_E : out std_logic;
lcd_Data : out std_logic_vector(7 downto 0)
);
end lcd;
architecture RTL of lcd is
constant Tstart : std_logic_vector(2 downto 0) := "000";
constant T1 : std_logic_vector(2 downto 0) := "001";
constant Tshow0 : std_logic_vector(2 downto 0) := "011";
constant Tshow1 : std_logic_vector(2 downto 0) := "010";
constant Tshow2 : std_logic_vector(2 downto 0) := "110";
constant Tshow3 : std_logic_vector(2 downto 0) := "100";
type stateS_TYPE is (Sinit0, Sinit1, Sinit2, Sinit3, Sinit4, Sinit5, Saddr, Sdata0, Sdata1, Sdata2, Sdata3);
signal stateS, next_stateS : stateS_TYPE;
signal stateT, next_stateT : std_logic_vector(2 downto 0);
signal lcdRS, lcdRW, lcdE, tempLcdRS, writeLCD : std_logic;
signal tempLcdData : std_logic_vector(7 downto 0);
signal ramData0, tempRamData0, ramData1, tempRamData1 : std_logic_vector(15 downto 0);
signal ramData2, tempRamData2, ramData3, tempRamData3 : std_logic_vector(15 downto 0);
signal ramData4, tempRamData4, ramData5, tempRamData5 : std_logic_vector(15 downto 0);
signal ramData6, tempRamData6, ramData7, tempRamData7 : std_logic_vector(15 downto 0);
signal lcdAddr, tempLcdAddr : std_logic_vector(2 downto 0);
signal showData : std_logic_vector(15 downto 0);
signal dataASIC3, dataASIC2, dataASIC1, dataASIC0 : std_logic_vector(3 downto 0);
signal tempDataASIC3, tempDataASIC2 : std_logic_vector(2 downto 0);
signal tempDataASIC1, tempDataASIC0 : std_logic_vector(2 downto 0);
signal lcdWriteAddr : std_logic_vector(6 downto 0);
signal lcdWriteData3, lcdWriteData2 : std_logic_vector(7 downto 0);
signal lcdWriteData1, lcdWriteData0 : std_logic_vector(7 downto 0);
begin
lcd_RS <= lcdRS;
lcd_RW <= lcdRW;
lcd_E <= lcdE;
lcd_Data <= tempLcdData;
----------- 接收 到 显示寄存器(ramData0 .. ramData7) --------------------------------------
-- CLK_Z enable wren out
-- 非上升沿 * * *
-- 上升沿 1 * *
-- 上升沿 1 H write
ramData0 <= tempRamData0; ramData1 <= tempRamData1;
ramData2 <= tempRamData2; ramData3 <= tempRamData3;
ramData4 <= tempRamData4; ramData5 <= tempRamData5;
ramData6 <= tempRamData6; ramData7 <= tempRamData7;
writeData_pro: process (RESET, CLK_Z, enable, wren, writeAddr, writeData, ramData0,
ramData1, ramData2, ramData3, ramData4, ramData5, ramData6, ramData7)
begin
if (RESET = '1') then
tempRamData0 <= (others => '0'); tempRamData1 <= (others => '0');
tempRamData2 <= (others => '0'); tempRamData3 <= (others => '0');
tempRamData4 <= (others => '0'); tempRamData5 <= (others => '0');
tempRamData6 <= (others => '0'); tempRamData7 <= (others => '0');
elsif (CLK_Z'event and CLK_Z = '1' and enable = '1' and wren = '1') then --上升沿
tempRamData0 <= ramData0; tempRamData1 <= ramData1;
tempRamData2 <= ramData2; tempRamData3 <= ramData3;
tempRamData4 <= ramData4; tempRamData5 <= ramData5;
tempRamData6 <= ramData6; tempRamData7 <= ramData7;
case writeAddr is
when "000" => tempRamData0 <= writeData;
when "001" => tempRamData1 <= writeData;
when "010" => tempRamData2 <= writeData;
when "011" => tempRamData3 <= writeData;
when "100" => tempRamData4 <= writeData;
when "101" => tempRamData5 <= writeData;
when "110" => tempRamData6 <= writeData;
when "111" => tempRamData7 <= writeData;
when others => null;
end case;
end if;
end process;
----------- 选择 显示数据 showData ------------------------------------------------------
showData_pro: process (RESET, CLK_Z, pulse1K, lcdAddr, ramData0, ramData1,
ramData2, ramData3, ramData4, ramData5, ramData6, ramData7)
begin
if (RESET = '1') then
showData <= "0000000000000000";
elsif (CLK_Z'event and CLK_Z = '1' and pulse1K = '1') then --上升沿
case lcdAddr is
when "000" => showData <= ramData0;
when "001" => showData <= ramData1;
when "010" => showData <= ramData2;
when "011" => showData <= ramData3;
when "100" => showData <= ramData4;
when "101" => showData <= ramData5;
when "110" => showData <= ramData6;
when "111" => showData <= ramData7;
when others => null;
end case;
end if;
end process;
------- 将 showData 转换为 4个 对应显示的ASIC码(lcdWriteData3 .. lcdWriteData0). --------------------
dataASIC3 <= showData(15 downto 12); tempDataASIC3 <= dataASIC3(2 downto 0) + "111";
dataASIC2 <= showData(11 downto 8); tempDataASIC2 <= dataASIC2(2 downto 0) + "111";
dataASIC1 <= showData( 7 downto 4); tempDataASIC1 <= dataASIC1(2 downto 0) + "111";
dataASIC0 <= showData( 3 downto 0); tempDataASIC0 <= dataASIC0(2 downto 0) + "111";
lcdWriteData3 <= ("01000" & tempDataASIC3) when((dataASIC3(3) and (dataASIC3(2) or dataASIC3(1))) = '1') else
("0011" & dataASIC3);
lcdWriteData2 <= ("01000" & tempDataASIC2) when((dataASIC2(3) and (dataASIC2(2) or dataASIC2(1))) = '1') else
("0011" & dataASIC2);
lcdWriteData1 <= ("01000" & tempDataASIC1) when((dataASIC1(3) and (dataASIC1(2) or dataASIC1(1))) = '1') else
("0011" & dataASIC1);
lcdWriteData0 <= ("01000" & tempDataASIC0) when((dataASIC0(3) and (dataASIC0(2) or dataASIC0(1))) = '1') else
("0011" & dataASIC0);
----------------- LCD 初始化, 并 向其发送 数据. ---------------------------------------------
stateS_mooreState: process (RESET, CLK_Z, pulse1K, next_stateS, tempLcdAddr)
begin
if (RESET = '1') then
stateS <= Sinit0;
lcdAddr <= "000";
elsif (CLK_Z'event and CLK_Z = '1' and pulse1K = '1') then --上升沿
stateS <= next_stateS;
lcdAddr <= tempLcdAddr;
end if;
end process;
lcdWriteAddr <= lcdAddr(2) & "00" & lcdAddr(1 downto 0) & "00"; --发送到 LCD的地址.
stateS_pro : process(stateS, lcdAddr, lcdWriteAddr, lcdWriteData0, lcdWriteData1, lcdWriteData2, lcdWriteData3)
begin
writeLCD <= '1'; --默认: 对LCD进行写操作.(除了 延时,其他状态都要置一)
tempLcdRS <= '0';
tempLcdData <= "00000001";
tempLcdAddr <= lcdAddr; --显示数据的地址.
case stateS is
when Sinit0 => --初始化
next_stateS <= Sinit1;
when Sinit1 => --功能设置. DL:1(8位数据接口); N:1(两行显示); F:0(5 * 7点阵字符)
tempLcdRS <= '0';
tempLcdData <= "00111000";--0x38;
next_stateS <= Sinit2;
when Sinit2 => --显示开关控制.D:1(表示显示开); C:0(表示光标关); B:0(表示闪烁关)
tempLcdRS <= '0';
tempLcdData <= "00001100";--0x0C;
next_stateS <= Sinit3;
when Sinit3 => --清屏(要延时 1.53ms).
tempLcdRS <= '0';
tempLcdData <= "00000001";--0x01;
next_stateS <= Sinit4;
when Sinit4 => --延时.
writeLCD <= '0'; --不对LCD操作.
next_stateS <= Sinit5;
when Sinit5 => --输入方式设置.:I/D:1(数据读、写操作后,AC自动增一); SH:0(数据读、写操作,画面不动)
tempLcdRS <= '0';
tempLcdData <= "00000110";--0x06;
next_stateS <= Saddr;
when Saddr => -- DDRAM 地址设置. RS:0, R/W:0, DB7:1.
tempLcdRS <= '0';
tempLcdData <= '1' & lcdWriteAddr;--lcdWriteAddr 7bit
tempLcdAddr <= lcdAddr + 1; --地址 加1(改变显示位置)
next_stateS <= Sdata0;
when Sdata0 => -- 显示数据0.
tempLcdRS <= '1';
tempLcdData <= lcdWriteData3; --显示数据高位
next_stateS <= Sdata1;
when Sdata1 => -- 显示数据1.
tempLcdRS <= '1';
tempLcdData <= lcdWriteData2;
next_stateS <= Sdata2;
when Sdata2 => -- 显示数据2.
tempLcdRS <= '1';
tempLcdData <= lcdWriteData1;
next_stateS <= Sdata3;
when Sdata3 => -- 显示数据3.
tempLcdRS <= '1';
tempLcdData <= lcdWriteData0; --显示数据低位
next_stateS <= Saddr;
when others => next_stateS <= Sinit0; -- 返回 开始状态
end case;
end process;
----------------- LCD 写操作 时序. -----------------------------------------------------
stateT_mooreState: process (RESET, CLK_Z, pulse1M, next_stateT)
begin
if (RESET = '1') then
stateT <= Tstart;
elsif (CLK_Z'event and CLK_Z = '1' and pulse1M = '1') then --上升沿
stateT <= next_stateT;
end if;
end process;
stateT_pro : process(stateT, pulse1K, writeLCD, tempLcdRS)
begin
lcdRS <= '0';
lcdRW <= '0';
lcdE <= '0';
case stateT is
when Tstart => --开始,等待 pulse1K 信号
lcdRS <= '0';
lcdRW <= '1';
if (pulse1K = '1') then
next_stateT <= T1;
else
next_stateT <= Tstart;
end if;
when T1 => --在 pulse1K 脉冲后的第一个 pulse1M 脉冲 处查看是否需要发送数据到LCD
if (writeLCD = '1') then --发送数据到 LCD
next_stateT <= Tshow0;
else
next_stateT <= Tshow3;
end if;
when Tshow0 => --KS0066 写操作时序0
lcdRS <= tempLcdRS;
lcdRW <= '0';
next_stateT <= Tshow1;
when Tshow1 => --KS0066 写操作时序1
lcdRS <= tempLcdRS;
lcdRW <= '0';
lcdE <= '1';
next_stateT <= Tshow2;
when Tshow2 => --KS0066 写操作时序2
lcdRS <= tempLcdRS;
lcdRW <= '0';
lcdE <= '0';
next_stateT <= Tshow3;
when Tshow3 => --KS0066 写操作时序3
lcdRS <= '0';
lcdRW <= '1';
lcdE <= '0';
next_stateT <= Tstart; -- 返回 开始状态
when others => next_stateT <= Tstart; -- 返回 开始状态
end case;
end process;
end RTL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -