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

C# WinForms多SerialPort读取Zebra扫描器出现乱码问题求助

Zebra DS9308扫描器串口接收乱码问题排查与解决

问题描述

我在C# WinForms应用中使用SerialPort类读取通过RS232和Cadyce转换器连接的Zebra DS9308扫描器数据。用Docklight测试三个扫描器的COM端口时接收正常,但启动WinForms应用打开三个串口后,每个SerialPort都收到类似“????”的乱码,且触发了DataReceived事件。曾怀疑是同时打开三个串口导致,但相同逻辑在另一台PC上运行正常。已更换RS232线缆和Cadyce转换器,问题仍存在。请问该问题是否与CPU、RS232线缆或Cadyce转换器有关?

相关代码

private SerialPort serialPort;
private SerialPort serialPort2;
private SerialPort serialPort3;

private void FinalForm_Load(object sender, EventArgs e)
{
    comPortRead();

    serialPort.Open();
    serialPort2.Open();
    serialPort3.Open();

    serialPort.DataReceived += serialPort1_DataReceived;
    serialPort2.DataReceived += serialPort2_DataReceived;
    serialPort3.DataReceived += serialPort3_DataReceived;

    GetPlanWorkOrder();
}

private void comPortRead()
{
    try
    {
        string[] array = File.ReadAllLines("com_ports.txt");
        for (int i = 0; i < array.Length; i++)
        {
            serialPort = new SerialPort(array[0], 9600, Parity.None, 8, StopBits.One);
            serialPort2 = new SerialPort(array[1], 9600, Parity.None, 8, StopBits.One);
            serialPort3 = new SerialPort(array[2], 9600, Parity.None, 8, StopBits.One);
        }
    }
    catch (FileNotFoundException)
    {
        MessageBox.Show("COM port file not found");
    }
    catch (IOException ex2)
    {
        MessageBox.Show(ex2.ToString());
    }
}

private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    try
    {
        string text = serialPort.ReadLine()?.Trim();

        if (!string.IsNullOrEmpty(text))
        {
            string logPath = "C:\\TTPL PETROL TANK\\serialPortLog.txt";

            // Ensure the log file exists
            if (!File.Exists(logPath))
            {
                File.Create(logPath).Dispose();
            }

            // Log the received data for debugging
            File.AppendAllText(logPath, $"{DateTime.Now}: {text}{Environment.NewLine}");
        }

        // Use Invoke to update richTextBox1 from the UI thread
        Invoke((MethodInvoker)delegate
        {
            richTextBox1.AppendText($"DATA RECEIVED ON SCANNER 1: {text}{Environment.NewLine}");
        });
        if (button3.Text == "SET PLAN")
        {
            richTextBox1.Text = "PLEASE SET PLAN";
        }
        else
        {
            if (openScanner1)
            {
                if (!string.IsNullOrEmpty(text) && text.Length > 9)
                {
                    if (CheckPartNoAndWorkOrderExist(text, _WorkOrder, _LotNo) || Station1.Contains(text))
                    {
                        UpdateRichTextBox("THIS PART IS ALREADY SCANNED...!!!", Color.Red);
                    }
                    else
                    {
                        string subString = text.Substring(0, 8);
                        if (subString == _TankNo)
                        {
                            TankData.Enqueue(text);
                        }
                        Station1.Add(text);

                        ScannedPartsData.Enqueue(text);

                        Invoke((MethodInvoker)delegate
                        {
                            if (!coilValue1)
                            {
                                UpdateRichTextBox("PLEASE PLACE BOX AT SENSOR", Color.Red);
                            }
                            else
                            {
                                richTextBox1.Text = "";
                                Thread.Sleep(200);
                                CompareReceivedData(subString);
                            }
                        });
                    }
                }
                text = "";
            }
        }
        serialPort.DiscardInBuffer();
    }
    catch (Exception ex)
    {
        Invoke((MethodInvoker)delegate
        {
            richTextBox1.AppendText(ex.ToString());
        });
    }
}

问题分析与排查方向

1. 编码不匹配(最可能原因)

SerialPort默认使用ASCII编码,但Zebra DS9308扫描器可能配置为UTF-8、ISO-8859-1或其他编码发送数据。Docklight会自动识别编码,但代码未指定,导致字符解析错误出现乱码。

2. 串口事件绑定顺序错误

代码先打开串口再绑定DataReceived事件,可能导致串口打开后触发的第一次事件无法被捕获,或部分数据解析异常。

3. 串口资源冲突(与CPU/主板相关)

另一台PC正常但当前PC异常,可能是当前PC的串口控制器存在中断请求(IRQ)冲突,或主板芯片组对多串口的支持存在兼容性问题,导致数据传输丢包或解析错误。

4. 串口参数不匹配

代码硬编码了波特率、校验位等参数,但扫描器的实际配置可能和代码设置不一致。Docklight会自动匹配参数,而代码固定值可能导致参数不匹配。

5. 代码逻辑缺陷

  • comPortRead方法中的循环完全冗余,每次循环都会重复创建三个SerialPort实例;
  • DataReceived事件中调用Thread.Sleep(200)会阻塞UI线程,导致数据处理延迟;
  • DiscardInBuffer在处理完数据后调用,若ReadLine未读完缓冲区数据,会直接丢弃剩余内容,引发后续解析异常。

解决建议

1. 指定SerialPort编码

创建SerialPort实例时明确设置编码,根据扫描器配置调整:

serialPort = new SerialPort(array[0], 9600, Parity.None, 8, StopBits.One)
{
    Encoding = Encoding.UTF8 // 或Encoding.GetEncoding("ISO-8859-1")
};

2. 调整事件绑定顺序

先绑定DataReceived事件,再打开串口:

// 先绑定事件
serialPort.DataReceived += serialPort1_DataReceived;
serialPort2.DataReceived += serialPort2_DataReceived;
serialPort3.DataReceived += serialPort3_DataReceived;

// 再打开串口
serialPort.Open();
serialPort2.Open();
serialPort3.Open();

3. 优化comPortRead方法

去掉冗余循环,增加配置校验:

private void comPortRead()
{
    try
    {
        string[] array = File.ReadAllLines("com_ports.txt");
        if (array.Length < 3)
        {
            MessageBox.Show("COM port配置文件缺少足够端口信息");
            return;
        }
        serialPort = new SerialPort(array[0], 9600, Parity.None, 8, StopBits.One) { Encoding = Encoding.UTF8 };
        serialPort2 = new SerialPort(array[1], 9600, Parity.None, 8, StopBits.One) { Encoding = Encoding.UTF8 };
        serialPort3 = new SerialPort(array[2], 9600, Parity.None, 8, StopBits.One) { Encoding = Encoding.UTF8 };
    }
    catch (FileNotFoundException)
    {
        MessageBox.Show("COM port file not found");
    }
    catch (IOException ex2)
    {
        MessageBox.Show(ex2.ToString());
    }
}

4. 修复UI线程阻塞问题

移除Thread.Sleep(200),改用异步延迟处理:

// 替换原Sleep代码
Task.Delay(200).ContinueWith(_ => 
{
    Invoke((MethodInvoker)delegate 
    {
        CompareReceivedData(subString);
    });
});

5. 排查硬件/驱动问题

  • 打开设备管理器查看串口IRQ是否冲突,如有尝试调整或更换串口接口;
  • 更新主板芯片组驱动和串口驱动;
  • 尝试使用PCIe串口扩展卡替代主板自带串口,排除兼容性问题。

6. 验证扫描器串口参数

用Docklight查看扫描器发送数据的实际参数(波特率、校验位、流控制等),确保代码设置和扫描器完全一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 18:24:54