如何在数据块的数据块与uart的TX端口之间以10 ms的延迟发送10次数据

时间:2014-05-18 08:39:25

标签: vhdl uart

我有一个传感器,它有一个解锁的字节序列,需要发送给它解锁它,然后它可以接收其他命令数据。 传感器以115200 bps的波特率接收数据,8个数据位,偶校验,2个停止位。 在接收任何命令数据(用于设置参数)之前,需要以1ms的间隔接收d4(十六进制数,字节)10次。 我发送d4转换为位11010100添加了奇偶校验,停止位变为11010100011到uart的TX端口,波特率为115200,但是如何在两个d4数据字节发送之间创建延迟?我写的代码如果不清楚请告诉我我会提供更多细节。

entity Uart_tx is

port (

  TX : out std_logic;
  clk_in : in std_logic;
  but_div_clk : out std_logic;
  clk_in_2 : in std_logic

);

end Uart_tx;

architecture Behavioral of Uart_tx is

  signal tx_clk : std_logic := '0';
  signal clk_1Khz : std_logic := '0';
  signal q : unsigned(8 downto 0) := (others => '0');
  signal p : unsigned(8 downto 0) := (others => '0');

  type state_type is (idle, start);
  signal state : state_type;

  signal tick_in : std_logic := '0';

  subtype byte is std_logic_Vector(7 downto 0);
  type byte_array is array(natural range <>) of byte;
  signal data_byte_array : byte_array(1 to 8);

  --  signal curr_byte : std_logic_vector(7 downto 0);
  signal byte_index : unsigned(2 downto 0) := "000";


  subtype reg is std_logic_Vector(10 downto 0);
  type reg_array is array(natural range <>) of reg;
  signal TxDataReg_array : reg_array(1 to 8);

  signal cur_Tx_reg : std_logic_vector(10 downto 0); 
  signal current_reg : unsigned(3 downto 0) := "0001";
  signal count : unsigned (4 downto 0) := (others => '0');

  signal count_d : unsigned (4 downto 0) := (others => '0');
  signal sent_d4 : unsigned (3 downto 0) := (others => '0');

  signal send_d4 : std_logic := '1';
  signal D_4 : std_logic_vector(10 downto 0) :="11000101011"; 

begin
  -- below are random entry ..actual data will come from slv_reg registers.
  data_byte_array(1) <= "10101010"; -- slv_reg0(7 downto 0);
  data_byte_array(2) <= "10101011"; -- slv_reg0(15 downto 8);
  data_byte_array(3) <= "10101010"; -- slv_reg0(23 downto 16);
  data_byte_array(4) <= "10101011"; -- slv_reg0(31 downto 24);
  data_byte_array(5) <= "10101010"; -- slv_reg1(39 downto 32);
  data_byte_array(6) <= "10101011"; -- slv_reg1(47 downto 40);
  data_byte_array(7) <= "10101010"; -- slv_reg1(55 downto 48);
  data_byte_array(8) <= "10101011"; -- slv_reg1(63 downto 56);
  tick_in <= '1';

  ---------------------------------------Clk_div-----------------------------------------

  process ( clk_in ) is 
  begin 
    if clk_in'event and clk_in = '1' then

      q <= q + 1;

      tx_clk <= q(8);   --- 58.gdfg/2^8 =~ 230Khz baud rate = 115200 

      but_div_clk <= tx_clk;
    end if;
  end process;

  ---------------------------------------Clk_div------------------------------------------


  ---------------------------------------Clk_div------------------------------------------

  process( clk_in_2 ) is 
  begin 

    if clk_in_2'event and clk_in_2 = '1' then

      p <= p + 1;

      clk_1Khz <= p(7);

    end if;
  end process;

  ---------------------------------------------------------------------------------------

  --------------------------------------TX_Process----------------------------------------   

  process( state, tx_clk , tick_in) is 

    variable parity : std_logic := '0';
    variable curr_byte : std_logic_vector(7 downto 0) := (others => '0');
  begin 

    case state is 

      when idle => TX <= '1';
        if tick_in = '1' then 
          state <= start;
        else 
          TX <= '1';
        end if;

      when start => 

        if send_d4 = '1' then 

          if (rising_edge(clk_1Khz)) then 

            case count_d is
              when "00000" => TX <= D_4(0);
              when "00001" => TX <= D_4(1);
              when "00010" => TX <= D_4(2);
              when "00011" => TX <= D_4(3);
              when "00100" => TX <= D_4(4);
              when "00101" => TX <= D_4(5);
              when "00110" => TX <= D_4(6);
              when "00111" => TX <= D_4(7);
              when "01000" => TX <= D_4(8);
              when "01001" => TX <= D_4(9);
              when "01010" => TX <= D_4(10);
              when others => TX <= '1';
            end case;

            count_d <= count_d +1;
            sent_d4 <= sent_d4 + 1;
            if to_integer(count_d) = 11 then
              count_d <= "00000";
            end if;

            if to_integer(sent_d4) = 10 then 
              send_d4 <= '0' ;    
            end if;
          end if;
        else 
          for i in 1 to 8 loop 

            curr_byte := data_byte_array(i);
            parity := '0';
            for j in curr_byte'range loop
              parity := parity xor curr_byte(j);
            end loop;

            if parity = '0' then
              TxDataReg_array(i) <= "110" & curr_byte ;
            else 
              TxDataReg_array(i) <= "111" & curr_byte ;
            end if;
          end loop;
          cur_Tx_reg <= TxDataReg_array(to_integer(byte_index)+1);
          byte_index <= byte_index + 1;   

          if rising_edge(tx_clk) then     
            case count is
              when "00000" => TX <= cur_Tx_reg(0);
              when "00001" => TX <= cur_Tx_reg(1);
              when "00010" => TX <= cur_Tx_reg(2);
              when "00011" => TX <= cur_Tx_reg(3);
              when "00100" => TX <= cur_Tx_reg(4);
              when "00101" => TX <= cur_Tx_reg(5);
              when "00110" => TX <= cur_Tx_reg(6);
              when "00111" => TX <= cur_Tx_reg(7);
              when "01000" => TX <= cur_Tx_reg(8);
              when "01001" => TX <= cur_Tx_reg(9);
              when "01010" => TX <= cur_Tx_reg(10);
              when others => TX <= '1';
            end case;
            count <= count+1;
            if to_integer(count) = 11 then
              count <= "00000";
              state   <= idle;
              --      TX  <= '1';
            end if;
          end if;         

        end if;

      when others => TX <= '1';
    end case;

  end process;

end Behavioral;

1 个答案:

答案 0 :(得分:0)

要获得定时延迟,您必须实现一个计数器,该计数器会计算出等于1 ms的计算时钟周期数。然后,您需要在FSM中插入激活计数器的状态,并在需要时等待它完成。可以手动计算计数器值,但您可以让工具为您工作,避免在代码中使用幻数。

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
...

constant CLOCK_FREQ   : real := 50.0e6; -- 50 MHz system clock
constant SENSOR_DELAY : real := 1.0e-3; -- 1 ms delay
constant DELAY_COUNT  : natural := integer(CLOCK_FREQ * SENSOR_DELAY);

-- This could be auto calculated with a ceil_log2() function
constant TIMER_SIZE : natural := 16;

signal timer : unsigned(TIMER_SIZE-1 downto 0);
constant DELAY_INIT : unsigned(timer'range)
    := to_unsigned(DELAY_COUNT, timer'length);
...

-- Initialize the timer sometime before you want the delay
timer <= DELAY_INIT;
...

-- Somewhere in your FSM
when WAIT_1MS =>
  timer <= timer - 1;
  if timer = 0 then
    state <= WHATEVER_YOU_WANT_NEXT;
  end if;

使用实常数计算整数值的这种方法受到舍入误差和一般浮点不准确性的影响。对于这些长时间延迟,可能发生的小错误(通常是一个一个)通常不会引起关注。

请注意,您需要重新设计状态机以遵循更常规的模式。您已经创建了一个将纯组合逻辑与同步逻辑混合的过程。你不应该把两者混在一起。你不应该在你的FSM case语句中有rising_edge()测试,而应该有一个if-block评估包含你的FSM的rising_edge()。

如果您需要时钟敏感的过程,那么它的灵敏度列表中应该只有时钟和(可选的)异步复位。任何其他纯组合代码都应该放在一个单独的过程中。在这样的设计中,虽然不应该是必要的。

VHDL允许你现在拥有的东西,但综合工具在描述硬件时期望使用更有限的风格。如果他们可以处理您的代码,则可能会产生意外结果。