【问题标题】:UART RS-232 TransmitterUART RS-232 发送器
【发布时间】:2025-12-11 18:20:04
【问题描述】:

我正在用 VHDL 实现 RS-232 发射器。 我想获取使用 PS-2 键盘输入的数据并将其显示在串行端口终端中。 我有工作的接收器,我知道除了这个发射器之外,其余的元素都在工作。

我写了以下代码:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity uart is
generic (
    CLK_FREQ    : integer := 50;        
    SER_FREQ    : integer := 115200     
);
port (
    clk         : in    std_logic;      
    rst         : in    std_logic;      
    tx          : out   std_logic;      

    tx_req      : in    std_logic;                                          
    tx_data     : in    std_logic_vector(7 downto 0);   
    rx_ready    : out   std_logic;                      
    rx_data     : out   std_logic_vector(7 downto 0)    
);
end uart;

architecture Behavioral of uart is


    constant UART_IDLE  :   std_logic := '1';
    constant UART_START :   std_logic := '0';
    constant RST_LVL       :    std_logic := '1';


    type state is (idle,data,stop);         

    signal tx_state         :   state;
    signal tx_next_state    :  state;
    signal tx_clk_en        :   std_logic;
    signal tx_data_tmp  :   std_logic_vector(7 downto 0);   
    signal tx_data_cnt  :   std_logic_vector(2 downto 0);   

begin
--
    tx_clk_gen:process(clk)
        variable counter    :   integer range 0 to conv_integer((CLK_FREQ*1_000_000)/SER_FREQ-1);
    begin
        if clk'event and clk = '1' then
            if counter = (CLK_FREQ*1_000_000)/SER_FREQ-1 then
                tx_clk_en   <=  '1';
                counter     :=  0;
            else
                tx_clk_en   <=  '0';
                counter     :=  counter + 1;
            end if;
        end if;
    end process;

    tx_process:process(clk, tx_state)
    begin
        if tx_clk_en = '0' then
            tx_next_state <= tx_state;
            case tx_state is
                when idle =>
                    if tx_req = '0' then
                        tx <= '0';
                        tx_data_tmp <= tx_data;
                        tx_next_state <= data;
                        tx_data_cnt <= (others=>'1');
                    else
                        tx <= '1';
                        tx_next_state <= idle;
                        tx_data_cnt <= (others=>'1');
                        tx_data_tmp <= (others=>'1');
                    end if;
                when data =>
                    tx <= tx_data_tmp(0);
                    if tx_data_cnt = 0 then
                        tx_next_state <= stop;
                        tx_data_cnt <= (others=>'1');
                        tx_data_tmp <=(others=>'1');
                    else
                        tx_next_state <= data;
                        tx_data_tmp <= '0' & tx_data_tmp(7 downto 1);
                        tx_data_cnt <= tx_data_cnt - 1;
                    end if;
                when stop =>
                    tx <= '1';
                    tx_next_state <= idle;
                    tx_data_cnt <= (others=>'1');
                    tx_data_tmp <=(others=>'1');
            end case;
        end if;
    end process;

    tx_next:process(tx_next_state)
    begin
        tx_state <= tx_next_state;
    end process;

end Behavioral;

在实施设计期间有一些警告:

One or more signals are missing in the process sensitivity list. To enable synthesis of FPGA/CPLD hardware, XST will assume that all necessary signals are present in the sensitivity list. Please note that the result of the synthesis may differ from the initial design specification. The missing signals are:<tx_clk_en>, <tx_req>, <tx_data>

Found 3-bit latch for signal <tx_data_cnt>. Latches may be generated from incomplete case or if statements. We do not recommend the use of latches in FPGA/CPLD designs, as they may lead to timing problems.

Found 8-bit latch for signal <tx_data_tmp>. Latches may be generated from incomplete case or if statements. We do not recommend the use of latches in FPGA/CPLD designs, as they may lead to timing problems.

Found 3-bit latch for signal <tx_next_state>. Latches may be generated from incomplete case or if statements. We do not recommend the use of latches in FPGA/CPLD designs, as they may lead to timing problems.

Found 1-bit latch for signal <tx>. Latches may be generated from incomplete case or if statements. We do not recommend the use of latches in FPGA/CPLD designs, as they may lead to timing problems. 

请帮帮我。 提前致谢。

编辑:

我根据您的提示调整了我的代码,现在没有任何警告,但我仍然不确定它是否能正常工作。任何人都可以在硬件上检查它吗?或者只是评论新版本。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity uart is
generic (
    CLK_FREQ    : integer := 50;        
    SER_FREQ    : integer := 115200     
);
port (
    clk         : in    std_logic;      
    rst         : in    std_logic;              
    tx          : out   std_logic;      
    tx_req      : in    std_logic;                                      
    tx_data     : in    std_logic_vector(7 downto 0);   
);
end uart;

architecture Behavioral of uart is


    constant UART_IDLE  :   std_logic := '1';
    constant UART_START :   std_logic := '0';
    constant RST_LVL       :    std_logic := '1';

    type state is (idle, active);           

    signal tx_state         :   state;
    signal tx_next_state    :  state;
    signal tx_clk_en        :   std_logic;
    signal tx_data_packet   :   std_logic_vector(9 downto 0);   
    signal tx_data_cnt  :   std_logic_vector(3 downto 0);   

begin
--
    tx_clk_gen:process(clk)
        variable counter    :   integer range 0 to conv_integer((CLK_FREQ*1_000_000)/SER_FREQ-1);
    begin
        if clk'event and clk = '1' then
            if counter = (CLK_FREQ*1_000_000)/SER_FREQ-1 then
                tx_clk_en   <=  '1';
                counter     :=  0;
            else
                tx_clk_en   <=  '0';
                counter     :=  counter + 1;
            end if;
        end if;
    end process;

    tx_reset:process(clk)
    begin
        if clk'event and clk = '1' then
            if rst = '0' then
                tx_state <= idle;
            else
                tx_state <= tx_next_state;
            end if;
        end if;
    end process;

    tx_process:process(clk, tx_state, tx_req, tx_clk_en)
    begin
        if clk'event and clk = '1' then
            if tx_clk_en = '0' then
                tx_next_state <= tx_state;
                case tx_state is
                    when idle =>
                        if tx_req = '0' then
                            tx_data_packet(9) <= '0';
                            tx_data_packet(8 downto 1) <= tx_data;
                            tx_data_packet(0) <= '1';
                            tx_next_state <= active;
                            tx_data_cnt <= "1010";
                        else
                            tx <= '1';
                            tx_next_state <= idle;
                            tx_data_cnt <= (others=>'1');
                            tx_data_packet <= (others=>'1');
                        end if;
                    when active =>
                        tx <= tx_data_packet(0);
                        if tx_data_cnt = 0 then
                            tx_next_state <= idle;
                            tx_data_cnt <= (others=>'1');
                            tx_data_packet <=(others=>'1');
                        else
                            tx_next_state <= active;
                            tx_data_packet <= '0' & tx_data_packet(9 downto 1);
                            tx_data_cnt <= tx_data_cnt - 1;
                        end if;
                end case;
            else
                tx <= '1';
                tx_data_packet <= (others=>'1');
                tx_data_cnt <= (others=>'1');
            end if;
        end if;
    end process;

end Behavioral;
# #

大家好! 我现在有以下代码,我在硬件上进行了测试,但它仍然无法正常工作。你有什么想法可能是错的吗?

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity uart is
generic (
    CLK_FREQ    : integer := 50;        
    SER_FREQ    : integer := 115200     
);
port (
    clk         : in    std_logic;      
    rst         : in    std_logic;      
    rx          : in    std_logic;      
    tx          : out   std_logic;      

    tx_req      : in    std_logic;                                          
    tx_data     : in    std_logic_vector(7 downto 0);   
);
end uart;

architecture Behavioral of uart is


    constant UART_IDLE  :   std_logic := '1';
    constant UART_START :   std_logic := '0';
    constant RST_LVL       :    std_logic := '1';


    type state is (idle, active);           

    signal tx_busy      :std_logic;
    signal tx_state         :   state;
    signal tx_next_state    :  state;
    signal tx_clk_en        :   std_logic;
    signal tx_data_packet   :   std_logic_vector(8 downto 0);   
    signal tx_data_cnt  :   std_logic_vector(3 downto 0);   

begin
--
    tx_clk_gen:process(clk, tx_req)
        variable counter    :   integer range 0 to conv_integer((CLK_FREQ*1_000_000)/SER_FREQ-1);
    begin
        if rising_edge(clk) then
            if tx_busy = '1' then
                if counter = (CLK_FREQ*1_000_000)/SER_FREQ-1 then
                    tx_clk_en   <=  '1';
                    counter     :=  0;
                else
                    tx_clk_en   <=  '0';
                    counter     :=  counter + 1;
                end if;
            end if;
        end if;
    end process;

    tx_reset:process(clk)
    begin
        if rising_edge(clk) then
            if rst = '0' then
                tx_state <= idle;
            else
                tx_state <= tx_next_state;
            end if;
        end if;
    end process;

    tx_process:process(clk, tx_state, tx_req, tx_clk_en)
    begin
        if rising_edge(clk) then
                case tx_state is
                    when idle =>
                        if tx_req = '1' then
                            tx <= '0';
                            tx_data_packet(7 downto 0) <= tx_data;
                            tx_data_packet(8) <= '1';
                            tx_next_state <= active;
                            tx_data_cnt <= "1010";
                            tx_busy <= '1';
                        else
                            tx <= '1';
                            tx_next_state <= idle;
                            tx_data_cnt <= (others=>'1');
                            tx_data_packet <= (others=>'1');
                        end if;
                    when active =>
                        if tx_clk_en = '1' then
                            tx <= tx_data_packet(0);
                            if tx_data_cnt = 0 then
                                tx_next_state <= idle;
                                tx_data_cnt <= (others=>'1');
                                tx_data_packet <=(others=>'1');
                                tx <= '1';
                                tx_busy <= '0';
                            else
                                tx_next_state <= active;
                                tx_data_packet <= '1' & tx_data_packet(8 downto 1);
                                tx_data_cnt <= tx_data_cnt - 1;
                            end if;
                        end if;
                end case;
        end if;
    end process;

【问题讨论】:

  • 注意:如果在传输一个 8 位字节时,它可能会简化事情,而不是“前置”一个起始位 0 并附加一个停止位 1,形成一个 10 位“数据”来发送,从而减少状态到 2 个条件:活跃,不活跃。

标签: serial-port vhdl fpga


【解决方案1】:

锁存器表示您打算为时钟提供时钟的非时钟进程,或具有不完整覆盖的组合逻辑(例如,if 没有else 部分的语句)。

简单地看一下这段代码,我可以看到其中的两个。

编辑回复:编辑:然后编写一个测试台并模拟它。它符合您的预期吗?

【讨论】:

    【解决方案2】:

    猜你在tx_process 的最外层缺少if clk'event and clk = '1' thenrising_edge(clk)

    tx_next 进程看起来也很奇怪;它实际上并没有像现在写的那样做任何事情(除了增量延迟)。

    【讨论】: