-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlcd_display.vhd
More file actions
216 lines (206 loc) · 6.62 KB
/
Copy pathlcd_display.vhd
File metadata and controls
216 lines (206 loc) · 6.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.all;
USE IEEE.NUMERIC_STD.ALL;
--USE IEEE.STD_LOGIC_ARITH.all;
USE IEEE.STD_LOGIC_UNSIGNED.all;
-- SW8 (GLOBAL RESET) resets LCD
ENTITY LCD_Display IS
PORT(reset, clock : IN STD_LOGIC;
sensor1, sensor2 : IN std_logic;
sensor3, sensor4, sensor5 : IN std_logic;
switch1, switch2, switch3 : OUT std_logic;
track1, track2, track3, track4 : OUT std_logic;
dirA, dirB : OUT std_logic_vector(1 DOWNTO 0));
LCD_RS, LCD_E : OUT STD_LOGIC;
LCD_RW : OUT STD_LOGIC;
DATA_BUS : INOUT STD_LOGIC_VECTOR(7 DOWNTO 0));
END LCD_Display;
ARCHITECTURE a OF LCD_Display IS
TYPE character_string IS ARRAY ( 0 TO 31 ) OF STD_LOGIC_VECTOR( 7 DOWNTO 0 );
TYPE STATE_TYPE IS (HOLD, FUNC_SET, DISPLAY_ON, MODE_SET, Print_String,
LINE2, RETURN_HOME, DROP_LCD_E, RESET1, RESET2,
RESET3, DISPLAY_OFF, DISPLAY_CLEAR);
-- LCD Display Signals
SIGNAL state, next_command: STATE_TYPE;
SIGNAL LCD_display_string : character_string;
-- Enter new ASCII hex data above for LCD Display
SIGNAL DATA_BUS_VALUE, Next_Char: STD_LOGIC_VECTOR(7 DOWNTO 0);
SIGNAL CLK_COUNT_400HZ: STD_LOGIC_VECTOR(19 DOWNTO 0);
SIGNAL CHAR_COUNT: STD_LOGIC_VECTOR(4 DOWNTO 0);
SIGNAL CLK_400HZ,LCD_RW_INT : STD_LOGIC;
SIGNAL Line1_chars, Line2_chars: STD_LOGIC_VECTOR(127 DOWNTO 0);
-- LCD Display Code for Train Status
LCD_display_string <= (
-- ASCII hex values for LCD Display
-- Enter Live Hex Data Values from hardware here
-- LCD DISPLAYS THE FOLLOWING:
-------------------------
--| sXXXXXtXXXXswXXX |
--| Train daXX dbXX |
-------------------------
-- Line 1
X"73",X"0" & "000" & Sensor5,X"0" & "000" & Sensor4,
X"0" & "000" & Sensor3,X"0" & "000" & Sensor2,X"0" & "000" & Sensor1,
X"74",X"0" & "000" & Track4,X"0" & "000" & Track3,
X"0" & "000" & Track2,X"0" & "000" & Track1,
X"73",X"77",X"0" & "000" & Switch3,X"0" & "000" & Switch2,X"0" & "000" & Switch1,
-- Line 2
X"54",X"72",X"61",X"69",X"6E",X"20",
X"20",X"64",X"61",X"0" & "000" & DIRA(1),X"0" & "000" & DIRA(0),
X"20",X"64",X"62",X"0" & "000" & DIRB(1),X"0" & "000" & DIRB(0));
-- BIDIRECTIONAL TRI STATE LCD DATA BUS
DATA_BUS <= DATA_BUS_VALUE WHEN LCD_RW_INT = '0' ELSE "ZZZZZZZZ";
-- get next character in display string
Next_Char <= LCD_display_string(CONV_INTEGER(CHAR_COUNT));
LCD_RW <= LCD_RW_INT;
LCD_CLOCK: PROCESS
BEGIN
WAIT UNTIL CLOCK'EVENT AND CLOCK = '1';
IF RESET = '1' THEN
CLK_COUNT_400HZ <= X"00000";
CLK_400HZ <= '0';
ELSE
IF CLK_COUNT_400HZ < X"0EA60" THEN
CLK_COUNT_400HZ <= CLK_COUNT_400HZ + 1;
ELSE
CLK_COUNT_400HZ <= X"00000";
CLK_400HZ <= NOT CLK_400HZ;
END IF;
END IF;
END PROCESS LCD_CLOCK;
LCD_ON <= '1';
LCD_DISPLAY: PROCESS (CLK_400HZ, reset)
BEGIN
IF reset = '1' THEN
state <= RESET1;
DATA_BUS_VALUE <= X"38";
next_command <= RESET2;
LCD_E <= '1';
LCD_RS <= '0';
LCD_RW_INT <= '1';
ELSIF CLK_400HZ'EVENT AND CLK_400HZ = '1' THEN
-- State Machine to send commands and data to LCD DISPLAY
CASE state IS
-- Set Function to 8-bit transfer and 2 line display with 5x8 Font size
-- see Hitachi HD44780 family data sheet for LCD command and timing details
WHEN RESET1 =>
LCD_E <= '1';
LCD_RS <= '0';
LCD_RW_INT <= '0';
DATA_BUS_VALUE <= X"38";
state <= DROP_LCD_E;
next_command <= RESET2;
CHAR_COUNT <= "00000";
WHEN RESET2 =>
LCD_E <= '1';
LCD_RS <= '0';
LCD_RW_INT <= '0';
DATA_BUS_VALUE <= X"38";
state <= DROP_LCD_E;
next_command <= RESET3;
WHEN RESET3 =>
LCD_E <= '1';
LCD_RS <= '0';
LCD_RW_INT <= '0';
DATA_BUS_VALUE <= X"38";
state <= DROP_LCD_E;
next_command <= FUNC_SET;
-- EXTRA STATES ABOVE ARE NEEDED FOR RELIABLE PUSHBUTTON RESET OF LCD
WHEN FUNC_SET =>
LCD_E <= '1';
LCD_RS <= '0';
LCD_RW_INT <= '0';
DATA_BUS_VALUE <= X"38";
state <= DROP_LCD_E;
next_command <= DISPLAY_OFF;
-- Turn off Display and Turn off cursor
WHEN DISPLAY_OFF =>
LCD_E <= '1';
LCD_RS <= '0';
LCD_RW_INT <= '0';
DATA_BUS_VALUE <= X"08";
state <= DROP_LCD_E;
next_command <= DISPLAY_CLEAR;
-- Clear Display and Turn off cursor
WHEN DISPLAY_CLEAR =>
LCD_E <= '1';
LCD_RS <= '0';
LCD_RW_INT <= '0';
DATA_BUS_VALUE <= X"01";
state <= DROP_LCD_E;
next_command <= DISPLAY_ON;
-- Turn on Display and Turn off cursor
WHEN DISPLAY_ON =>
LCD_E <= '1';
LCD_RS <= '0';
LCD_RW_INT <= '0';
DATA_BUS_VALUE <= X"0C";
state <= DROP_LCD_E;
next_command <= MODE_SET;
-- Set write mode to auto increment address and move cursor to the right
WHEN MODE_SET =>
LCD_E <= '1';
LCD_RS <= '0';
LCD_RW_INT <= '0';
DATA_BUS_VALUE <= X"06";
state <= DROP_LCD_E;
next_command <= Print_String;
-- Write ASCII hex character in first LCD character location
WHEN Print_String =>
LCD_E <= '1';
LCD_RS <= '1';
LCD_RW_INT <= '0';
-- ASCII character to output
IF Next_Char(7 DOWNTO 4) /= X"0" THEN
DATA_BUS_VALUE <= Next_Char;
ELSE
-- Convert 4-bit value to an ASCII hex digit
IF Next_Char(3 DOWNTO 0) >9 THEN
-- ASCII A...F
DATA_BUS_VALUE <= X"4" & (Next_Char(3 DOWNTO 0)-9);
ELSE
-- ASCII 0...9
DATA_BUS_VALUE <= X"3" & Next_Char(3 DOWNTO 0);
END IF;
END IF;
state <= DROP_LCD_E;
-- Loop to send out 32 characters to LCD Display (16 by 2 lines)
IF (CHAR_COUNT < 31) AND (Next_Char /= X"FE") THEN
CHAR_COUNT <= CHAR_COUNT +1;
ELSE
CHAR_COUNT <= "00000";
END IF;
-- Jump to second line?
IF CHAR_COUNT = 15 THEN next_command <= line2;
-- Return to first line?
ELSIF (CHAR_COUNT = 31) OR (Next_Char = X"FE") THEN
next_command <= return_home;
ELSE next_command <= Print_String; END IF;
-- Set write address to line 2 character 1
WHEN LINE2 =>
LCD_E <= '1';
LCD_RS <= '0';
LCD_RW_INT <= '0';
DATA_BUS_VALUE <= X"C0";
state <= DROP_LCD_E;
next_command <= Print_String;
-- Return write address to first character postion on line 1
WHEN RETURN_HOME =>
LCD_E <= '1';
LCD_RS <= '0';
LCD_RW_INT <= '0';
DATA_BUS_VALUE <= X"80";
state <= DROP_LCD_E;
next_command <= Print_String;
-- The next three states occur at the end of each command or data transfer to the LCD
-- Drop LCD E line - falling edge loads inst/data to LCD controller
WHEN DROP_LCD_E =>
LCD_E <= '0';
state <= HOLD;
-- Hold LCD inst/data valid after falling edge of E line
WHEN HOLD =>
state <= next_command;
END CASE;
END IF;
END PROCESS LCD_DISPLAY;
END a;