Nexys 4开发板VHDL实现UART整串发送无输出问题求助
Nexys 4开发板VHDL实现UART整串发送无输出问题求助
我正在学习VHDL和FPGA,手里有一块Digilent的Nexys 4开发板。之前我实现了按一次按钮发送一个字符的功能,现在想改成每次按按钮发送一整串字符串,但终端(我用Putty)完全没有输出。我怀疑问题出在顶层模块里,但不确定具体哪里错了,附上我的顶层模块代码:
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity UART_tx_top is port(btnC : in std_logic; clk : in std_logic; RsTx : out std_logic); end UART_tx_top; architecture behavioral of UART_tx_top is signal string_to_send : string := "Hello World!"; constant string_length : integer := 12; signal tx_index : integer := 0; type state_type is (TX_WAIT_BTN, TX_SEND_CHAR, TX_SEND_WAIT); signal state : state_type := TX_WAIT_BTN; signal uartRdy : std_logic; signal uartSend: std_logic; signal uartData: std_logic_vector (7 downto 0); signal initStr : std_logic_vector (7 downto 0) := x"41"; signal btnCclr : std_logic; signal btnC_prev : std_logic; component UART_tx_ctrl generic(baud : integer); port(send : in std_logic; clk : in std_logic; data : in std_logic_vector (7 downto 0); ready : out std_logic; uart_tx : out std_logic); end component; component debounce is port(clk : in std_logic; btn : in std_logic; btn_clr : out std_logic); end component; begin process(clk) begin if rising_edge(clk) then btnC_prev <= btnCclr; case state is when TX_WAIT_BTN => if btnC_prev = '0' and btnCclr = '1' then state <= TX_SEND_CHAR; end if; when TX_SEND_CHAR => if tx_index < string_length then uartData <= std_logic_vector(to_unsigned(character'pos(string_to_send(tx_index + 1)), 8)); --initStr <= std_logic_vector(unsigned(initStr) + 1); tx_index <= tx_index + 1; --state <= TX_SEND_WAIT; else uartData <= (others => '0'); tx_index <=0; state <= TX_WAIT_BTN; end if; when TX_SEND_WAIT => if uartRdy = '1' then state <= TX_WAIT_BTN; end if; end case; end if; end process; uartSend <= '1' when (state = TX_SEND_CHAR) else '0'; SX : UART_tx_ctrl generic map(baud => 19200) port map(send => uartSend, data => uartData, clk => clk, ready => uartRdy, uart_tx => RsTx); dbc : debounce port map(clk => clk, btn => btnC, btn_clr => btnCclr); end behavioral;
Hey,我仔细看了你的代码和问题,之前单字符发送正常,现在整串发没输出,问题大概率出在状态机的逻辑流程上,咱们来捋一捋:
问题分析
- 状态机流程断裂:你定义了
TX_SEND_WAIT状态,但把切换到这个状态的代码注释掉了(--state <= TX_SEND_WAIT;),导致状态一直卡在TX_SEND_CHAR里疯狂循环更新数据和索引,根本没给UART留出发送单个字符的时间——UART还没发完当前字符,下一个字符就覆盖了,终端自然收不到有效数据。 - UART触发信号错误:
uartSend被设置为只要在TX_SEND_CHAR状态就保持高电平,但大部分UART发送控制器的send信号需要的是单个时钟周期的脉冲触发,持续高电平可能无法正确启动多次发送,甚至让控制器进入异常状态。 - 缺少发送完成等待逻辑:你没有等待UART的
ready信号就连续切换字符,UART还没完成上一个字符的发送,新数据就进来了,完全没法正常工作。
修改方案
调整状态机流程,让每发送一个字符后,等待UART完成发送(uartRdy = '1')再发下一个,直到整串发完回到等待按钮状态,同时修正uartSend的触发逻辑为脉冲信号:
process(clk) begin if rising_edge(clk) then btnC_prev <= btnCclr; case state is when TX_WAIT_BTN => if btnC_prev = '0' and btnCclr = '1' then tx_index <= 0; -- 按下按钮后重置字符索引 state <= TX_SEND_CHAR; end if; when TX_SEND_CHAR => uartSend <= '1'; -- 生成一个时钟周期的发送触发脉冲 if tx_index < string_length then uartData <= std_logic_vector(to_unsigned(character'pos(string_to_send(tx_index + 1)), 8)); tx_index <= tx_index + 1; state <= TX_SEND_WAIT; -- 切换到等待发送完成状态 else tx_index <= 0; state <= TX_WAIT_BTN; -- 整串发送完成,回到等待按钮状态 end if; when TX_SEND_WAIT => uartSend <= '0'; -- 拉低触发信号 if uartRdy = '1' then -- 发送完成后判断是否还有剩余字符 if tx_index < string_length then state <= TX_SEND_CHAR; else state <= TX_WAIT_BTN; end if; end if; end case; end if; end process; -- 移除原来的uartSend赋值,改在状态机内处理 -- uartSend <= '1' when (state = TX_SEND_CHAR) else '0';
另外补充两个小提醒:
- 确保你的
UART_tx_ctrl模块中,ready信号会在发送完成后拉高,且能正确响应send的脉冲触发; - 你设置的
string_length = 12和索引tx_index + 1是对的,因为VHDL的string类型是从1开始索引的,刚好匹配"Hello World!"的字符数。
备注:内容来源于stack exchange,提问作者user1583007
相关产品推荐
相关产品推荐

