COM 端口被拒绝

发布于 2024-10-05 23:37:08 字数 571 浏览 1 评论 0原文

您好,我正在尝试使用 COM 端口使用 modbus 协议读取一些寄存器,一切正常,直到我重新启动 modbus 从设备,然后出现 com 被拒绝的错误,我能做的就是重新启动计算机或拔出并重新插入' USB 到 COM 转换器'。似乎该设备无法正确处理 com 端口。

using (port = new SerialPort(comPort))
{
   ushort[] registers = null;
   try
   {
      port.BaudRate = boudRate;
      port.DataBits = 8;
      port.Parity = Parity.None;
      port.StopBits = StopBits.One;
      port.Open();

      // modbus reading registers

      port.Close();
      return registers;
   }
   catch (Exception e)
   {
      Logs.AddToLog(e.Message);
      return registers;
   }
}

Hi I am trying to use COM port to read some registers using modbus protocol, everything works fine until I rebote modbus slave device, then I have error that com is denied, what I can do is or rebot computer or plug out and back in 'usb to com converter'. Seems that this device doesn't handle with com port properly.

using (port = new SerialPort(comPort))
{
   ushort[] registers = null;
   try
   {
      port.BaudRate = boudRate;
      port.DataBits = 8;
      port.Parity = Parity.None;
      port.StopBits = StopBits.One;
      port.Open();

      // modbus reading registers

      port.Close();
      return registers;
   }
   catch (Exception e)
   {
      Logs.AddToLog(e.Message);
      return registers;
   }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

喵星人汪星人 2024-10-12 23:37:08

如果您使用 FTDI USB/串行适配器,则可以直接从托管包装器检索状态 (FTDI 托管驱动程序包装器)并根据连接状态重新初始化串行端口。

请原谅我缺乏 FTDI 设备的经验,但这应该重置您的 R-232 适配器:

FTD2XX_NET.FTDI device = new FTD2XX_NET.FTDI();
string port;
device.GetCOMPort(out port);

if (!string.IsNullOrEmpty(port) && (port.Equals(target)) && device.IsOpen)
{
    device.CyclePort();
    device.ResetDevice();
    device.ResetPort();
}

据我了解 device.CyclePort() 将关闭任何活动连接(调用 FT_CLOSE) ,卸载 USB 设备,并从 USB 总线重新枚举该设备。这应该与您物理移除并重新插入适配器的情况完全相同。

另外,根据 FTDI 设备库的 Perl 包装器的文档:

与其他总线控件一样,有一个
等待 5-8 秒后
CyclePort 任何 API 都可以调用
需要直接连接到
设备,如 GetSerialByIndex()
等等,将会失败并返回 FT_INVALID_HANDLE
直到完全稳定下来。
该应用程序应考虑
在此等待期间,或设置轮询
循环检测返回的变化
状态。

If you are using an FTDI USB/Serial adapter, you can retrieve the state directly from the managed wrapper (FTDI Managed Driver Wrapper) and reinitialize your serial port based on the connected state.

Forgive my lack of experiance with FTDI devices, but this should reset your R-232 adapter:

FTD2XX_NET.FTDI device = new FTD2XX_NET.FTDI();
string port;
device.GetCOMPort(out port);

if (!string.IsNullOrEmpty(port) && (port.Equals(target)) && device.IsOpen)
{
    device.CyclePort();
    device.ResetDevice();
    device.ResetPort();
}

By my understanding device.CyclePort() will close any active connection (calls FT_CLOSE), unmounts the usb device, and reenumerates the device from the usb bus. This should be exactly the same as if you physically removed, and reinserted the adapter.

Also, according to the documentation for the Perl wrapper for the FTDI device library:

As with other bus controls, there is a
wait period of 5-8 seconds after a
CyclePort where any API call that
requires direct connection to the
device, like GetSerialByIndex()
etc, will fail with FT_INVALID_HANDLE
until it has completely stabilized.
The application should account for
this wait period, or setup a polling
loop to detect the change in return
status.

会发光的星星闪亮亮i 2024-10-12 23:37:08

我有过类似的经历,FTDI 设备会进入一种状态,除非我物理拔掉它,否则我无法与其通信。格雷格的回答帮助我想出了一个解决方法。

Greg 对 FTDI 托管包装器的引用非常有帮助,但他提供的代码片段并不完整,因为实际引用 FTDI 设备需要更多代码。以他的想法为起点,我改编了 FTDI 的一些示例代码并编写了这个函数。它能够让我的 FTDI 设备恢复工作状态,无需物理干预。

/// <summary>
/// Attempts to reset an attached FTDI device and returns true if successful.  Note that a
/// 5-8 second delay is recommended after the reset.
/// </summary>
/// <returns></returns>
private bool ResetFTDI() {
  UInt32 ftdiDeviceCount = 0;
  FTD2XX_NET.FTDI.FT_STATUS ftStatus = FTD2XX_NET.FTDI.FT_STATUS.FT_OK;

  // Create new instance of the FTDI device class
  FTD2XX_NET.FTDI myFtdiDevice = new FTD2XX_NET.FTDI();
  // Determine the number of FTDI devices connected to the machine
  ftStatus = myFtdiDevice.GetNumberOfDevices(ref ftdiDeviceCount);
  // Check status
  if (ftStatus != FTD2XX_NET.FTDI.FT_STATUS.FT_OK) {
    Log.WriteLog("Failed to get number of FTDI devices [" + ftStatus.ToString() + "]");
    return false;
  }
  // If no devices available, return
  if (ftdiDeviceCount == 0) {
    Log.WriteLog("Failed to find any FTDI devices [" + ftStatus.ToString() + "]");
    return false;
  }
  // Allocate storage for device info list
  FTD2XX_NET.FTDI.FT_DEVICE_INFO_NODE[] ftdiDeviceList = new FTD2XX_NET.FTDI.FT_DEVICE_INFO_NODE[ftdiDeviceCount];
  // Populate our device list
  ftStatus = myFtdiDevice.GetDeviceList(ftdiDeviceList);
  if (ftStatus != FTD2XX_NET.FTDI.FT_STATUS.FT_OK) {
    Log.WriteLog("Failed enumerate FTDI devices [" + ftStatus.ToString() + "]");
    return false;
  }
  // Open first device in our list by serial number
  ftStatus = myFtdiDevice.OpenBySerialNumber(ftdiDeviceList[0].SerialNumber);
  if (ftStatus != FTD2XX_NET.FTDI.FT_STATUS.FT_OK) {
    Log.WriteLog("Failed to open device [" + ftStatus.ToString() + "]");
    return false;
  }
  // Finally, reset the port
  myFtdiDevice.CyclePort();
  return true;
}

上面的 Log 对象是我的项目的内部对象,因此可以替换任何适合您的对象。

一些进一步的研究也发现了这个问题。在答案中,Zach Saw 提到了他在 .NET SerialPort 通信中发现的一个问题。我将尝试他的解决方案,如果这完全解决了问题,我将在这里发帖,因为我认为上述内容有点像创可贴。

I had a similar experience where an FTDI device would enter a state where I couldn't communicate with it unless I physically unplugged it. Greg's answer helped me come up with a workaround.

Greg's reference to FTDI's managed wrapper was very helpful, but the snippet he provided isn't quite there because it takes a bit more code to actually reference an FTDI device. With his idea as a starting point, I adapted some example code from FTDI and wrote this function. It was able to put my FTDI device back into a working state without physical intervention.

/// <summary>
/// Attempts to reset an attached FTDI device and returns true if successful.  Note that a
/// 5-8 second delay is recommended after the reset.
/// </summary>
/// <returns></returns>
private bool ResetFTDI() {
  UInt32 ftdiDeviceCount = 0;
  FTD2XX_NET.FTDI.FT_STATUS ftStatus = FTD2XX_NET.FTDI.FT_STATUS.FT_OK;

  // Create new instance of the FTDI device class
  FTD2XX_NET.FTDI myFtdiDevice = new FTD2XX_NET.FTDI();
  // Determine the number of FTDI devices connected to the machine
  ftStatus = myFtdiDevice.GetNumberOfDevices(ref ftdiDeviceCount);
  // Check status
  if (ftStatus != FTD2XX_NET.FTDI.FT_STATUS.FT_OK) {
    Log.WriteLog("Failed to get number of FTDI devices [" + ftStatus.ToString() + "]");
    return false;
  }
  // If no devices available, return
  if (ftdiDeviceCount == 0) {
    Log.WriteLog("Failed to find any FTDI devices [" + ftStatus.ToString() + "]");
    return false;
  }
  // Allocate storage for device info list
  FTD2XX_NET.FTDI.FT_DEVICE_INFO_NODE[] ftdiDeviceList = new FTD2XX_NET.FTDI.FT_DEVICE_INFO_NODE[ftdiDeviceCount];
  // Populate our device list
  ftStatus = myFtdiDevice.GetDeviceList(ftdiDeviceList);
  if (ftStatus != FTD2XX_NET.FTDI.FT_STATUS.FT_OK) {
    Log.WriteLog("Failed enumerate FTDI devices [" + ftStatus.ToString() + "]");
    return false;
  }
  // Open first device in our list by serial number
  ftStatus = myFtdiDevice.OpenBySerialNumber(ftdiDeviceList[0].SerialNumber);
  if (ftStatus != FTD2XX_NET.FTDI.FT_STATUS.FT_OK) {
    Log.WriteLog("Failed to open device [" + ftStatus.ToString() + "]");
    return false;
  }
  // Finally, reset the port
  myFtdiDevice.CyclePort();
  return true;
}

The Log object above is internal to my project so substitute whatever suits you.

Some further research also turned up this question. In the answers, Zach Saw references a problem he discovered with .NET SerialPort communications. I'm going to try his solution and I'll post back here if that resolves the problem entirely because I consider the above to be something of a bandaid.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文