【问题标题】:I/O exception error when using serialport.open()使用 serialport.open() 时出现 I/O 异常错误
【发布时间】:2013-01-30 20:56:17
【问题描述】:

最终更新

这一直是我们的固件。在某种程度上令人尴尬,但我很高兴我们可以继续前进,我可以推迟一天学习 Java。我的答案如下。

更新

所以我或多或少地放弃了这一点。我认为这是一个归结为 API 的错误,但我既没有时间、资源也没有技能来深入了解它。我认为存在一些 Windows 只是竖起中指的硬件。我已经下载了 Eclipse,切换到 Java 并尝试看看是否可行。如果没有,你会在这里看到我。但是,我绝对很想解决这个问题,所以如果有人有时间或有兴趣深入研究这个问题,我很想看看你想出了什么。显然我会不时回来这里查看。请确保您在您的 cmets 中“@”我,以便我收到提醒。


原帖

我知道还有其他一些人在处理这个问题,但我希望有人可以帮助我。我正在尝试连接到 COM port,但是当我尝试使用 serialport.Open() 命令时出现 I/O 异常:

System.IO.IOException: The parameter is incorrect.

   at System.IO.Ports.InternalResources.WinIOError(Int32 errorCode, String str)
   at System.IO.Ports.InternalResources.WinIOError()
   at System.IO.Ports.SerialStream.InitializeDCB(Int32 baudRate, Parity parity, Int32 dataBits, StopBits stopBits, Boolean discardNull)
   at System.IO.Ports.SerialStream..ctor(String portName, Int32 baudRate, Parity parity, Int32 dataBits, StopBits stopBits, Int32 readTimeout, Int32 writeTimeout, Handshake handshake, Boolean dtrEnable, Boolean rtsEnable, Boolean discardNull, Byte parityReplace)
   at System.IO.Ports.SerialPort.Open()
   at *programtitlehere.cs*:line 90

我正在使用 Stellaris LM4F232 来模拟 COM 端口。我可以使用 Termite(终端程序)打开、访问并获得良好的结果,但是每当我尝试使用 Visual Studio 时,它甚至都无法连接,并且出现此错误。现在我什至不知道这个错误是什么意思,尽管尝试在其他地方阅读,我仍然感到迷茫。

谁能向我解释这里发生了什么,也许我可以开始尝试解决这个问题?我可以包含更多代码,但老实说那里没有多少;串口设备的所有属性都正常,只有这个设备才会出现这种情况(我可以使用MSP430,细节相同)。

我的代码如下所示,供希望查看的人使用(注意这只是一个“沙箱”,不是实际程序,但症状是相同的):

try
{
    serialPort1.PortName = "COM5";
    serialPort1.Open();
    if (serialPort1.IsOpen == true)
    {
        textBox1.Text = "CONNECTED";
    }
    else
    {
        textBox1.Text = "NOT CONNECTED";
    }
}
catch (Exception ex)
{
    MessageBox.Show("Error: " + ex.ToString(), "ERROR");
}

其他设置是通过属性管理器完成的(唯一的区别是波特设置为 230400;所有其他设置都是默认值)。 我可以用这个(一个 MSP430)打开 COM4,从所有意图和目的来看,它都是一个相同的设备。我可以用 Termite 打开 COM5,所以我知道连接良好)。不,我不想同时打开它们。如果您需要更多信息,请告诉我,我可以发布更多信息。

编辑:我正在尝试解决这个问题的第三天,但仍然没有运气。我真的不明白为什么我可以通过终端程序而不是我自己的程序访问这个 COM 端口,而在我所见的情况下,绝对没有区别。是否有可以“检查” COM 端口以查看其属性的程序(我的意思是 Windows 管理器除外)?在我弄清楚这一点之前,我感到非常沮丧,并且在我的项目中处于停滞状态......

EDIT2:我找到了一个明显的解决方法,但我还没有让它工作here。现在我得到了一些不同的 I/O 错误,但至少它是运动(不确定它是否是进度)。我还了解到这是一个 .NET 错误,自 2.0 以来就存在。我仍然希望得到任何帮助,但如果我弄清楚了,我会报告回来。 Zach 的代码(上面链接的解决方法)如下所示:

using System;
using System.IO;
using System.IO.Ports;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.Win32.SafeHandles;

namespace SerialPortTester
{
    public class SerialPortFixer : IDisposable
    {
        public static void Execute(string portName)
        {
            using (new SerialPortFixer(portName))
            {
            }
        }

        #region IDisposable Members

        public void Dispose()
        {
            if (m_Handle != null)
            {
                m_Handle.Close();
                m_Handle = null;
            }
        }

        #endregion

        #region Implementation

        private const int DcbFlagAbortOnError = 14;
        private const int CommStateRetries = 10;
        private SafeFileHandle m_Handle;

        private SerialPortFixer(string portName)
        {
            const int dwFlagsAndAttributes = 0x40000000;
            const int dwAccess = unchecked((int) 0xC0000000);

            if ((portName == null) || !portName.StartsWith("COM", StringComparison.OrdinalIgnoreCase))
            {
                throw new ArgumentException("Invalid Serial Port", "portName");
            }
            SafeFileHandle hFile = CreateFile(@"\\.\" + portName, dwAccess, 0, IntPtr.Zero, 3, dwFlagsAndAttributes,
                                              IntPtr.Zero);
            if (hFile.IsInvalid)
            {
                WinIoError();
            }
            try
            {
                int fileType = GetFileType(hFile);
                if ((fileType != 2) && (fileType != 0))
                {
                     throw new ArgumentException("Invalid Serial Port", "portName");
                }
                m_Handle = hFile;
                InitializeDcb();
            }
            catch
            {
                hFile.Close();
                m_Handle = null;
                throw;
            }
        }

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern int FormatMessage(int dwFlags, HandleRef lpSource, int dwMessageId, int dwLanguageId,
                                                StringBuilder lpBuffer, int nSize, IntPtr arguments);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern bool GetCommState(SafeFileHandle hFile, ref Dcb lpDcb);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern bool SetCommState(SafeFileHandle hFile, ref Dcb lpDcb);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern bool ClearCommError(SafeFileHandle hFile, ref int lpErrors, ref Comstat lpStat);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern SafeFileHandle CreateFile(string lpFileName, int dwDesiredAccess, int dwShareMode,
                                                        IntPtr securityAttrs, int dwCreationDisposition,
                                                        int dwFlagsAndAttributes, IntPtr hTemplateFile);

        [DllImport("kernel32.dll", SetLastError = true)]
        private static extern int GetFileType(SafeFileHandle hFile);

        private void InitializeDcb()
        {
            Dcb dcb = new Dcb();
            GetCommStateNative(ref dcb);
            dcb.Flags &= ~(1u << DcbFlagAbortOnError);
            SetCommStateNative(ref dcb);
        }

        private static string GetMessage(int errorCode)
        {
            StringBuilder lpBuffer = new StringBuilder(0x200);
            if (
                FormatMessage(0x3200, new HandleRef(null, IntPtr.Zero), errorCode, 0, lpBuffer, lpBuffer.Capacity,
                              IntPtr.Zero) != 0)
            {
                return lpBuffer.ToString();
            }
            return "Unknown Error";
        }

        private static int MakeHrFromErrorCode(int errorCode)
        {
            return (int) (0x80070000 | (uint) errorCode);
        }

        private static void WinIoError()
        {
            int errorCode = Marshal.GetLastWin32Error();
            throw new IOException(GetMessage(errorCode), MakeHrFromErrorCode(errorCode));
        }

        private void GetCommStateNative(ref Dcb lpDcb)
        {
            int commErrors = 0;
            Comstat comStat = new Comstat();

            for (int i = 0; i < CommStateRetries; i++)
            {
                if (!ClearCommError(m_Handle, ref commErrors, ref comStat))
                {
                     WinIoError();
                }
                if (GetCommState(m_Handle, ref lpDcb))
                {
                     break;
                }
                if (i == CommStateRetries - 1)
                {
                     WinIoError();
                }
            }
        }

        private void SetCommStateNative(ref Dcb lpDcb)
        {
            int commErrors = 0;
            Comstat comStat = new Comstat();

            for (int i = 0; i < CommStateRetries; i++)
            {
                 if (!ClearCommError(m_Handle, ref commErrors, ref comStat))
                 {
                     WinIoError();
                 }
                 if (SetCommState(m_Handle, ref lpDcb))
                 {
                     break;
                 }
                 if (i == CommStateRetries - 1)
                 {
                     WinIoError();
                 }
            }
        }

        #region Nested type: COMSTAT

        [StructLayout(LayoutKind.Sequential)]
        private struct Comstat
        {
            public readonly uint Flags;
            public readonly uint cbInQue;
            public readonly uint cbOutQue;
        }

        #endregion

        #region Nested type: DCB

        [StructLayout(LayoutKind.Sequential)]
        private struct Dcb
        {
            public readonly uint DCBlength;
            public readonly uint BaudRate;
            public uint Flags;
            public readonly ushort wReserved;
            public readonly ushort XonLim;
            public readonly ushort XoffLim;
            public readonly byte ByteSize;
            public readonly byte Parity;
            public readonly byte StopBits;
            public readonly byte XonChar;
            public readonly byte XoffChar;
            public readonly byte ErrorChar;
            public readonly byte EofChar;
            public readonly byte EvtChar;
            public readonly ushort wReserved1;
        }

        #endregion

        #endregion
    }

    internal class Program
    {
        private static void Main(string[] args)
        {
            SerialPortFixer.Execute("COM1");
            using (SerialPort port = new SerialPort("COM1"))
            {
                port.Write("test");
            }
        }
    }
}

EDIT3:第 6 天:我仍在努力解决这个问题。我的饮水量很低,但我仍然在努力。我觉得帮助肯定就在眼前。谁找到了这本日记,就把我的遗体带回加拿大并找到妮可。告诉她我爱她。

但是说真的,我不知道是什么导致了这个问题。我想知道它是否纯粹在嵌入式方面;可能是因为它是USB On-The-Go (OTG),或者因为该设备也能够成为主机。有没有人遇到过这个问题?但它并没有解释为什么我可以使用 Termite(一个终端程序,对于那些刚刚加入我们的观众)。我一直在尝试找到一个开源终端程序,它 a) 可以工作并且 b) 参见 a)。像往常一样,如果我在这里发现这个问题,我会报告回来,因为我现在发现了无数论坛,听起来人们可以追溯到 2006 年。

EDIT4:按照给出的建议,我下载了一个端口监控软件应用程序(我得到了Eltima Serial Port Monitor),它看起来确实是一个波特问题:

但奇怪的是,无论我设置什么波特,它仍然失败。也有人可以解释上/下的意思吗?我试着用谷歌搜索它,但关键字太笼统了。像往常一样,我会继续报告任何变化。

另外,作为记录,我可以使用 Eltima 以 115200 的波特率进行连接(与 Termite 相同)。不幸的是,这在 Visual Studio 中不起作用。

EDIT5:我们的情节出现了意外的转折。我正在监视当 Termite 连接到有问题的 COM 端口和 BLAM 时会发生什么! Termite 会抛出与我的程序完全相同的错误,但它忽略它。天才,对吧?马虎,但它的工作原理。现在我需要学习如何忽略 IOExceptions。等我弄明白了再汇报。

EDIT6:事实证明这是一个波特率问题,但它更深入。我一直在使用 Eltima 串口监控软件,它非常直观易用。我会推荐它。在some research 之后,我了解到您不能忽略此异常并仍然使用.NET 的库连接到串行端口。

所以我必须深入了解 Win32 API 并编写自己的 API。我找到了一些涉及到这一点的页面,但老实说我以前从未做过这样的事情,所以我可能需要一段时间才能报告,但我一定会弄清楚这一点并回复给大家。受此问题困扰的人太多了。

我发现很多论坛和网站都可以看到完全相同的症状,但除了说“是的,.NET 很烂”之外,没有人真正做过很多事情。我计划编写一个完整的静态库类,然后在我的网站、这里和其他任何我可以发布的地方发布。希望 .NET 能引起注意(这个错误从 2.0 开始就存在)。

【问题讨论】:

  • 我唯一的猜测是您的属性在某种程度上是错误的。也许尝试将波特率降低到 9600。
  • 如果您进入控制面板管理工具计算机管理设备管理器Ports,找到虚拟端口并打开它的属性,你应该能够在Port Settings选项卡下看到它的设置。我会尝试匹配这些设置。
  • 嗯。您是否尝试将其关闭并重新打开?
  • 嗨 tmwoods,您可以将 Zach 的代码发布到您的问题中吗?谢谢,在 StackOverflow(和超级用户)问题/答案中通常会包含链接内容的摘要或专门回答问题的亮点。 SE 网站的目标是成为未来几年的知识和答案资源。通过对答案的仅链接引用,人们必须挖掘另一个资源来找到他/她可能不确定的答案。最重要的是,如果您的链接永远中断,那么您的回答对于将来访问此页面的任何人都是无用的。祝你好运!
  • 只是想知道...您是否尝试过在提升模式下运行 VS(例如以管理员身份)?

标签: c# winapi serial-port ioexception baud-rate


【解决方案1】:

这个来自串口驱动;它对其中一种设置不满意。由于波特率是一个很好的候选者,驱动程序往往只允许最高 115200。尽管当这是专用 CAN 总线产品时,这不应成为限制。

解决此问题的最佳方法是使用 Sysinternals 的 Portmon 实用程序;您可以看到正在发送给驱动程序的内容。首先观察它是否终止;这是您已知的工作基线。然后修改 SerialPort 属性,直到初始化命令(如您在 PortMon 中看到的)由您的程序发送的与 Termite 的匹配。只是值,而不是顺序。如果还是不行,那就把它带到停车场,然后用你的车把它倒过来几次,然后再买一个品牌。


更新:它确实看起来像一个波特率问题。这是 .NET 中的一个问题。它不会像您的终端模拟器程序那样忽略驱动程序的错误返回代码。实际值无关紧要,因为您正在与 仿真 串行端口通信。然而,CAN 总线速度可能存在问题;费率是可变的,我不清楚它们是如何协商的。在过去,这往往是通过 DIP 开关完成的,很可能是驱动程序希望您通过波特率设置来指定速度。盒子上或说明书上应该有关于它的东西。典型速度为 40、250 或 500 kbit/s。制造商肯定会知道;给他们打电话。

【讨论】:

  • 我晚上不在办公室,但明天我会去试试看:)
  • 能推荐一个更新的端口监控软件包吗?我能找到的唯一版本与 Windows 7 不兼容(他们最后一次更新这个软件似乎是 Win98)。它说它的版权归 2012 年所有,但我无法连接它,并且所有帮助文件要么丢失,要么针对 Win98 环境进行了解释。
  • 我试过Eltima Serial Port Monitor,看上面问题的主体。
  • 呃,我们是在谈论 SysInternals 的 PortMon 实用程序吗?它肯定可以在 Windows 7 上运行。请注意,您必须以提升的权限运行它,右键单击 + 以管理员身份运行。
  • 我已经删除了它,但我确信这会解决问题。 Eltima 效果很好,我看到了无效参数的出现位置,包括 Termite 和我的程序。现在我想弄清楚如何安全地忽略异常打开端口。在我这样做之前,我不想将问题标记为已解决。谢谢,任何更多的输入表示赞赏:)
【解决方案2】:

我遇到了同样的情况。我正在尝试在 /dev/ttyUSB0 将串行通信连接到我的 3G USB 加密狗(华为 E303F)。我在Raspbian (Raspberry Pi 2) 中使用Mono。在我的开发 PC 和 macOS 上,我的程序运行良好。但是当我将它部署到 Raspbian 中时,我在 Serial.Open() 上遇到了 IOException Broken Pipe 错误。

我花了三天时间调试,尝试了所有可能的解决方案。最后我发现我必须设置...

serialPort.DtrEnable = true;
serialPort.RtsEnable = true;

在调用 .Open() 之前。

【讨论】:

    【解决方案3】:

    我遇到了这个帖子中报告的类似问题,但我设法解决了这个问题!

    我正在为 VCP 使用 STM32F2xx!

    确实是我的固件问题。我忘记在我的 USB 回调中包含串口设置!

    从PC和固件连接串口的过程:

    1. 当PC打开串口通信时,PC会向“配置端点”发送一些命令
    2. 在固件中,它会有一个回调,固件会提供所有的 USB 信息(他们称之为 USB 描述符)
    3. USB 信息是每个端点的配置,(例如,延迟、数据大小传输和 USB 类型 - 高速或低速)
    4. 固件发送完所有信息后,PC 将确认并成功打开 USB 通信
    5. 然后,PC 将发送命令从固件中获取串口设置
    6. 串行端口设置为波特率、数据奇偶校验和位长度。
    7. 在固件中,它应该将串口设置回复给PC(我的错误出现在这里;我没有将任何串口设置发送回PC
    8. 如果成功,PC将启动串口通信!
    9. 如果失败,PC 将给出一个打开串行端口错误(但请注意,有时会绕过此错误)

    在STM32固件代码中:

    static int8_t CDC_Control_FS (uint8_t cmd, uint8_t* pbuf, uint16_t length)
    {
        switch (cmd) {
           case CDC_GET_LINE_CODING:
            {
                // I was missing this part
                uint32_t baudrate = 9600;
                pbuf[0] = (uint8_t)(baudrate);
                pbuf[1] = (uint8_t)(baudrate >> 8);
                pbuf[2] = (uint8_t)(baudrate >> 16);
                pbuf[3] = (uint8_t)(baudrate >> 24);
                pbuf[4] = 0;
                pbuf[5] = 0;
                pbuf[6] = 8;
                break;
            }:
    ....
    

    【讨论】:

    • 当我遇到类似问题时,这也对我有用。具体来说,每当设备断开连接并重新连接时,它会出现在设备管理器中并被识别为 USB 串行 COM 端口,但任何软件都无法使用,并且 .NET 会抛出“连接到系统的设备无法正常工作“ 例外。通过确保 USBUART 设备 (Cypress PSoC5LP) 固件正确设置活动端口并在检测到 USB 配置发生变化时重新初始化 CDC 接口(发送端口设置)来解决问题。
    【解决方案4】:

    我们惊心动魄的故事就这样结束了。它一直是固件(即嵌入式设备上的代码)。我们改变了一些功能,基本上是四处寻找、切碎、添加并完全清理了代码,瞧,代码正在工作。 This pic 总结得很好。诅咒你的固件!

    但是,我的(冗长的)问题中描述的错误对于很多人来说仍然存在,我知道还有很多人仍然有它。我只能说祝你好运并四次检查你的固件(显然现在三次检查还不够)。

    【讨论】:

    • Re“改变了一些功能”:你能说得更具体点吗?没有太多事情要做。
    • (链接似乎已断开 - “连接已超时。weknowmemes.com 上的服务器响应时间过长。”
    • 这只是一个链接到“我的代码不起作用/我不知道为什么/我的代码起作用/我不知道为什么”模因。
    • 至于“改变了一些功能”,老实说我不知道​​。现在已经有一段时间了,意识到我写那是多么无用。
    【解决方案5】:

    我遇到了同样的问题,将波特率设置为 1 修复了它

    【讨论】:

    • 奇怪的是,这对我也有用。我想知道为什么。
    猜你喜欢
    • 2020-02-21
    • 2015-01-17
    • 2016-06-02
    • 2015-09-15
    • 2017-08-22
    • 1970-01-01
    • 1970-01-01
    • 2014-04-05
    • 2023-04-01
    相关资源
    最近更新 更多