You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于RS232的PC与Altera板卡通信问题:多字符传输异常

问题:RS232双字符传输异常,单字符正常

我正在做一个学校项目,需要通过RS232线缆,用VS中的C#代码向Altera板卡传输ASCII字符。单字符(如'A')传输正常,但传输双字符(如"AB")时接收异常,LED亮灭不符合预期。以下是我的VHDL接收代码和C#发送代码,求解决办法。


VHDL接收代码

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity UART_RX is
-- clockls per bit = 50Mhz/9600baudrate
generic(
        gClocks_per_Bit : integer := 5208
        
       );
        
port(
      iClk       : in std_logic;
      iReset     : in std_logic;
      iRX        : in std_logic:='0';
        led1,led2  : out std_logic:='0';
      oTX        : out std_logic_vector (7 downto 0)
      
    );
end UART_RX;

architecture Behavioral of UART_RX  is 

type uart_rx_type is (idle,start,data,stop);
signal sNext_state : uart_rx_type  := idle;

signal sClock_counter : integer range 0 to gClocks_per_Bit := 0;
signal sIndex : integer range 0 to 15 := 0;
signal sTemp : std_logic_vector (15 downto 0);


signal receiver1, receiver2 : std_logic_vector (7 downto 0);
signal oTX_1 : std_logic_vector (7 downto 0);
begin
    process(iClk,iReset)
        begin 
            if(iReset = '0') then
                sIndex <= 0;
                sClock_counter <= 0;        
            elsif(rising_edge(iClk)) then  
                case sNext_state is
                    when idle =>                    
                        sClock_counter <= 0;
                        sIndex <= 0;
                        if(iRX = '0') then
                            sNext_state <= start;
                        elsif(iRX = '1') then
                            sNext_state <= idle;
                        end if;
                    
                    when start => 
                        if(sClock_counter < gClocks_per_Bit) then
                            sClock_counter <= sClock_counter  + 1;
                                if(sClock_counter = gClocks_per_Bit/2 AND iRX ='0') then
                                    sNext_state <= start;
                                elsif(sClock_counter = gClocks_per_Bit/2 AND iRX ='1') then
                                    sClock_counter <= 0;
                                    sNext_state <= idle;
                                end if;
                            sNext_state <= start;
                        else
                            sClock_counter <= 0;
                            sNext_state <= data;
                        end if;
                    
                    when data => 
                        if(sClock_counter < gClocks_per_Bit) then
                            sClock_counter <= sClock_counter  + 1;
                            sNext_state <= data;
                            if(sClock_counter = gClocks_per_Bit/2) then
                                sTemp(sindex)<= iRX;
                            end if;
                        else
                            sClock_counter <= 0;
                                if(sIndex < 15) then
                                    sIndex <= sIndex + 1;
                                    sNext_state <= data;
                                else
                                    sIndex <= 0;
                                    sNext_state <= stop;
                                end if;
                        end if;
                    
                    when stop =>
                        if(sClock_counter = gClocks_per_Bit / 2) then
                            sClock_counter <= 0;
                            sNext_state <= idle;
                        elsif(sClock_counter  < gClocks_per_Bit) then
                            sClock_counter <= sClock_counter + 1;
                        end if;
                          when others => null;
                end case;
                end if;
            end process;
            receiver1<=sTemp(7 downto 0);
            receiver2<=sTemp(15 downto 8);
--          oTX <= sTemp;
process(receiver1,receiver2,iReset)
begin
    if iReset = '0' then
        led2<='0';
        led1<='0';
            
    elsif receiver1 = "01000001" then -- A (led 1 on)
        led2 <= '0';
        led1 <= '1';
        
        
    elsif receiver1 = "01000010" then -- B
        led2 <= '1';
        led1 <= '0';
    elsif receiver1 = "01000011" then -- C
        led2 <= '0';
        led1 <= '0';
    elsif sTemp = "0100000101000010" then -- AB
        led2 <= '1';
        led1 <= '1';
    
    else -- What Ever You Write Turns Off/On Leds.
    null;
    
    end if;
end process;
oTX <= sTemp(7 downto 0);
end Behavioral ;

C#发送代码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Ports;
using System.Threading;

namespace COMPORT
{
    public partial class Form1 : Form
    {
        string dataOUT;
        public Form1()
        {
            InitializeComponent();
        }

        private void comboBox5_SelectedIndexChanged(object sender, EventArgs e)
        {

        }

        private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                serialPort1.PortName = cBoxCOMPORT.Text;
                serialPort1.BaudRate = Convert.ToInt32(CBoxBaudRate.Text);
                serialPort1.DataBits = Convert.ToInt32(cBoxDataBits.Text);
                serialPort1.StopBits = (StopBits)Enum.Parse(typeof(StopBits), cBoxStopBits.Text);
                serialPort1.Parity = (Parity)Enum.Parse(typeof(Parity), cBoxParityBits.Text);

                serialPort1.Open();
                progressBar1.Value = 100;
            }
            
            catch (Exception err)
            {
                MessageBox.Show(err.Message,"Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void btnClose_Click(object sender, EventArgs e)
        {
            if(serialPort1.IsOpen)
            {
                serialPort1.Close();
                progressBar1.Value = 0;
            }

        }

        private void Form1_Load(object sender, EventArgs e)
        {
            string[] ports = SerialPort.GetPortNames();
            cBoxCOMPORT.Items.AddRange(ports);

        }

        private void btnSendData_Click(object sender, EventArgs e)
        {
            if(serialPort1.IsOpen)
            {
                dataOUT = tBoxDataOut.Text;
                //dataOUT = ConvertToHex(dataOUT);
                //dataOUT = hex2binary(dataOUT);
                serialPort1.Write(dataOUT);
                Thread.Sleep((int)TimeSpan.FromSeconds(2).TotalMilliseconds);
                MessageBox.Show(dataOUT);

            }

        }

        private void tBoxDataOut_TextChanged(object sender, EventArgs e)
        {

        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            this.Text = DateTime.Now.ToString();
        }

        //public static string ConvertToHex(string asciiString)
        //{
        //    string bin = "";
        //    foreach (char c in asciiString)
        //    {
        //        int tmp = c;
        //        bin += String.Format("{0:x2}", (uint)System.Convert.ToUInt32(tmp.ToString()));
        //    }
        //    return bin;
        //}

        //private string hex2binary(string hexvalue)
        //{
        //    string binaryval = "";
        //    binaryval = Convert.ToString(Convert.ToInt32(hexvalue, 16), 2);
        //    return binaryval;
        //}
    }
}

问题原因及修复方案

核心问题

  1. UART帧格式误解:你的VHDL代码试图一次性接收16位连续数据,但标准UART中每个字符是独立的帧(起始位+8数据位+停止位)。发送"AB"实际是两个独立帧,而非连续16位数据流,导致sTemp数据混乱。
  2. 判断优先级错误:LED控制逻辑中,单字符判断优先级高于双字符,即使接收到"AB",也会先触发单字符的LED逻辑,永远不会执行双字符分支。

修复方案

方案1:修正VHDL接收逻辑(推荐)

修改状态机,每次接收一个完整字节,存储到缓冲区,累计两个字节后再进行判断:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity UART_RX is
generic(
        gClocks_per_Bit : integer := 5208
       );
port(
      iClk       : in std_logic;
      iReset     : in std_logic;
      iRX        : in std_logic:='0';
      led1,led2  : out std_logic:='0';
      oTX        : out std_logic_vector (7 downto 0)
    );
end UART_RX;

architecture Behavioral of UART_RX  is 
type uart_rx_type is (idle,start,data,stop);
signal sNext_state : uart_rx_type  := idle;

signal sClock_counter : integer range 0 to gClocks_per_Bit := 0;
signal sIndex : integer range 0 to 7 := 0;
signal sTemp_byte : std_logic_vector (7 downto 0);
signal rx_buffer : std_logic_vector(15 downto 0);
signal byte_count : integer range 0 to 1 := 0;
signal rx_done : std_logic := '0';

begin
    process(iClk,iReset)
        begin 
            if(iReset = '0') then
                sIndex <= 0;
                sClock_counter <= 0;
                byte_count <= 0;
                rx_done <= '0';
                rx_buffer <= (others => '0');
            elsif(rising_edge(iClk)) then  
                rx_done <= '0';
                case sNext_state is
                    when idle =>                    
                        sClock_counter <= 0;
                        sIndex <= 0;
                        if(iRX = '0') then
                            sNext_state <= start;
                        else
                            sNext_state <= idle;
                        end if;
                    
                    when start => 
                        if(sClock_counter < gClocks_per_Bit) then
                            sClock_counter <= sClock_counter + 1;
                            if(sClock_counter = gClocks_per_Bit/2 AND iRX = '1') then
                                sClock_counter <= 0;
                                sNext_state <= idle;
                            end if;
                        else
                            sClock_counter <= 0;
                            sNext_state <= data;
                        end if;
                    
                    when data => 
                        if(sClock_counter < gClocks_per_Bit) then
                            sClock_counter <= sClock_counter + 1;
                            if(sClock_counter = gClocks_per_Bit/2) then
                                sTemp_byte(sindex) <= iRX;
                            end if;
                        else
                            sClock_counter <= 0;
                            if(sIndex < 7) then
                                sIndex <= sIndex + 1;
                                sNext_state <= data;
                            else
                                sIndex <= 0;
                                sNext_state <= stop;
                            end if;
                        end if;
                    
                    when stop =>
                        if(sClock_counter < gClocks_per_Bit) then
                            sClock_counter <= sClock_counter + 1;
                            if(sClock_counter = gClocks_per_Bit) then
                                if(byte_count = 0) then
                                    rx_buffer(7 downto 0) <= sTemp_byte;
                                    byte_count <= 1;
                                else
                                    rx_buffer(15 downto 8) <= sTemp_byte;
                                    byte_count <= 0;
                                    rx_done <= '1';
                                end if;
                                sNext_state <= idle;
                            end if;
                        end if;
                    when others => null;
                end case;
            end if;
        end process;

process(rx_done, rx_buffer, iReset)
begin
    if iReset = '0' then
        led2 <= '0';
        led1 <= '0';
    elsif rx_done = '1' then
        if rx_buffer = "0100001001000001" then -- 先接A(低字节),后接B(高字节)
            led1 <= '1';
            led2 <= '1';
        elsif rx_buffer(7 downto 0) = "01000001" then
            led1 <= '1';
            led2 <= '0';
        elsif rx_buffer(7 downto 0) = "01000010" then
            led1 <= '0';
            led2 <= '1';
        elsif rx_buffer(7 downto 0) = "01000011" then
            led1 <= '0';
            led2 <= '0';
        end if;
    end if;
end process;

oTX <= rx_buffer(7 downto 0);
end Behavioral ;

方案2:调整LED判断优先级(临时修复)

将双字符判断放在单字符之前,确保优先触发:

process(receiver1,receiver2,iReset)
begin
    if iReset = '0' then
        led2<='0';
        led1<='0';
    elsif sTemp = "0100000101000010" then -- AB 判断移到最前面
        led2 <= '1';
        led1 <= '1';
    elsif receiver1 = "01000001" then -- A
        led2 <= '0';
        led1 <= '1';
    elsif receiver1 = "01000010" then -- B
        led2 <= '1';
        led1 <= '0';
    elsif receiver1 = "01000011" then -- C
        led2 <= '0';
        led1 <= '0';
    else
        null;
    end if;
end process;

C#代码验证

你的C#代码无需修改,serialPort1.Write(dataOUT)会自动将ASCII字符转换为标准UART帧发送。


内容的提问来源于stack exchange,提问作者Omer DT8

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 04:27:23