⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 freq_counter.vhd

📁 分频器 几次分频欧次分频 vhdl 语言实现
💻 VHD
字号:
--
--
-- AUTO-RANGING Single Chip Frequency Counter
--
-- This is a synthesizable model of an autoranging frequency counter.
-- The overall frequency counting coverage is from DC~9.999MHz.  There are
-- four ranges, which are "auto" selected:
--
--			frequency 			GATE width
--		 DC-9999Hz,					1    sec
--		 10.00KHz-99.99KHz,			.1   sec
--		 100.0KHz-999.9KHz.			.01  sec
--		 1.000MHz-9.999MHz			.001 sec
--
--
-- Top level chip-interface is as follows:
--
-- Input:
-- 		sys_rs_l		std_logic		asynchronous actuve low reset
--		ref_clk			std_logic		10MHz reference clock input
--		Funknown		std_logic		reference clock input from DC - 10Mhz
--
-- Output
--		gate0_l			std_logic		one's place 7segment LED common anode gate
--		gate1_l			std_logic		ten's place 6segment LED common anode gate										
--		gate2_l			std_logic		hundred's place 7segment LED common anode gate
--		gate3_l			std_logic		thousand's place 6segment LED common anode gate										
--
--
--
-- OPERATION
--
-- This frequency counter is based on the premise of counting the incoming unknown
-- frequency's rising edge for a predetermined fixed amount of time, or GATE.
-- If the counter overflow , then the presently selected GATE is too wide, so the
-- next shortest GATE width is selected.  This switching is done immediately, so
-- that no time is wasted in waiting for the GATE to turn off.
-- The measured frequency data is then displayed onto a multiplexed 4 digit 7segment
-- LED display.  Since the LED display is refhreshed at 100KHz, a fixed time interval
-- is waited before the next conversion cycle.  This gives the display a chance to
-- "update" all the segments. 
--
--
-- STATE TRANSITION
--
--            /------\
-- 			 |	      |
--			 |		IDLE
-- 			 |		  |
--			 |	 /--  |        
--			 |	 |  \ V        overflow=HI
--			 |	 |  GATE_ON ----------------> OVERFLOW
--           |   \--/ |                           |
-- 			 |		  |                           |
--			 |		  | gate_counter=N            |
--           |        |                           |
--			 |		  V                           |
--			 |	    DISPLAY                       |
--			 |		  |                           |
--			 |		  |                           |
--			 |	 /--  |                           |
--			 |	 |	\ V                           |
--			 |	 |	DELAY <----------------------/
--			 |	 \--/ |
--			 \-------/
--                gate_counter=N2
--
--  IDLE state
--	This state hold the BCD counter in reset state then transitions 
--  into the next state, GATE_ON.  The BCD counter must be hold into reset
--  in order not to accumulate from the previous count cycle
--
--  GATE_ON state
--  In this state, the BCD counter is allowed to start counting by asserting 
--	the signal 'GATE'.  Also, an internal timer is started which times
--  the time for which the GATE should be on for.  Go to next state when
--  the timer hits the expected tick count
--
--  DISPLAY state
--  In this state, the 4 digit muxed display is "refreshed", that is loaded with 
--  the new data from the BCD counter
--
--  DELAY state
--  This state simply waits for a fixed delay.  This fixed delay is required
--  in order to give the display a chance to cycle through the segment refreshing
--
--  OVERFLOW state
--  This state enters when the BCD counter overflows with the given GATE.  This 
--  means that the GATE is too long, so the next shortest gate length is chosen
--  and the measurement starts over again.
--
--
--

LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_arith.all;
USE ieee.std_logic_unsigned.all;

 
ENTITY freq_counter IS
   PORT (
			sys_rst_l	:	IN  std_logic;
			ref_clk		: 	IN  std_logic;
			Funknown	: 	IN  std_logic;
			gate0_l		:	OUT std_logic;
			gate1_l		: 	OUT std_logic;
			gate2_l		: 	OUT std_logic;
			gate3_l		:	OUT std_logic;
			digit_out_l	:	OUT std_logic_vector (7 downto 0);

			-- debug
			d_gate		: 	OUT std_logic;
			d_gate_cnt_limit : OUT integer range 0 to 10000000;
			d_f_counter_count_out : OUT std_logic_vector (15 downto 0);
			d_f_overflow	: OUT std_logic
		);
END freq_counter;


ARCHITECTURE FREQ_COUNTER_RTL OF freq_counter IS

  -- Declare the 4 digit muxed 7segment LED display DISPLAY 
  COMPONENT disp4_muxed  
  PORT ( clk_disp	: IN  std_logic;
		 clk_ref	: IN  std_logic;
		 sys_rst_l	: IN  std_logic;
		 data_in 	: IN  std_logic_vector (15 downto 0);
		 dp_in		: IN  std_logic_vector ( 1 downto 0);
         load		: IN  std_logic;
		 gate0_l	: OUT std_logic;
		 gate1_l	: OUT std_logic;
		 gate2_l	: OUT std_logic;
		 gate3_l	: OUT std_logic;
		 digit_out_l: OUT std_logic_vector (7 downto 0)	-- MSB=dp,g,f,.., LSB=a
 	   );
  END COMPONENT;
  -- Declare the 4 digit BCD counter
  COMPONENT bcdcounter4 
   PORT ( Funknown	:	IN  std_logic;
	 	  sys_rst_l	:	IN  std_logic;
		  GATE		: 	IN  std_logic;
		  ready		:   OUT std_logic;
		  data_out	:   OUT std_logic_vector (15 downto 0);
		  overflow	: 	OUT std_logic
 	    );
  END COMPONENT;
   
  CONSTANT HIGH 			:	std_logic := '1';
  CONSTANT LOW				:   std_logic := '0';
  TYPE allowed_states IS (idle, gate_on, display, delay, overflow);
  SIGNAL state 				: allowed_states;  
  SIGNAL display_load		: std_logic;
  SIGNAL gate				: std_logic;
  SIGNAL f_ready			: std_logic;
  SIGNAL f_counter_count_out : std_logic_vector (15 downto 0);
  SIGNAL f_overflow			: std_logic;
  SIGNAL clk_100Khz			: std_logic;
  SIGNAL scaler				: std_logic_vector (2 downto 0);
  SIGNAL auto_scale			: std_logic_vector (2 downto 0);
  SIGNAL gate_counter 		: integer RANGE 0 TO 10000000;  -- 24 bits
  SIGNAL GATE_CNT_LIMIT		: integer RANGE 0 TO 10000000;
  SIGNAL cnt_ena			: std_logic;
  SIGNAL counter_reset		: std_logic;


  -- RTL BEGINS HERE
  BEGIN
   

  -- debug signals (turn them off if yuo do not need them
  -- these were on for helping simulation)
  d_gate <= gate;
  d_gate_cnt_limit <= gate_cnt_limit;
  d_f_counter_count_out <= f_counter_count_out;
  d_f_overflow <= f_overflow;

  -- Connect the subcomponenet 
  THE_DISPLAY: disp4_muxed PORT MAP (clk_disp	=>	clk_100Khz,
									clk_ref		=>  ref_clk,
									sys_rst_l   =>  sys_rst_l,
									data_in		=>  f_counter_count_out,  
			 						dp_in		=>  NOT (auto_scale(1 downto 0)),
      								load		=>  display_load,
									gate0_l		=>  gate0_l,
									gate1_l		=>  gate1_l,
									gate2_l		=>  gate2_l,
									gate3_l		=>  gate3_l,
									digit_out_l =>  digit_out_l );

  -- COnnect the 4 digit BCD counter
  THE_COUNTER: bcdcounter4 PORT MAP	(Funknown	=>  Funknown,
									sys_rst_l	=> 	counter_reset,
									GATE		=>  gate,
									ready		=> 	f_ready,
									data_out	=>	f_counter_count_out,
									overflow	=>  f_overflow );


  
  -- CONTROLLER STATE MACHINE
  --
  SM: PROCESS (sys_rst_l, ref_clk)

    BEGIN
	  -- on reset clear the world
      IF (sys_rst_l=LOW) THEN 
         state 			<= idle;
		 scaler 		<= "000";
		 auto_scale		<= "000";
		 gate           <= LOW;
		 cnt_ena		<= LOW;
	     display_load   <= LOW;
 		 counter_reset <= LOW;	-- reset the fcounter

      -- on every rising edge of ref_clk (10MHz)
      ELSIF (ref_clk=HIGH and ref_clk'EVENT) THEN
         CASE (state) IS

             -- IDLE state
			 -- goto next state 
             WHEN idle =>
 				state <= gate_on;
				counter_reset <= LOW;	-- reset the fcounter

			 -- GATE_ON state
			 -- turn on the "gate" which the BCD counter will count clk pulses			 
			 WHEN gate_on =>
                counter_reset <= HIGH;
				gate	 	<= HIGH;	-- GATE is high
				cnt_ena		<= HIGH;	-- GATE counter is enabled
                -- if the gate counter reaches the gate time limit, goto next state
				IF (gate_counter=GATE_CNT_LIMIT) THEN
					gate	<= LOW;		-- turn off gate
					cnt_ena <= LOW;		-- turn off gate counter
					state 	<= display;
					auto_scale <= "000";
				-- if the BCD counter has overflowed, go to overflow state
                ELSIF (f_overflow=HIGH) THEN
					state   <= overflow;					
				END IF;

			 -- DISPLAY state
			 -- go and "refresh" the display							
			 WHEN display =>
			    display_load <= HIGH;	-- load the display with the recent BCD counter
				state 		 <= delay;

			 -- DELAY state
			 -- wait here for a bit, to give the muxed LED display a chance
			 -- to go through its mux cycle
			 WHEN delay =>
				scaler		 <= "100";	-- set delay to be just the display delay
				cnt_ena		 <= HIGH;	-- enable gate counter
				display_load <= LOW;	-- stop with the loading..
				-- when the counter has hit the time limit go to next state
				IF (gate_counter=GATE_CNT_LIMIT) THEN
					cnt_ena	 <= LOW;	-- turn off gate counter
					scaler   <= auto_scale;
					state	 <= idle;
				END IF;

			 -- OVERFLOW state
			 -- when the BCD counter has overflowed with the current gate width,
			 -- select the next shortest gate (1sec, .1sec, .01sec and .001 sec)
			 -- and remeasure it.
			 WHEN overflow =>
				CASE (auto_scale) IS
					WHEN "000" => auto_scale <= "001";
					WHEN "001" => auto_scale <= "010";
					WHEN "010" => auto_scale <= "011";
					WHEN "011" => auto_scale <= "011";
					WHEN OTHERS => NULL;						
				END CASE;
				gate	<= LOW;		-- turn off gate
				cnt_ena	<= LOW;
				state 	<= delay;
		END CASE;				
	  END IF;
  END PROCESS SM;


  -- GATE WIDTH SELECTOR
  -- This process selects the width of the GATE signal, by selecting
  -- the ticks which will equal the reference time.  The ticks is
  -- based on 100nS period (10MHz).  IF you're using a differenct clock, you need to
  -- change the below 5 values
  PROCESS (scaler)
  BEGIN
    CASE (scaler) IS
       WHEN "000" =>
			GATE_CNT_LIMIT <= 10000000;		-- 10 million cycles per GATE of 1    SECOND
	   WHEN "001" =>
			GATE_CNT_LIMIT <= 1000000;		-- 1  million cycles per GATE of .1   SECOND
	   WHEN "010" =>
			GATE_CNT_LIMIT <= 100000;		-- 100K		  cycles per GATE of .01  SECOND
	   WHEN "011" =>
			GATE_CNT_LIMIT <= 10000;		-- 10K		  cycles per GATE of .001 SECOND
	   WHEN "100" =>
			GATE_CNT_LIMIT <= 50000;		-- 50000 a bit of delay, for LED mux disp refresh
	   WHEN OTHERS =>
			NULL;
    END CASE;
  END PROCESS;

 
  -- TIMER
  -- This timer is enabled when "ent_ena" signal is asserted.  
  -- Synchronous to the 10MHZ clock, on the rising edge
  PROCESS (cnt_ena, ref_clk )
  BEGIN
     IF (cnt_ena=LOW) THEN
        gate_counter <= 0;
     ELSIF (ref_clk=HIGH and ref_clk'EVENT) THEN
		gate_counter <= gate_counter + 1;
     END IF;
  END PROCESS;
   
 
  -- 100KHz clock generator
  -- This is a divider which gnerates 100KHz clock from the 10MHz clock in
  -- The 100KHz clock is used on the LED display segment refreshing
  PROCESS (sys_rst_l, ref_clk)
  VARIABLE counter    : INTEGER range 0 TO 50;  
  BEGIN
     IF (sys_rst_l='0') THEN	-- active low, asynchronous reset
       clk_100KHZ <= '0';
       counter := 0;
     ELSIF (ref_clk='1' AND ref_clk'EVENT) THEN		-- toggle at 50 ticks of 100nS
       IF (counter=50) THEN
          clk_100KHZ <= NOT clk_100KHZ;
		  counter := 0;
       ELSE 
          counter := counter + 1;
       END IF;
     END IF;
  END PROCESS;



  END FREQ_COUNTER_RTL;
	



⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -