串行端口 - 如何设置字符?

发布于 2025-01-01 06:09:41 字数 1242 浏览 2 评论 0 原文

考虑一下:

Baud rate 19200
RTS on
DTR on
Data bits=8, Stop bits=1, Parity=None
Set chars: Eof=0x00, Error=0x2A, Break=0x2A, Event=0x00, Xon=0x11, Xoff=0x13
Handflow: ControlHandShake=(DTR_CONTROL), FlowReplace=(TRANSMIT_TOGGLE, RTS_CONTROL),
XonLimit=0, XoffLimit=4096

好的,所以使用端口扫描仪我发现 USB 设备需要这些设置来促进导入。我可以重新创建其中的大部分,如下所示:

port = new SerialPort("COM4");
port.DtrEnable = true;
port.RtsEnable = true;
port.Handshake = Handshake.None;                                  
port.BaudRate = 19200;
port.StopBits = StopBits.One;
port.Parity = Parity.None;
port.DataBits = 8;    

port.Open();

byte[] a = new byte[2] { 0x0 , 0x1 };
port.Write(a, 0, 1);
port.Write(a, 0, 1);
port.Write("mem");
port.Write("mem");

string output = port.ReadExisting();

System.Diagnostics.Debug.WriteLine("Found: " + output);

但是,生成的代码如下:

Set chars: Eof=0x1A, Error=0x00, Break=0x00, Event=0x1A, Xon=0x11, Xoff=0x13
XonLimit=1024, XoffLimit=1024

如何更改 X 限制和每个字符代码,以便有机会工作?

帖子 SerialPort 0x1A 字符读取问题是迄今为止我发现的最接近的事情,但我不明白它。

Consider:

Baud rate 19200
RTS on
DTR on
Data bits=8, Stop bits=1, Parity=None
Set chars: Eof=0x00, Error=0x2A, Break=0x2A, Event=0x00, Xon=0x11, Xoff=0x13
Handflow: ControlHandShake=(DTR_CONTROL), FlowReplace=(TRANSMIT_TOGGLE, RTS_CONTROL),
XonLimit=0, XoffLimit=4096

OK, so using a port scanner I've found that a USB device needs these settings to facilitate an import. I can recreate most of these as follows:

port = new SerialPort("COM4");
port.DtrEnable = true;
port.RtsEnable = true;
port.Handshake = Handshake.None;                                  
port.BaudRate = 19200;
port.StopBits = StopBits.One;
port.Parity = Parity.None;
port.DataBits = 8;    

port.Open();

byte[] a = new byte[2] { 0x0 , 0x1 };
port.Write(a, 0, 1);
port.Write(a, 0, 1);
port.Write("mem");
port.Write("mem");

string output = port.ReadExisting();

System.Diagnostics.Debug.WriteLine("Found: " + output);

However, the codes produced are these:

Set chars: Eof=0x1A, Error=0x00, Break=0x00, Event=0x1A, Xon=0x11, Xoff=0x13
XonLimit=1024, XoffLimit=1024

How do I change the X limits, and each of the character codes so that this has a chance of working?

The post SerialPort 0x1A character reading problem is the closest thing I've found so far, but I don't understand it.

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

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

发布评论

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

评论(2

時窥 2025-01-08 06:09:41

您可以在 C# 中向串行端口添加扩展 - 请参阅NET2.0 SerialPort 类中的 Xon/Xoff 值

对于其他字段,您可以更改:

dcbType.GetField("XonChar"); // "XonChar", "XoffChar", "ErrorChar", "EofChar", "EvtChar"

代码:

using System;
using System.ComponentModel;
using System.IO.Ports;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using Microsoft.Win32.SafeHandles;

class Program
{
    static void Main(string[] args)
    {
        using (var port = new SerialPort("COM1"))
        {
            port.Open();
            port.SetXonXoffChars(0x12, 0x14);
        }
    }
}

internal static class SerialPortExtensions
{
    [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
    public static void SetXonXoffChars(this SerialPort port, byte xon, byte xoff)
    {
        if (port == null)
            throw new NullReferenceException();
        if (port.BaseStream == null)
            throw new InvalidOperationException("Cannot change X chars until after the port has been opened.");

        try
        {
            // Get the base stream and its type which is System.IO.Ports.SerialStream
            object baseStream = port.BaseStream;
            Type baseStreamType = baseStream.GetType();

            // Get the Win32 file handle for the port
            SafeFileHandle portFileHandle = (SafeFileHandle)baseStreamType.GetField("_handle", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(baseStream);

            // Get the value of the private DCB field (a value type)
            FieldInfo dcbFieldInfo = baseStreamType.GetField("dcb", BindingFlags.NonPublic | BindingFlags.Instance);
            object dcbValue = dcbFieldInfo.GetValue(baseStream);

            // The type of dcb is Microsoft.Win32.UnsafeNativeMethods.DCB which is an internal type. We can only access it through reflection.
            Type dcbType = dcbValue.GetType();
            dcbType.GetField("XonChar").SetValue(dcbValue, xon);
            dcbType.GetField("XoffChar").SetValue(dcbValue, xoff);

            // We need to call SetCommState but because dcbValue is a private type, we don't have enough
            //  information to create a p/Invoke declaration for it. We have to do the marshalling manually.

            // Create unmanaged memory to copy DCB into
            IntPtr hGlobal = Marshal.AllocHGlobal(Marshal.SizeOf(dcbValue));
            try
            {
                // Copy their DCB value to unmanaged memory
                Marshal.StructureToPtr(dcbValue, hGlobal, false);

                // Call SetCommState
                if (!SetCommState(portFileHandle, hGlobal))
                    throw new Win32Exception(Marshal.GetLastWin32Error());

                // Update the BaseStream.dcb field if SetCommState succeeded
                dcbFieldInfo.SetValue(baseStream, dcbValue);
            }
            finally
            {
                if (hGlobal != IntPtr.Zero)
                    Marshal.FreeHGlobal(hGlobal);
            }
        }
        catch (SecurityException) { throw; }
        catch (OutOfMemoryException) { throw; }
        catch (Win32Exception) { throw; }
        catch (Exception ex)
        {
            throw new ApplicationException("SetXonXoffChars has failed due to incorrect assumptions about System.IO.Ports.SerialStream which is an internal type.", ex);
        }
    }

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern bool SetCommState(SafeFileHandle hFile, IntPtr lpDCB);
}

You can add an extension to the serialPort in C# - see Xon/Xoff values in NET2.0 SerialPort class.

For the other fields you can change:

dcbType.GetField("XonChar"); // "XonChar", "XoffChar", "ErrorChar", "EofChar", "EvtChar"

Code:

using System;
using System.ComponentModel;
using System.IO.Ports;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using Microsoft.Win32.SafeHandles;

class Program
{
    static void Main(string[] args)
    {
        using (var port = new SerialPort("COM1"))
        {
            port.Open();
            port.SetXonXoffChars(0x12, 0x14);
        }
    }
}

internal static class SerialPortExtensions
{
    [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
    public static void SetXonXoffChars(this SerialPort port, byte xon, byte xoff)
    {
        if (port == null)
            throw new NullReferenceException();
        if (port.BaseStream == null)
            throw new InvalidOperationException("Cannot change X chars until after the port has been opened.");

        try
        {
            // Get the base stream and its type which is System.IO.Ports.SerialStream
            object baseStream = port.BaseStream;
            Type baseStreamType = baseStream.GetType();

            // Get the Win32 file handle for the port
            SafeFileHandle portFileHandle = (SafeFileHandle)baseStreamType.GetField("_handle", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(baseStream);

            // Get the value of the private DCB field (a value type)
            FieldInfo dcbFieldInfo = baseStreamType.GetField("dcb", BindingFlags.NonPublic | BindingFlags.Instance);
            object dcbValue = dcbFieldInfo.GetValue(baseStream);

            // The type of dcb is Microsoft.Win32.UnsafeNativeMethods.DCB which is an internal type. We can only access it through reflection.
            Type dcbType = dcbValue.GetType();
            dcbType.GetField("XonChar").SetValue(dcbValue, xon);
            dcbType.GetField("XoffChar").SetValue(dcbValue, xoff);

            // We need to call SetCommState but because dcbValue is a private type, we don't have enough
            //  information to create a p/Invoke declaration for it. We have to do the marshalling manually.

            // Create unmanaged memory to copy DCB into
            IntPtr hGlobal = Marshal.AllocHGlobal(Marshal.SizeOf(dcbValue));
            try
            {
                // Copy their DCB value to unmanaged memory
                Marshal.StructureToPtr(dcbValue, hGlobal, false);

                // Call SetCommState
                if (!SetCommState(portFileHandle, hGlobal))
                    throw new Win32Exception(Marshal.GetLastWin32Error());

                // Update the BaseStream.dcb field if SetCommState succeeded
                dcbFieldInfo.SetValue(baseStream, dcbValue);
            }
            finally
            {
                if (hGlobal != IntPtr.Zero)
                    Marshal.FreeHGlobal(hGlobal);
            }
        }
        catch (SecurityException) { throw; }
        catch (OutOfMemoryException) { throw; }
        catch (Win32Exception) { throw; }
        catch (Exception ex)
        {
            throw new ApplicationException("SetXonXoffChars has failed due to incorrect assumptions about System.IO.Ports.SerialStream which is an internal type.", ex);
        }
    }

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern bool SetCommState(SafeFileHandle hFile, IntPtr lpDCB);
}
断爱 2025-01-08 06:09:41

这些设置可以通过 Win32 SetCommState 功能。

不幸的是,.NET 没有提供一组很好的属性来配置它们,也没有让您访问 HANDLE,因此您无法使用 p/invoke 来调整 .NET 的设置。 NET 串行端口类。

相反,您必须放弃整个 System.IO.Ports.SerialPort 类并使用 Win32 API 执行所有操作:

  • CreateFile
  • GetCommState
  • < code>SetCommState
  • WriteFile(Ex)
  • ReadFile(Ex)
  • WaitCommEvent

我建议您不要使用 C#,因为Win32 API 在 C++ 中使用起来要容易得多,并且通过 C++/CLI,您可以编写与 C# GUI 良好交互的类。这是一项相当大的工作量,好处是 Win32 串行端口功能比 .NET 库提供的功能强大得多。我希望有一天能够发布我制作的 C++/CLI 串口类。

Those settings can be configured by the Win32 SetCommState function.

Unfortunately, .NET doesn't provide a nice set of properties to configure them, nor does it give you access to the HANDLE, so you can't use p/invoke to adjust the settings for a .NET SerialPort class.

Instead, you'll have to ditch the entire System.IO.Ports.SerialPort class and do everything using the Win32 APIs:

  • CreateFile
  • GetCommState
  • SetCommState
  • WriteFile(Ex)
  • ReadFile(Ex)
  • WaitCommEvent

I recommend that you not use C# for that, the Win32 API is much easier to use from C++, and with C++/CLI, you can write classes that interface nicely with a C# GUI. It's a fair amount of work, the upside is that the Win32 serial port functions are far more powerful than what the .NET libraries give you access to. I hope to someday be allowed to publish the C++/CLI serial port class I've made.

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