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;