library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; entity sonar is generic ( -- slow clock is 25.175 Mhz / 156 / 2 = 80.689 kHz clock_divisor : positive := 156; -- max clock cycles to wait for pulse bounce back max_range : positive := 1000; -- time between measurement cycles in clock cycles display_time : positive := 5000 ); port ( -- reset is the right user button and is active low -- button is the left user button and is active high -- it toggles between measure and hold functions -- sonar_in is active high clk, reset, button, sonar_in : in std_logic; slow_clk, running : buffer std_logic; led1, led2 : out std_logic_vector(6 downto 0); sonar_out : buffer std_logic ); end sonar; architecture behavioral of sonar is type state_type is (sending_pulse, display); signal state : state_type; signal led_disp, led_disp2, timer : std_logic_vector(16 downto 0); signal slow_clk_count : std_logic_vector(7 downto 0); signal button_down, obj, recd_obj : std_logic; signal button_count : std_logic_vector(5 downto 0); constant zero : std_logic_vector(6 downto 0) := "1000000"; constant one : std_logic_vector(6 downto 0) := "1111001"; constant two : std_logic_vector(6 downto 0) := "0100100"; constant three : std_logic_vector(6 downto 0) := "0110000"; constant four : std_logic_vector(6 downto 0) := "0011001"; constant five : std_logic_vector(6 downto 0) := "0010010"; constant six : std_logic_vector(6 downto 0) := "0000010"; constant seven : std_logic_vector(6 downto 0) := "1111000"; constant eight : std_logic_vector(6 downto 0) := "0000000"; constant nine : std_logic_vector(6 downto 0) := "0010000"; begin -- process to divide clock by any integer amount x2 process (clk) begin if clk'EVENT and clk = '1' then if slow_clk_count = clock_divisor then slow_clk_count <= (others => '0'); slow_clk <= not slow_clk; else slow_clk_count <= slow_clk_count + 1; end if; end if; end process; -- latch return pulse at 25 MHz so we don't happen -- to miss the first return pulse process (clk, reset) begin if reset = '0' then obj <= '0'; elsif clk'EVENT and clk = '1' then if recd_obj = '1' then obj <= '0'; elsif sonar_in = '1' then obj <= '1'; end if; end if; end process; -- this process runs the whole thing process (slow_clk, sonar_in) begin if reset = '0' then state <= display; button_down <= '0'; timer <= (others => '1'); running <= '0'; led_disp <= (others => '0'); sonar_out <= '1'; elsif slow_clk'EVENT and slow_clk = '1' then -- when a button is pressed toggle between running -- and not running -- once a button is pressed it waits for 64 clock -- cycles before registering the next button state -- (button debouncer) if button = '0' then if button_down = '0' then running <= not running; button_down <= '1'; button_count <= (others => '0'); else button_count <= button_count + 1; end if; elsif button_down = '1' then if button_count = 63 then button_down <= '0'; button_count <= (others => '0'); else button_count <= button_count + 1; end if; end if; -- state machine keeps firing of ultrasonic pulses -- and times how long it takes the first one to get -- back, then waits for a period of time as set by -- display_time, this keeps the led output from -- changing too quickly to be readable case state is when sending_pulse => timer <= timer + 1; if running = '0' then state <= display; sonar_out <= '1'; elsif obj = '1' then state <= display; led_disp <= timer; timer <= (others => '0'); sonar_out <= '1'; recd_obj <= '1'; elsif timer >= max_range then led_disp <= (others => '0'); timer <= (others => '0'); state <= display; sonar_out <= '1'; else sonar_out <= not sonar_out; end if; when display => if timer > display_time then timer <= (others => '0'); state <= sending_pulse; recd_obj <= '0'; elsif running = '1' then timer <= timer + 1; end if; when others => timer <= (others => '0'); state <= display; end case; end if; end process; -- this process takes led_disp and interprets it into -- human usable data output to the led display -- each clock cycle is about 2.13 mm -- 343 m/s / 80 kHz / 2 process (led_disp) begin -- take care of most significant digit -- and output on left 7 segment display if led_disp >=0 and led_disp < 45 then led1 <= zero; led_disp2 <= led_disp; elsif led_disp >= 45 and led_disp < 90 then led1 <= one; led_disp2 <= led_disp - 45; elsif led_disp >= 90 and led_disp < 135 then led1 <= two; led_disp2 <= led_disp - 90; elsif led_disp >= 135 and led_disp < 180 then led1 <= three; led_disp2 <= led_disp - 135; elsif led_disp >= 180 and led_disp < 225 then led1 <= four; led_disp2 <= led_disp - 180; elsif led_disp >= 225 and led_disp < 270 then led1 <= five; led_disp2 <= led_disp - 225; elsif led_disp >= 270 and led_disp < 315 then led1 <= six; led_disp2 <= led_disp - 270; elsif led_disp >= 315 and led_disp < 360 then led1 <= seven; led_disp2 <= led_disp - 315; elsif led_disp >= 360 and led_disp < 405 then led1 <= eight; led_disp2 <= led_disp - 360; elsif led_disp >= 405 then led1 <= nine; led_disp2 <= led_disp - 405; end if; -- take care of least significant digit -- and output on right 7 segment display if led_disp2 >= 0 and led_disp2 < 3 then led2 <= zero; elsif led_disp2 >= 3 and led_disp2 < 8 then led2 <= one; elsif led_disp2 >= 8 and led_disp2 < 12 then led2 <= two; elsif led_disp2 >= 12 and led_disp2 < 17 then led2 <= three; elsif led_disp2 >= 17 and led_disp2 < 22 then led2 <= four; elsif led_disp2 >= 22 and led_disp2 < 26 then led2 <= five; elsif led_disp2 >= 26 and led_disp2 < 31 then led2 <= six; elsif led_disp2 >= 31 and led_disp2 < 36 then led2 <= seven; elsif led_disp2 >= 36 and led_disp2 < 40 then led2 <= eight; elsif led_disp2 >= 40 then led2 <= nine; end if; end process; end behavioral;