【问题标题】:Using events in conjuction with serial ports in c#在 C# 中将事件与串行端口结合使用
【发布时间】:2022-10-24 20:13:40
【问题描述】:

我正在建造一个网6.0我们必须与通过以下方式通信的外部设备进行交互的应用程序RS232串行端口。

外部设备使用协议与应用程序通信,我们事先知道大小和某些部分(头状) 的消息包,是基于客户端-服务器架构.

在我尝试实施该解决方案时,我使用了轮询在串行的无限循环中工作正常,尽管同步需要相当长的时间(大约30秒)。

我试图解决该解决方案并转到更多“事件驱动方法" 基于events 并尝试通过数据接收event

虽然看起来我正在取回数据,但缓冲区的实际内容与预期的内容明显不同,大小要大得多(预计最大大约 10-15 个字节,大约 140 个字节)。

我阅读了提供的第二个链接上的评论,似乎有一些模棱两可的结果:

  1. 操作系统决定何时引发事件
  2. 每个字节到达时不会引发事件

    我的问题是:

    1. 什么时候数据接收事件触发?会有操作系统的情况吗缓冲接收的数据并将它们作为一批发送?例如,来自 RS232 的一个“请求”将是 12 个字节,下一个是 14 个字节等,因此当我尝试从缓冲区访问数据时,字节数会大得多?

    2. 有没有办法配置应用程序或操作系统(不确定该解决方案的便携性),以便当 RS232 设备发送任何类型的有效负载(例如 12 字节或 14 字节等)时,这将显式触发事件?

      非常感谢您的宝贵时间!

【问题讨论】:

    标签: c# .net events serial-port serial-communication


    【解决方案1】:

    您正在寻找的可能是这样的:

    使用 BytesToRead 属性来确定缓冲区中还有多少数据要读取。 DataRecieved 事件通常在从客户端发送 EOC 字符时触发。当“BytesToRead”中出现足够的字节时,它也会触发。有时它会触发每个字节。

       Private Sub _SerialPortReader_DataReceived(sender As Object, e As SerialDataReceivedEventArgs) Handles _SerialPortReader.DataReceived
        Dim currentSP As SerialPort = Convert.ChangeType(sender, GetType(SerialPort))
        Dim strBuilder As System.Text.StringBuilder = New System.Text.StringBuilder()
        Dim incomingText As String = ""
        currentSP.ReadTimeout = 1000
        Do
            Try
                strBuilder.Append(Convert.ChangeType(currentSP.ReadByte(), GetType(Char)))
                incomingText = strBuilder.ToString()
                If incomingText.Contains(CustomSharedFunctions.GetStringFromDecimal(_EndofCommunicationString)) Then Exit Do
            Catch ex As Exception
                Exit Do
            End Try
        Loop
    'incomingText contains now the full message sent to you, remember this event triggers on a different thread, so you might want to use Invoke() here.
    
    End Sub
    

    C#代码在这里:

    private void _SerialPortReader_DataReceived(object sender, SerialDataReceivedEventArgs e){
    SerialPort currentSP = Convert.ChangeType(sender, typeof(SerialPort));
    System.Text.StringBuilder strBuilder = new System.Text.StringBuilder();
    string incomingText = "";
    currentSP.ReadTimeout = 1000;
    do
    {
        try
        {
            strBuilder.Append(Convert.ChangeType(currentSP.ReadByte(), typeof(char)));
            incomingText = strBuilder.ToString();
            if (incomingText.Contains(CustomSharedFunctions.GetStringFromDecimal(_EndofCommunicationString)))
                break;
        }
        catch (Exception ex)
        {
            break;
        }
    }
    while (true);}
    

    【讨论】:

    • 没有看到循环的意义,SerialPort.ReadExisting 就是为了这个……?
    • 我发现循环和使用 readbyte (这样我可以查找 EOC 字符)比只使用 readexistsing 好得多(并且可能由于竞争条件而错过一些东西)
    【解决方案2】:

    也许你不应该关心操作系统如何/何时管理它的东西......通常它是由缓冲区大小/性能超时的微妙平衡触发的。

    据我了解,您正在处理应用程序级别,因此您应该更专注于检测帧结束(因为您使用给定协议)而不是单个字节。

    我建议尝试在传入数据上构建一种解析器/适配器,以检测格式良好/拆分的帧(在专用/自定义事件中优雅/健壮?)...

    协议只是嵌套层/帧到位/字节的问题......

    【讨论】:

      猜你喜欢
      • 2016-08-16
      • 2023-03-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-12-21
      • 1970-01-01
      相关资源
      最近更新 更多