You are on page 1of 7

Marquesina con LCD

Se presenta el código en VHDL para realizar una marquesina en un LCD 16x2, configurado en dos líneas y corrimiento a la
izquierda. El LCD utilizado es el PmodCLP de conexión paralela (8 bits del bus de datos y tres pines de control: RS, RW y E).
Se probó en las tarjetas Nexys 2 y Nexys 3 utilizando el conector JA y JB (parte baja), así como un botón de reset (BTN0 en
la Nexys 2 y BTNR en la Nexys 3.

------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity PmodCLP is
Port (
btn0: in std_logic; --use BTN0 as reset input
clk: in std_logic; --Nexys 2 50MHz, Nexys 3 100 MHz clock input

--lcd input signals


--signal on connector JA
JA: out std_logic_vector(7 downto 0); --output bus, used for data transfer (DB)
-- signal on connector JB
--JB(4)register selection pin (RS)
--JB(5)selects between read/write modes (RW)
--JB(6)enable signal for starting the data read/write (E)
JB: out std_logic_vector (6 downto 4)
);
end PmodCLP;

architecture Behavioral of PmodCLP is

-----------------------------------------------------------------
-- Symbolic names for all possible states of the state machines.

--LCD control state machine


type mstate is (
FunctionSet, --Initialization states
DisplayCtrlSet,
DisplayClear,
PowerOn_Delay, --Delay states
FunctionSet_Delay,
DisplayCtrlSet_Delay,
DisplayClear_Delay,
InitDne, --Display characters and perform standard operations
ActWr,
CharDelay --Write delay for operations
);

------------------------------------------------------------------
-- Signal Declarations and Constants
------------------------------------------------------------------
--These constants are used to initialize the LCD pannel.

--FunctionSet:
--Bit 0 and 1 are arbitrary
--Bit 2: Displays font type(0=5x8, 1=5x11)
--Bit 3: Numbers of display lines (0=1, 1=2)
--Bit 4: Data length (0=4 bit, 1=8 bit)
--Bit 5-7 are set
--DisplayCtrlSet:
--Bit 0: Blinking cursor control (0=off, 1=on)
--Bit 1: Cursor (0=off, 1=on)
--Bit 2: Display (0=off, 1=on)
--Bit 3-7 are set
--DisplayClear:
--Bit 1-7 are set

signal clkCount: std_logic_vector (6 downto 0); --Signal to do OneUSClk


signal OneUSClk: std_logic; --Signal is treated as a 1 MHz clock

signal count: std_logic_vector (17 downto 0):= "000000000000000000";


--18 bit count variable for timing delays
signal delayOK: std_logic:= '0'; --High when count has reached the right delay time
signal stCur: mstate:= PowerOn_Delay; --LCD control state machine
signal stNext: mstate;
signal writeDone: std_logic:= '0'; --Command set finish

type LCD_CMDS_T is array(integer range <>) of std_logic_vector(9 downto 0);


constant LCD_CMDS : LCD_CMDS_T := (
0 => "00"&X"38", --Function Set DL 8bits, 2row, F 5x7
-- 1 => "00"&X"0C", --Display ON, Cursor OFF, Blink OFF
1 => "00"&X"0C", --Display ON, Cursor ON, Blink ON
2 => "00"&X"01", --Clear Display
3 => "00"&X"02", --return home

4 => "10"&X"48", --H


5 => "10"&X"65", --e
6 => "10"&X"6C", --l
7 => "10"&X"6C", --l
8 => "10"&X"6F", --o
9 => "10"&X"20", --blank
10 => "10"&X"46", --F
11 => "10"&X"72", --r
12 => "10"&X"6F", --o
13 => "10"&X"6D", --m
14 => "00"&X"C0", --beginning 2nd row
15 => "00"&X"14", --Shift right cursor
16 => "00"&X"14", --Shift right cursor
17 => "10"&X"4d", --M
18 => "10"&X"65", --e
19 => "10"&X"78", --x
20 => "10"&X"69", --i
21 => "10"&X"63", --c
22 => "10"&X"6f", --o
23 => "10"&X"21", --!
24 => "10"&X"21", --!
25 => "00"&X"18"); --Shift left display

signal lcd_cmd_ptr : integer range 0 to LCD_CMDS'HIGH + 1 := 0;

begin

----------------------------------------------------------------------------------------------------
--This process counts to 24(or 49), and then resets. It is used to divide the clock signal.
--This makes oneUSClock peak aprox. once every 1microsecond
process (CLK)
begin
if (CLK = '1' and CLK'event) then
-- if(clkCount = "0110001") then --49 Nexys 3
if(clkCount = "0011000") then --24 Nexys 2 [50*20ns]=1us
clkCount <= "0000000";
oneUSClk <= not oneUSClk;
else
clkCount <= clkCount + 1;
end if;
end if;
end process;

----------------------------------------------------------------------------------------------------
--This process increments the count variable unless delayOK = 1.
process (oneUSClk, delayOK)
begin
if (oneUSClk = '1' and oneUSClk'event) then
if delayOK = '1' then
count <= "000000000000000000";
else
count <= count + 1;
end if;
end if;
end process;

--#####---------------------------------------------------------------------------------------------
--Determines when count has gotten to the right number, depending on the state.
delayOK <= '1' when (
(stCur = PowerOn_Delay and count = "000100111000100000") or --20,000 -> 20 ms
(stCur = FunctionSet_Delay and count = "000000000000101000") or --40 -> 40 us (37us)
(stCur = DisplayCtrlSet_Delay and count = "000000000000101000") or --40 -> 40 us (37us)
(stCur = DisplayClear_Delay and count = "000000011001000000") or --1,600 -> 1.6 ms (1.52us)
(stCur = CharDelay and count = "110000110101000000")) --200,000-> 200 ms - Max Delay writes and shifts
else '0';
--#####---------------------------------------------------------------------------------------------
--writeDone goes high when all commands have been run
writeDone <= '1' when (lcd_cmd_ptr = LCD_CMDS'HIGH)
else '0';

----------------------------------------------------------------------------------------------------
--Increments the pointer so the statemachine goes through the commands
process (lcd_cmd_ptr, oneUSClk)
begin
if (oneUSClk = '1' and oneUSClk'event) then
if ((stNext = InitDne or stNext = DisplayCtrlSet or stNext = DisplayClear) and writeDone = '0') then
lcd_cmd_ptr <= lcd_cmd_ptr + 1;
elsif stCur = PowerOn_Delay or stNext = PowerOn_Delay then
lcd_cmd_ptr <= 0;
else
lcd_cmd_ptr <= lcd_cmd_ptr;
end if;
end if;
end process;

----------------------------------------------------------------------------------------------------
--This process runs the LCD state machine
process (oneUSClk, btn0)
begin
if oneUSClk = '1' and oneUSClk'Event then
if btn0 = '1' then
stCur <= PowerOn_Delay;
else
stCur <= stNext;
end if;
end if;
end process;

----------------------------------------------------------------------------------------------------
--This process generates the sequence of outputs needed to initialize and write to the LCD screen
process (stCur, delayOK, writeDone, lcd_cmd_ptr)
begin
case stCur is
--Delays the state machine for 20ms which is needed for proper startup.
when PowerOn_Delay =>
if delayOK = '1' then
stNext <= FunctionSet;
else
stNext <= PowerOn_Delay;
end if;

--This issues the function set to the LCD as follows


--8 bit data length, 1 lines, font is 5x8.
when FunctionSet =>
stNext <= FunctionSet_Delay;

--Gives the proper delay of 37us between the function set and
--the display control set.
when FunctionSet_Delay =>
if delayOK = '1' then
stNext <= DisplayCtrlSet;
else
stNext <= FunctionSet_Delay;
end if;

--Issuse the display control set as follows


--Display ON, Cursor OFF, Blinking Cursor OFF.
when DisplayCtrlSet =>
stNext <= DisplayCtrlSet_Delay;

--Gives the proper delay of 37us between the display control set
--and the Display Clear command.
when DisplayCtrlSet_Delay =>
if delayOK = '1' then
stNext <= DisplayClear;
else
stNext <= DisplayCtrlSet_Delay;
end if;

--Issues the display clear command.


when DisplayClear =>
stNext <= DisplayClear_Delay;

--Gives the proper delay of 1.52ms between the clear command


--and the state where you are clear to do normal operations.
when DisplayClear_Delay =>
if delayOK = '1' then
stNext <= InitDne;
else
stNext <= DisplayClear_Delay;
end if;

--State for normal operations for displaying characters, changing the


--Cursor position etc.
when InitDne =>
stNext <= ActWr;

when ActWr =>


stNext <= CharDelay;

--Provides a max delay between instructions.


when CharDelay =>
if delayOK = '1' then
stNext <= InitDne;
else
stNext <= CharDelay;
end if;
end case; -- end FSM
end process;

JB(4) <= LCD_CMDS(lcd_cmd_ptr)(9);


JB(5) <= LCD_CMDS(lcd_cmd_ptr)(8);
JA <= LCD_CMDS(lcd_cmd_ptr)(7 downto 0);
JB(6) <= '1' when stCur = FunctionSet or stCur = DisplayCtrlSet or
stCur = DisplayClear or stCur = ActWr
else '0';

end Behavioral;

## ucf for Nexys2 board

##Clock signal -----------------


Net "clk" LOC=B8 ;#| IOSTANDARD=LVCMOS33;

## 12 pin connectors

##JA -----------------
Net "JA<0>" LOC = L15 | IOSTANDARD = LVCMOS33; # JA1
Net "JA<1>" LOC = K12 | IOSTANDARD = LVCMOS33; # JA2
Net "JA<2>" LOC = L17 | IOSTANDARD = LVCMOS33; # JA3
Net "JA<3>" LOC = M15 | IOSTANDARD = LVCMOS33; # JA4
Net "JA<4>" LOC = K13 | IOSTANDARD = LVCMOS33; # JA7
Net "JA<5>" LOC = L16 | IOSTANDARD = LVCMOS33; # JA8
Net "JA<6>" LOC = M14 | IOSTANDARD = LVCMOS33; # JA9
Net "JA<7>" LOC = M16 | IOSTANDARD = LVCMOS33; # JA10

##JB -----------------
#Net "JB<0>" LOC = M13 | IOSTANDARD = LVCMOS33; # JB1
#Net "JB<1>" LOC = R18 | IOSTANDARD = LVCMOS33; # JB2
#Net "JB<2>" LOC = R15 | IOSTANDARD = LVCMOS33; # JB3
#Net "JB<3>" LOC = T17 | IOSTANDARD = LVCMOS33; # JB4
Net "JB<4>" LOC = P17 | IOSTANDARD = LVCMOS33; # JB7
Net "JB<5>" LOC = R16 | IOSTANDARD = LVCMOS33; # JB8
Net "JB<6>" LOC = T18 | IOSTANDARD = LVCMOS33; # JB9
#Net "JB<7>" LOC = U18 | IOSTANDARD = LVCMOS33; # JB10

## Buttons -----------------
Net "btn0" LOC = B18 | IOSTANDARD = LVCMOS33; # BTN0

##################################################################################################
## ucf for Nexys3 rev B board

##Clock signal
#Net "CLK" LOC=V10 | IOSTANDARD=LVCMOS33;
#Net "clk" TNM_NET = sys_clk_pin;
#TIMESPEC TS_sys_clk_pin = PERIOD sys_clk_pin 100000 kHz;

## Buttons
#Net "btnr" LOC = D9 | IOSTANDARD = LVCMOS33; # Bank = 0, pin name = IO_L34P_GCLK19, Sch name = BTNR

## 12 pin connectors

##JA
#Net "JA<0>" LOC = T12 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L19P, Sch name = JA1
#Net "JA<1>" LOC = V12 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L19N, Sch name = JA2
#Net "JA<2>" LOC = N10 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L20P, Sch name = JA3
#Net "JA<3>" LOC = P11 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L20N, Sch name = JA4
#Net "JA<4>" LOC = M10 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L22P, Sch name = JA7
#Net "JA<5>" LOC = N9 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L22N, Sch name = JA8
#Net "JA<6>" LOC = U11 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L23P, Sch name = JA9
#Net "JA<7>" LOC = V11 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L23N, Sch name = JA10

##JB
#Net "JB<0>" LOC = K2 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L38P_M3DQ2, Sch name = JB1
#Net "JB<1>" LOC = K1 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L38N_M3DQ3, Sch name = JB2
#Net "JB<2>" LOC = L4 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L39P_M3LDQS, Sch name = JB3
#Net "JB<3>" LOC = L3 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L39N_M3LDQSN, Sch name = JB4
#Net "JB<4>" LOC = J3 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L40P_M3DQ6, Sch name = JB7
#Net "JB<5>" LOC = J1 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L40N_M3DQ7, Sch name = JB8
#Net "JB<6>" LOC = K3 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L42N_GCLK24_M3LDM, Sch name = JB9
#Net "JB<7>" LOC = K5 | IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L43N_GCLK22_IRDY2_M3CASN, Sch name
= JB10

Referencias

PmodCLP, consultado feb-2018, disponible en:


https://store.digilentinc.com/pmodclp-character-lcd-with-parallel-interface/