library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity HC_SR04_Distance_Measurement is
port (
clk : in std_logic;
reset : in std_logic;
echo : in std_logic;
distance_out : out std_logic;
led_out : out std_logic_vector(3 downto 0); --- LEDs output
trigger : out std_logic
);
end HC_SR04_Distance_Measurement;
architecture Behavioral of HC_SR04_Distance_Measurement is
-- Constants
constant CLK_FREQ : integer := 50000000;
constant TRIGGER_INTERVAL : integer := 10000000; -- 200 milliseconds
constant TRIGGER_PULSE_WIDTH : integer := 500; -- 10 microseconds
constant CM_DIVISOR : integer := 58;
-- Signals
signal counter_trigger : unsigned(23 downto 0) := (others => '0');
signal counter_echo : unsigned(15 downto 0) := (others => '0');
signal distance_cm : integer range 0 to 255 := 0;
signal led_toggle : std_logic_vector(3 downto 0) := (others => '0');
signal trigger_pulse : std_logic := '0';
begin
-- Output distance threshold
distance_out <= '1' when distance_cm <= 40 else
'0' when distance_cm >= 140;
-- Connect LED toggle to output
led_out <= led_toggle;
-- Connect trigger pulse to output
trigger <= trigger_pulse;
-- Trigger pulse generation
trigger_pulse_gen: process(clk, reset)
begin
if reset = '0' then
counter_trigger <= (others => '0');
trigger_pulse <= '0';
elsif rising_edge(clk) then
-- Increment the counter
counter_trigger <= counter_trigger + 1;
-- Generate trigger pulse
if (counter_trigger = to_unsigned(TRIGGER_INTERVAL, counter_trigger'length)) then
trigger_pulse <= '1';
elsif counter_trigger = to_unsigned(TRIGGER_INTERVAL + TRIGGER_PULSE_WIDTH, counter_trigger'length) then
trigger_pulse <= '0';
counter_trigger <= (others => '0');
end if;
end if;
end process;
-- Echo pulse measurement
echo_pulse: process(clk, reset)
begin
if reset = '0' then
counter_echo <= (others => '0');
distance_cm <= 0;
elsif rising_edge(clk) then
-- Measure echo pulse width
if echo = '1' then
counter_echo <= counter_echo + 1;
elsif echo = '0' then
-- Calculate distance in cm using shifts
distance_cm <= to_integer(((counter_echo * 1000000) / CLK_FREQ) / CM_DIVISOR);
counter_echo <= (others => '0');
end if;
end if;
end process echo_pulse;
-- LED toggle for out of range
led_toggle_gen: process(clk, reset)
begin
if reset = '0' then
led_toggle <= (others => '1');
elsif rising_edge(clk) then
if distance_cm > 255 or distance_cm < 20 then
led_toggle <= not led_toggle;
else
led_toggle <= (others => '1');
end if;
end if;
end process;
end Behavioral;