天天看點

VHDL控制ADC TLC549采集電壓并通過序列槽發送到PC

VHDL控制ADC TLC549采集電壓并通過序列槽發送到PC

VHDL代碼

.

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
-----------------------------------------------
entity ADC_TLC549 is

generic(
		data_bits :std_logic_vector(3 downto 0) := "1000";	--data_bits收發資料位數
		delay_ms: STD_LOGIC_VECTOR (5 downto 0) := "110010";--Amount of 100ms to delay
		div: integer := 27;									--div時鐘分頻系數
		udata_bits: integer := 8
		--div: STD_LOGIC_VECTOR (4 downto 0) := "11011"		--div時鐘分頻系數	
		);


port(
		--uart
--		rxd_in: in std_logic;			--rxd_in 序列槽輸入端
		txd_out:out std_logic;			--txd_out 序列槽輸出端
		--ADC
		rst: in std_logic;
		clk: in std_logic;		--internal clk
		sclk: buffer std_logic;	-- clk to ADC 
		din: in std_logic;
		cs: out std_logic
		
);
end entity;
---------------------------------------------------
architecture behave of ADC_TLC549 is

signal div_cnt: std_logic_vector(7 downto 0) := (others => '0');
signal delay_cnt: std_logic_vector(7 downto 0):= (others => '0');
signal us_count: std_logic_vector(7 downto 0) := (others => '0');
signal buff_vout: std_logic_vector(0 to 7) := (others => '0');
--signal adc_bit_cnt: std_logic_vector(7 downto 0) := (others => '0');
signal adc_bit_cnt: integer := 0;
signal rising: std_logic := '0';
signal falling: std_logic := '0';
signal vout_flag: std_logic:= '0';
type adc_states is(adc_idle,
						 adc_convert,
						 adc_waite17us,
						 adc_waite2us,
						 adc_out);

signal adc_pr_state: adc_states := adc_idle;


--Variable about uart								
	signal count: integer range 0 to div*2;		--count 内部晶振時鐘計數
	signal dclk: std_logic;							--dclk 分頻後的時鐘
	signal txd_buffer: std_logic_vector(7 downto 0);			--txd_buffer 發送資料緩沖區
	signal tclk_cnt: std_logic_vector(3 downto 0);				--tclk_cnt 序列槽輸出時鐘計數
	signal txd_cnt: integer range 0 to udata_bits;				--txd_cnt 序列槽輸出位計數
	signal rising_dclk: std_logic;
	signal ms_count1: std_logic_vector(11 downto 0);
	signal ms_count2: std_logic_vector(11 downto 0);	
	type txd_states is (T_none, 
						T_start,
						T_wait, 
						T_shift, 
						T_stop
						--T_delay1s	--txd_states 發送的狀态機
						);		
	signal txd_state: txd_states := T_none;
	
											 
begin


-----------------clock divider 64 division-----------
	
	sclk <= div_cnt(5); 					--SCLK = CLK / 64		   
	CLK_DIV: process(clk)
	begin
		if(rising_edge(clk)) then
			if(rst = '1')then
				div_cnt <= (others => '0');
			else
				if (adc_pr_state = adc_convert) then 			--start clock counter when in send state
					div_cnt <= div_cnt + 1;
				else 								--reset clock counter when not in send state
					div_cnt <= (others => '0');
				end if;
			end if;
		end if;
	end process;	


----------------ADC component----------------------------
	process(clk)
	begin
		if(rising_edge(clk))then
			if(rst = '1')then
				cs <= '1';
				us_count <= x"00";
				delay_cnt <= x"00";
				adc_bit_cnt <= 0;
				rising <= '0';
				falling <= '0';
				txd_buffer <= x"00";--buff_vout <= x"00";
				vout_flag <= '0';	
				adc_pr_state <=adc_idle;
			else
				case adc_pr_state is
					when adc_idle =>
						cs <= '1';
						adc_pr_state <= adc_waite2us;
						
					when adc_waite2us =>
						cs <= '0';
						if(delay_cnt = X"31")then			--50 count, 1us
							if(us_count = X"01")then			-- delay 2us
								if(txd_state = T_none)then						--make sure uart is ready
									us_count <= x"00";
									delay_cnt <= x"00";
									adc_pr_state <= adc_convert;
								end if;
							else
								us_count <= us_count + '1';
								delay_cnt <= x"00";
							end if;
						else
							delay_cnt <= delay_cnt + '1';
						end if;
						
					when adc_convert =>
						
							if(sclk = '1' and rising = '0')then
								rising <= '1';
								falling <= '0';
								txd_buffer (7 - adc_bit_cnt) <= din; --buff_vout(7 - adc_bit_cnt) <= din;
								adc_bit_cnt <= adc_bit_cnt + 1;
							elsif(sclk = '0' and falling = '0')then
								falling <= '1';
								rising <= '0';
								if(adc_bit_cnt = 8)then
									adc_pr_state <= adc_waite17us;
									adc_bit_cnt <= 0;
									rising <= '0';
									vout_flag <= '1';							--ready to output digital value				
								end if;
							end if;	
					
					
					--wait for 17us 
					when adc_waite17us =>
						cs <= '1';
						if(delay_cnt = X"31")then			--50 count, 1us
							if(us_count = X"10")then			-- delay 17us
								us_count <= x"00";
								delay_cnt <= x"00";
								adc_pr_state <= adc_waite2us;
								vout_flag <= '0';						--clear ready flag
							else
								us_count <= us_count + '1';
								delay_cnt <= x"00";
							end if;
						else
							delay_cnt <= delay_cnt + '1';
						end if;					
					when others=>
						adc_pr_state <= adc_idle;
					
				end case;
			end if;
		end if;
	end process;
------------------------------------------------------------------------------


	
--------------- uart dclk divider-----------------	
	process(clk)
		
	begin
		if(clk'event and clk = '1')then
			if(count < div/2)then
				count <= count + 1;
				dclk <= '0';
			elsif(count < div -1)then
				count <= count + 1;
				dclk <= '1';
			else
				count <= 0;
				dclk <= '0';
			end if;
		
		end if;
	end process;
	

-------------------------TXD--------------------------------------------
	process(clk)
	begin
		if(rising_edge(clk))then
			if(rst = '1')then
				txd_state <= T_none;
				ms_count1 <= X"000";
				ms_count2 <= X"000";
				txd_cnt <= 0;
				tclk_cnt <= "0000";
				txd_out <= '1';
			else
				if(dclk = '1' and rising_dclk = '0')then
					rising_dclk <= '1';
					case txd_state is 
						when T_none =>
							if(vout_flag = '1')then
								txd_state <= T_start;
							else
								txd_cnt <= 0;
								tclk_cnt <= "0000";
							end if;
							txd_out <= '1';
						when T_start =>
							txd_out <= '0';
							txd_state <= T_wait;
						when T_wait =>
							if(tclk_cnt = "1110")then
								if(txd_cnt = udata_bits)then
									txd_cnt <= 0;
									txd_state <= T_stop;
								else
									txd_state <= T_shift;
								end if;
								tclk_cnt <= "0000";
							else
								tclk_cnt <= tclk_cnt + '1';
							end if;
						when T_shift =>
							txd_out <= txd_buffer(txd_cnt);
							txd_cnt <= txd_cnt + 1;
							txd_state <= T_wait;
						when T_stop =>
							if(tclk_cnt = "1111")then
								txd_state <= T_none;--T_delay1s;
								tclk_cnt <= "0000";
							else
								tclk_cnt <= tclk_cnt + '1';
							end if;
							txd_out <= '1';
					end case;
				elsif(dclk = '0')then 
					rising_dclk <= '0';
				end if;
			end if;
		end if;
	end process;
end behave;

           

VHDL testbench代碼

.

-- Copyright (C) 2018  Intel Corporation. All rights reserved.
-- Your use of Intel Corporation's design tools, logic functions 
-- and other software and tools, and its AMPP partner logic 
-- functions, and any output files from any of the foregoing 
-- (including device programming or simulation files), and any 
-- associated documentation or information are expressly subject 
-- to the terms and conditions of the Intel Program License 
-- Subscription Agreement, the Intel Quartus Prime License Agreement,
-- the Intel FPGA IP License Agreement, or other applicable license
-- agreement, including, without limitation, that your use is for
-- the sole purpose of programming logic devices manufactured by
-- Intel and sold by Intel or its authorized distributors.  Please
-- refer to the applicable agreement for further details.

-- ***************************************************************************
-- This file contains a Vhdl test bench template that is freely editable to   
-- suit user's needs .Comments are provided in each section to help the user  
-- fill out necessary details.                                                
-- ***************************************************************************
-- Generated on "03/07/2019 10:13:47"
                                                            
-- Vhdl Test Bench template for design  :  ADC_TLC549
-- 
-- Simulation tool : ModelSim-Altera (VHDL)
-- 

LIBRARY ieee;                                               
USE ieee.std_logic_1164.all;                                

ENTITY ADC_TLC549_vhd_tst IS
END ADC_TLC549_vhd_tst;
ARCHITECTURE ADC_TLC549_arch OF ADC_TLC549_vhd_tst IS
-- constants    
constant clk_period: time := 20ns;                                                
-- signals                                                   
SIGNAL clk : STD_LOGIC;
SIGNAL cs : STD_LOGIC;
SIGNAL din : STD_LOGIC;
SIGNAL rst : STD_LOGIC :='0';
SIGNAL sclk : STD_LOGIC := '0';
SIGNAL txd_out : STD_LOGIC;
COMPONENT ADC_TLC549
	PORT (
	clk : IN STD_LOGIC;
	cs : OUT STD_LOGIC;
	din : IN STD_LOGIC;
	rst : IN STD_LOGIC;
	sclk : BUFFER STD_LOGIC;
	txd_out : OUT STD_LOGIC
	);
END COMPONENT;
BEGIN
	i1 : ADC_TLC549
	PORT MAP (
-- list connections between master ports and signals
	clk => clk,
	cs => cs,
	din => din,
	rst => rst,
	sclk => sclk,
	txd_out => txd_out
	);
init : PROCESS                                               
-- variable declarations                                     
BEGIN                                     
wait for clk_period/4;
rst <= '1';
wait for clk_period/4;
rst <= '0';	                                             
        -- code that executes only once                      
WAIT;                                                       
END PROCESS init;                                           
always : PROCESS                                              
-- optional sensitivity list                                  
-- (        )                                                 
-- variable declarations                                      
BEGIN                                                         
        -- code executes for every event on sensitivity list  
WAIT;                                                        
END PROCESS always;

		process
		begin
			clk <= '0';
			wait for clk_period/2;
			clk <= '1';
			wait for clk_period/2;
		end process; 
		
		process
		begin
			din <= '0';
			wait for clk_period;
			din <= '1';
			wait for clk_period;
		end process; 


                                          
END ADC_TLC549_arch;

           

繼續閱讀