VHDL Code for 8-Channel Analog Signal Acquisition and Display
Advertisement
This document presents VHDL code designed to accept an 8-channel analog signal and display it on either an LCD panel or a 7-segment display.
VHDL Source Code
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
use work.lcd_grap.all;
entity adc_lcd is
port (
clk: in std_logic; -- 4 MHz clock
reset: in std_logic; -- Master reset pin
intr: in std_logic;
adc_out: in std_logic_vector(7 downto 0);
cs, rd, wr: out std_logic;
lcd_rw: out std_logic;
lcd_select: out std_logic;
lcd_enable: out std_logic;
lcd_data: out std_logic_vector(7 downto 0) -- Registered data output
);
end adc_lcd;
architecture adc_beh of adc_lcd is
type state_type is (initial, display, clear, location, putchar);
signal state, next_state: state_type;
-- LCD Control Constants
constant clr: std_logic_vector(7 downto 0) := "00000001"; -- Clear screen
constant don: std_logic_vector(7 downto 0) := "00001100"; -- Display on, no cursor
constant set: std_logic_vector(7 downto 0) := "00111000"; -- 8-bit data, 2-line display
-- Frequency divider signals
signal counter: std_logic_vector(18 downto 0);
signal clk_div: std_logic;
constant big_delay: integer := 16;
constant small_delay: integer := 2;
constant reg_setup: integer := 1;
signal digital_data1, data1, data2: std_logic_vector(7 downto 0);
signal digital_data: integer range 0 to 255;
signal ntr: std_logic;
begin
ibuf_inst: ibuf
generic map (iostandard => "lvcmos25")
port map (
o => ntr, -- Buffer output
i => intr -- Buffer input (connect directly to top-level port)
);
process(clk)
begin
if clk = '1' and clk'event then
counter <= counter + '1';
end if;
end process;
clk_div <= counter(7);
cs <= '0';
wr <= ntr;
digital_data1 <= adc_out;
rd <= '0';
digital_data <= conv_integer(digital_data1);
process(digital_data)
begin
case (digital_data) is
when 0 to 100 => data1 <= one; data2 <= nine;
when 101 to 110 => data1 <= two; data2 <= zero;
when 111 to 120 => data1 <= two; data2 <= one;
when 121 to 130 => data1 <= two; data2 <= two;
when 131 to 140 => data1 <= two; data2 <= three;
when 141 to 150 => data1 <= two; data2 <= four;
when 151 to 160 => data1 <= two; data2 <= five;
when 161 to 170 => data1 <= two; data2 <= six;
when 171 to 180 => data1 <= two; data2 <= seven;
when 181 to 190 => data1 <= two; data2 <= eight;
when 191 to 200 => data1 <= two; data2 <= nine;
when 201 to 205 => data1 <= three; data2 <= zero;
when 206 to 210 => data1 <= three; data2 <= one;
when 211 to 215 => data1 <= three; data2 <= two;
when 216 to 220 => data1 <= three; data2 <= three;
when 221 to 225 => data1 <= three; data2 <= four;
when 226 to 230 => data1 <= three; data2 <= five;
when 231 to 235 => data1 <= three; data2 <= six;
when 236 to 240 => data1 <= three; data2 <= seven;
when 241 to 245 => data1 <= three; data2 <= eight;
when 246 to 250 => data1 <= three; data2 <= nine;
when others => data1 <= four; data2 <= zero;
end case;
end process;
lcd_rw <= '0';
process (clk_div, reset)
variable count: integer range 0 to big_delay;
variable c1: std_logic_vector(7 downto 0);
begin
if reset = '1' then
state <= initial;
count := 0;
lcd_enable <= '0';
lcd_select <= '0';
c1 := "01111111";
elsif clk_div'event and clk_div = '1' then
case state is
when initial => -- To set the function
if count = reg_setup then
lcd_enable <= '1';
else
lcd_enable <= '0';
end if;
lcd_data <= set;
lcd_select <= '0';
if count = small_delay then
state <= display;
count := 0;
else
count := count + 1;
end if;
when display => -- To set display on
if count = reg_setup then
lcd_enable <= '1';
else
lcd_enable <= '0';
end if;
lcd_data <= don;
lcd_select <= '0';
if count = small_delay then
state <= clear;
count := 0;
else
count := count + 1;
end if;
when clear => -- Clear the screen
if count = reg_setup then
lcd_enable <= '1';
else
lcd_enable <= '0';
end if;
lcd_data <= clr;
lcd_select <= '0';
if count = big_delay then
state <= location;
count := 0;
else
count := count + 1;
end if;
when location => -- Set cursor location
if count = reg_setup then
lcd_enable <= '1';
else
lcd_enable <= '0';
end if;
if count = 0 then
if c1 = "10001111" then
c1 := "10000000";
else
c1 := c1 + '1';
end if;
end if;
lcd_data <= c1;
lcd_select <= '0';
if count = big_delay then
state <= putchar;
count := 0;
else
count := count + 1;
end if;
when putchar => -- Display the character on the LCD
if count = reg_setup then
lcd_enable <= '1';
else
lcd_enable <= '0';
end if;
case c1 is
when "10000000" => lcd_data <= a;
when "10000001" => lcd_data <= d;
when "10000010" => lcd_data <= c;
when "10000011" => lcd_data <= space;
when "10000100" => lcd_data <= v;
when "10000101" => lcd_data <= o;
when "10000110" => lcd_data <= l;
when "10000111" => lcd_data <= t;
when "10001000" => lcd_data <= a;
when "10001001" => lcd_data <= g;
when "10001010" => lcd_data <= e;
when "10001011" => lcd_data <= space;
when "10001100" => lcd_data <= equal;
when "10001101" => lcd_data <= data1;
when "10001110" => lcd_data <= dot;
when "10001111" => lcd_data <= data2;
when "11000000" => lcd_data <= space;
when "11000001" => lcd_data <= space;
when "11000010" => lcd_data <= space;
when "11000011" => lcd_data <= space;
when "11000100" => lcd_data <= space;
when "11000101" => lcd_data <= space;
when "11000110" => lcd_data <= space;
when "11000111" => lcd_data <= space;
when "11001000" => lcd_data <= space;
when "11001001" => lcd_data <= space;
when "11001010" => lcd_data <= space;
when "11001011" => lcd_data <= space;
when "11001100" => lcd_data <= space;
when "11001101" => lcd_data <= space;
when "11001110" => lcd_data <= space;
when "11001111" => lcd_data <= space;
when others => null;
end case;
lcd_select <= '1';
if count = small_delay then
state <= location;
count := 0;
else
count := count + 1;
end if;
end case;
end if;
end process;
end adc_beh;
Explanation
This VHDL code describes a module (adc_lcd
) that reads an 8-bit analog value from an ADC and displays it on an LCD. Here’s a breakdown:
- Entity Declaration: Defines the input and output ports of the module. Crucially, it receives the ADC output (
adc_out
) and provides signals to control the LCD (lcd_rw
,lcd_select
,lcd_enable
,lcd_data
). - Architecture Body: Implements the behavior of the module. It utilizes a state machine (
state_type
) to control the LCD initialization and data display. - LCD Initialization: The
initial
state sends commands to the LCD to set it up for 8-bit data, 2-line display, and turns the display on. - Data Conversion and Display: The
digital_data
signal holds the integer representation of the ADC output. The code includes a process that maps ranges of ADC values to displayable charactersdata1
anddata2
forming a two digit number. The state machine then sends these characters to the LCD in theputchar
state. - Clock Division: A clock divider is used to slow down the clock signal for the LCD, as LCDs typically require slower control signals than the main system clock.
- Interrupt Handling: An interrupt signal (
intr
) is used to signal when the ADC has a new sample ready. This signal is buffered using anibuf
instance to ensure proper signal integrity.
VHDL Code Snippets Explanation
- Libraries: The code begins by declaring the necessary libraries.
ieee.std_logic_1164.all
is essential for standard logic types.ieee.std_logic_unsigned.all
andieee.std_logic_arith.all
are used for arithmetic operations onstd_logic_vector
signals, although the use of thenumeric_std
package is generally recommended for newer designs.work.lcd_grap.all
suggests a custom package containing LCD-related definitions (character constants, etc.). ibuf_inst
: This instantiates an input buffer. The generic mapiostandard => "lvcmos25"
specifies the I/O standard.- State machine: Implemented with
process (clk_div, reset)
. This is responsible for the LCD initialization and the data update cycles.