You are on page 1of 5

University of North Texas, Digital Design Technology, Dr.

Albert Grubbs 1

Maqsood Khandaker
Digital Design Technology Final Project: Digital
Voltmeter VLSI (Dec 2009)
required for the correct functioning of the push button reset. In
Abstract—A very large scale integration of a Digital Voltmeter between every state two additional states are occurring, these
was successfully completed. Altera's DE2 CPLD (complex are the Drop_LCD_E and Hold states. A falling edge from the
programmable Logic Device board, National Semiconductor's enable pin is required to write the instruction to the LCD
ADC0804 analog to digital converter and Hitachi’s HD44780
LCD a were interfaced with VHDL, a high level compiler for controller and Hold state holds the current next state till after
logic circuits the falling edge.
However if reset is not pressed, on every rising edge of the
Index Terms—VHDL, ADC, Altera DE2, ADC0804, LCD, clock the LCD is continuously printing characters from the
HD44780 input bus. This input bus is defined as LCD_display_string, an
array of 32 elements, with each element being 8 bits long.
I. INTRODUCTION Each character is represented by two Hex digit addresses. On

T HIS paper describes the procedure followed in order to


successfully create a Digital Voltmeter via Altera's DE2
Complex programmable logic device board and VHDL
the LCD controller, the RAM contains the bit patterns for each
character. A table containing the addresses and corresponding
characters was used to display the correct characters. The three
compiler. states representing this continuous printing are Print_string,
Measuring voltage from transducers is vital in the world of LINE2, and Return_Home, as shown on page 3 of the handout.
electronics instrumentation. A transducer such as temperature The Print_string state prints the characters directly, however
sensors, accelerometers, and piezoelectric devices output when it encounters a zero in the first four bits, it then converts
voltage which is a function of the input condition. For example the last four bits from binary to hex representation. This
in a LM35 temperature sensor there is a 10mV/o C output function was useful to display values from the ADC.
voltage relation. If one were to interface this output to a ADC However it is not so easy to display the value on the LCD,
(analog to digital converter) this information can now be that represents the actual input test voltage supplied to the
manipulated. It can recorded into memory, compared to ADC. This is because the first four bits from the output of the
desired settings and error calculated. With this error we can ADC represent the test value in units of 0.32 volts from zero to
control the system. Examples of such systems are thermostats 4.8. The last four bits of the output represent the test value in
and strain gage systems for weight measurement, Crash units of 0.020, from zero to 0.3. For example an input test
detection systems. voltage of 1.54 creates an output of 01001101, the first four
bits, 0100 correspond to 1.28 Volts from the table. The last
II.PROCEDURE FOR PAPER SUBMISSION four bits, 1101 correspond to 0.26. So the final result would be
1.28 + 0.26 = 1.54 Volts. This logic must be programmed in
On the first page of the companion handout, the VHDL VHDL. This was done with the help of case statements and
entity/architecture can be seen. Here the inputs and outputs to BCD arithmetic.
the black box are defined. This black box has to interface with In conclusion the LCD portion of the project was completed
an LCD and a ADC microchip. The LCD features a 8 bit data with 100% confidence and accuracy. Any errors displayed, is a
bus, as well other control registers, that control backlight and result of the physical calibration of the ADC circuit. Effort and
read/write operations. All of these ports must be defined in the diligence required of an engineer was spent. From
entity of the VHDL program. Next the ADC features a 8-bit understanding the internal workings of the LCD and ADC, to
out data bus, as well control ports for Chip Select, read, write robust testing was done. ADC chips were interchanged,
and interrupt. These have also been defined in the entity of the circuits rebuilt, various DE2 boards programmed and LCD
VHDL program. output verified. This was done to validate the VHDL code.
On the next page of the handout a graphical representation
of what happens when reset is pressed or LCD is turned on for REFERENCES
the first time can be seen. The green blocks represent the [1] A. Grubbs, private communication, Nov 2009
sequential states. As can be seen Reset1, Reset2,Reset3, and [2] P. K. Lala, Principles of Modern Digital Design . Wiley-Interscience,
2007, pp. 338–339.
Func_Set all perform the same thing. This repetition is
[3] J. Jackson (2009, Nov 27). Digital Systems Design. Available:

Maqsood khandaker – Is a Masters student in System Engineering at UNT. http://jjackson.eng.ua.edu/courses/ece480/
He has completed his BSc in Electrical Engineering from Oklahoma State
University. He is also a firm believer in Pareto's 80/20 law, where 80% of the
effects come from 20% of the causes. It can be applied to this project as well.
University of North Texas, Digital Design Technology, Dr. Albert Grubbs 2

Source code
LIBRARY IEEE; -- Enter new ASCII hex data above for LCD Display
USE IEEE.STD_LOGIC_1164.all;
USE IEEE.STD_LOGIC_ARITH.all; SIGNAL DATA_BUS_VALUE, Next_Char :
USE IEEE.STD_LOGIC_UNSIGNED.all; STD_LOGIC_VECTOR(7 DOWNTO 0);
USE IEEE.numeric_std.all; SIGNAL CLK_COUNT_400HZ :
STD_LOGIC_VECTOR(19 DOWNTO 0);
ENTITY LCD_Display IS SIGNAL CHAR_COUNT :
STD_LOGIC_VECTOR(4 DOWNTO 0);
------------------------------------------------------------------- SIGNAL CLK_400HZ_Enable,LCD_RW_INT :
-- ASCII HEX TABLE STD_LOGIC;
-- Hex Low Hex Digit SIGNAL Line1_chars, Line2_chars :
-- Value 0 1 2 3 4 5 6 7 8 9 A B C D E F STD_LOGIC_VECTOR(127 DOWNTO 0);
------\---------------------------------------------------------------- SIGNAL S0,S1,S2 : STD_LOGIC_VECTOR(3
--H 2 | SP ! " # $ % & ' ( ) * + , - . / downto 0);
--i 3 | 0 1 2 3 4 5 6 7 8 9 : ; < = > ? SIGNAL Z0,Z1, C1,C2 :
--g 4 | @ A B C D E F G H I J K L M N O STD_LOGIC_VECTOR(3 downto 0);
--h 5 | P Q R S T U V W X Y Z [ \ ] ^ _ BEGIN
-- 6 | ` a b c d e f g h i j k l m n o
-- 7 | p q r s t u v w x y z { | } ~ DEL LCD_ON <= '1';
----------------------------------------------------------------------- LCD_BLON <= '1';
-- Example "A" is row 4 column 1, so hex value is X"41" LEDR(11 downto 8) <= S0;
-- *see LCD Controller's Datasheet for other graphics LEDR(7 downto 4) <= S1;
characters available LEDR(3 downto 0) <= S2;
--
PORT(KEY : IN STD_LOGIC_VECTOR(0 downto 0); LCD_display_string <= (
CLOCK_50 : IN STD_LOGIC; -- ASCII hex values for LCD Display
GPIO_0 : IN STD_LOGIC_VECTOR(11 -- Enter Live Hex Data Values from hardware here
DOWNTO 0); -- LCD DISPLAYS THE FOLLOWING:
LCD_RS, LCD_EN : OUT STD_LOGIC;
LCD_RW : OUT STD_LOGIC; -- Line 1
LCD_ON : OUT STD_LOGIC; X"0" & S0,X"2E",X"0" & S1,X"0" & S2,X"20",X"56",
LCD_BLON : OUT STD_LOGIC;
LEDR : OUT STD_LOGIC_VECTOR(11 X"20",X"20",X"20",X"20",X"20",X"20",X"20",X"20",X
downto 0); "20",X"20",
LCD_DATA : INOUT -- Line 2
STD_LOGIC_VECTOR(7 DOWNTO 0)); X"42",X"79",X"20",X"4D",X"61",X"71",X"73",X"6F",
X"6F",X"64",X"20",X"20",X"20",X"20",X"20",X"20");
END ENTITY LCD_Display;
-- BIDIRECTIONAL TRI STATE LCD DATA BUS
ARCHITECTURE Behavior OF LCD_Display IS LCD_DATA <= DATA_BUS_VALUE WHEN
TYPE character_string IS ARRAY ( 0 TO 31 ) OF LCD_RW_INT = '0' ELSE "ZZZZZZZZ";
STD_LOGIC_VECTOR( 7 DOWNTO 0 );
TYPE numeric_digit IS ARRAY (0 to 2) OF -- get next character in display string
STD_LOGIC_VECTOR(3 downto 0); Next_Char <=
LCD_display_string(CONV_INTEGER(CHAR_COUNT
TYPE STATE_TYPE IS (HOLD, FUNC_SET, ));
DISPLAY_ON, MODE_SET, Print_String, LCD_RW <= LCD_RW_INT;
LINE2, RETURN_HOME, DROP_LCD_E,
RESET1, RESET2, PROCESS
RESET3, DISPLAY_OFF, DISPLAY_CLEAR); BEGIN
WAIT UNTIL CLOCK_50'EVENT AND CLOCK_50 =
SIGNAL state, next_command : STATE_TYPE; '1';
SIGNAL LCD_display_string : character_string; IF KEY(0) = '0' THEN
SIGNAL number_array_one : numeric_digit; CLK_COUNT_400HZ <= X"00000";
SIGNAL number_array_two : numeric_digit; CLK_400HZ_Enable <= '0';
SIGNAL result_add : numeric_digit; ELSE
IF CLK_COUNT_400HZ < X"0F424" THEN
University of North Texas, Digital Design Technology, Dr. Albert Grubbs 3

CLK_COUNT_400HZ <= CLK_COUNT_400HZ + number_array_one(0) <="0011";


1; number_array_one(1) <="0101";
CLK_400HZ_Enable <= '0'; number_array_one(2) <="0010";
ELSE when "1100" =>
CLK_COUNT_400HZ <= X"00000"; number_array_one(0) <="0011";
CLK_400HZ_Enable <= '1'; number_array_one(1) <="1000";
END IF; number_array_one(2) <="0100";
END IF; when "1101" =>
END PROCESS; number_array_one(0) <="0100";
number_array_one(1) <="0001";
PROCESS (GPIO_0) number_array_one(2) <="0110";
BEGIN when "1110" =>
CASE GPIO_0(7 downto 4) is number_array_one(0) <="0100";
when "0000" => number_array_one(1) <="0100";
number_array_one(0) <="0000"; number_array_one(2) <="1000";
number_array_one(1) <="0000"; when "1111" =>
number_array_one(2) <="0000"; number_array_one(0) <="0100";
when "0001" => number_array_one(1) <="1000";
number_array_one(0) <="0000"; number_array_one(2) <="0000";
number_array_one(1) <="0011"; end case;
number_array_one(2) <="0010";
when "0010" => CASE GPIO_0(3 downto 0) is
number_array_one(0) <="0000"; when "0000" =>
number_array_one(1) <="0110"; number_array_two(0) <="0000";
number_array_one(2) <="0100"; number_array_two(1) <="0000";
when "0011" => number_array_two(2) <="0000";
number_array_one(0) <="0000"; when "0001" =>
number_array_one(1) <="1001"; number_array_two(0) <="0000";
number_array_one(2) <="0110"; number_array_two(1) <="0000";
when "0100" => number_array_two(2) <="0010";
number_array_one(0) <="0001"; when "0010" =>
number_array_one(1) <="0010"; number_array_two(0) <="0000";
number_array_one(2) <="1000"; number_array_two(1) <="0000";
when "0101" => number_array_two(2) <="0100";
number_array_one(0) <="0001"; when "0011" =>
number_array_one(1) <="0110"; number_array_two(0) <="0000";
number_array_one(2) <="0000"; number_array_two(1) <="0000";
when "0110" => number_array_two(2) <="0110";
number_array_one(0) <="0001"; when "0100" =>
number_array_one(1) <="1001"; number_array_two(0) <="0000";
number_array_one(2) <="0010"; number_array_two(1) <="0000";
when "0111" => number_array_two(2) <="1000";
number_array_one(0) <="0010"; when "0101" =>
number_array_one(1) <="0010"; number_array_two(0) <="0000";
number_array_one(2) <="0100"; number_array_two(1) <="0001";
when "1000" => number_array_two(2) <="0000";
number_array_one(0) <="0010"; when "0110" =>
number_array_one(1) <="0101"; number_array_two(0) <="0000";
number_array_one(2) <="0110"; number_array_two(1) <="0001";
when "1001" => number_array_two(2) <="0010";
number_array_one(0) <="0010"; when "0111" =>
number_array_one(1) <="1000"; number_array_two(0) <="0000";
number_array_one(2) <="1000"; number_array_two(1) <="0001";
when "1010" => number_array_two(2) <="0100";
number_array_one(0) <="0011"; when "1000" =>
number_array_one(1) <="0010"; number_array_two(0) <="0000";
number_array_one(2) <="0000"; number_array_two(1) <="0001";
when "1011" => number_array_two(2) <="0110";
University of North Texas, Digital Design Technology, Dr. Albert Grubbs 4

when "1001" => END PROCESS;


number_array_two(0) <="0000";
number_array_two(1) <="0001"; PROCESS (CLOCK_50, KEY(0))
number_array_two(2) <="1000"; BEGIN
when "1010" => IF KEY(0) = '0' THEN
number_array_two(0) <="0000"; state <= RESET1;
number_array_two(1) <="0010"; DATA_BUS_VALUE <= X"38";
number_array_two(2) <="0000"; next_command <= RESET2;
when "1011" => LCD_EN <= '1';
number_array_two(0) <="0000"; LCD_RS <= '0';
number_array_two(1) <="0010"; LCD_RW_INT <= '1';
number_array_two(2) <="0010";
when "1100" => ELSIF CLOCK_50'EVENT AND CLOCK_50 = '1'
number_array_two(0) <="0000"; THEN
number_array_two(1) <="0010"; -- State Machine to send commands and data to LCD
number_array_two(2) <="0100"; DISPLAY
when "1101" => IF CLK_400HZ_Enable = '1' THEN
number_array_two(0) <="0000"; CASE state IS
number_array_two(1) <="0010"; -- Set Function to 8-bit transfer and 2 line display with 5x8
number_array_two(2) <="0110"; Font size
when "1110" => -- see Hitachi HD44780 family data sheet for LCD command
number_array_two(0) <="0000"; and timing details
number_array_two(1) <="0010"; WHEN RESET1 =>
number_array_two(2) <="1000"; LCD_EN <= '1';
when "1111" => LCD_RS <= '0';
number_array_two(0) <="0000"; LCD_RW_INT <= '0';
number_array_two(1) <="0011"; DATA_BUS_VALUE <= X"38";
number_array_two(2) <="0000"; state <= DROP_LCD_E;
end case; next_command <= RESET2;
CHAR_COUNT <= "00000";
WHEN RESET2 =>
result_add(2) <=number_array_one(2) + LCD_EN <= '1';
number_array_two(2); LCD_RS <= '0';
LCD_RW_INT <= '0';
if result_add(2) > 9 then DATA_BUS_VALUE <= X"38";
Z0 <= "1010"; state <= DROP_LCD_E;
c1 <="0001"; next_command <= RESET3;
else WHEN RESET3 =>
Z0 <="0000"; LCD_EN <= '1';
c1 <="0000"; LCD_RS <= '0';
end if; LCD_RW_INT <= '0';
S2<=result_add(2) - Z0; DATA_BUS_VALUE <= X"38";
state <= DROP_LCD_E;
result_add(1) <=number_array_one(1) + next_command <= FUNC_SET;
number_array_two(1)+ c1; -- EXTRA STATES ABOVE ARE NEEDED FOR
if result_add(1) > 9 then RELIABLE PUSHBUTTON RESET OF LCD
Z1 <= "1010"; WHEN FUNC_SET =>
c2 <="0001"; LCD_EN <= '1';
else LCD_RS <= '0';
Z1 <="0000"; LCD_RW_INT <= '0';
c2 <="0000"; DATA_BUS_VALUE <= X"38";
end if; state <= DROP_LCD_E;
S1<=result_add(1) - Z1; next_command <= DISPLAY_OFF;
-- Turn off Display and Turn off cursor
result_add(0) <=number_array_one(0) + WHEN DISPLAY_OFF =>
number_array_two(0) + c2; LCD_EN <= '1';
S0<=result_add(0); LCD_RS <= '0';
LCD_RW_INT <= '0';
University of North Texas, Digital Design Technology, Dr. Albert Grubbs 5

DATA_BUS_VALUE <= X"08"; -- Jump to second line?


state <= DROP_LCD_E; IF CHAR_COUNT = 15 THEN next_command
next_command <= DISPLAY_CLEAR; <= line2;
-- Clear Display and Turn off cursor -- Return to first line?
WHEN DISPLAY_CLEAR => ELSIF (CHAR_COUNT = 31) OR (Next_Char =
LCD_EN <= '1'; X"FE") THEN
LCD_RS <= '0'; next_command <= return_home;
LCD_RW_INT <= '0'; ELSE next_command <= Print_String; END IF;
DATA_BUS_VALUE <= X"01"; -- Set write address to line 2 character 1
state <= DROP_LCD_E; WHEN LINE2 =>
next_command <= DISPLAY_ON; LCD_EN <= '1';
-- Turn on Display and Turn off cursor LCD_RS <= '0';
WHEN DISPLAY_ON => LCD_RW_INT <= '0';
LCD_EN <= '1'; DATA_BUS_VALUE <= X"C0";
LCD_RS <= '0'; state <= DROP_LCD_E;
LCD_RW_INT <= '0'; next_command <= Print_String;
DATA_BUS_VALUE <= X"0C"; -- Return write address to first character postion on line 1
state <= DROP_LCD_E; WHEN RETURN_HOME =>
next_command <= MODE_SET; LCD_EN <= '1';
-- Set write mode to auto increment address and move cursor LCD_RS <= '0';
to the right LCD_RW_INT <= '0';
WHEN MODE_SET => DATA_BUS_VALUE <= X"80";
LCD_EN <= '1'; state <= DROP_LCD_E;
LCD_RS <= '0'; next_command <= Print_String;
LCD_RW_INT <= '0'; -- The next three states occur at the end of each command or
DATA_BUS_VALUE <= X"06"; data transfer to the LCD
state <= DROP_LCD_E; -- Drop LCD E line - falling edge loads inst/data to LCD
next_command <= Print_String; controller
-- Write ASCII hex character in first LCD character location WHEN DROP_LCD_E =>
WHEN Print_String => LCD_EN <= '0';
state <= DROP_LCD_E; state <= HOLD;
LCD_EN <= '1'; -- Hold LCD inst/data valid after falling edge of E line
LCD_RS <= '1'; WHEN HOLD =>
LCD_RW_INT <= '0'; state <= next_command;
-- ASCII character to output END CASE;
IF Next_Char(7 DOWNTO 4) /= X"0" THEN END IF;
DATA_BUS_VALUE <= Next_Char; END IF;
ELSE END PROCESS;
-- Convert 4-bit value to an ASCII hex digit END Behavior;
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;

You might also like