?? 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 + -