【问题标题】:How to fix "The I/O operation has been aborted because of either a thread exit or an application request" with SerialPort in VB.NET?如何使用 VB.NET 中的 SerialPort 解决“由于线程退出或应用程序请求而中止 I/O 操作”?
【发布时间】:2022-01-23 06:32:57
【问题描述】:

我是编程新手,.net 是我用来做我需要的简单事情的工具。我创建了一个程序来读取来自串行端口的重量指示器,它在 EL05 设备上工作得很好:

Private Sub sppuerto_DataReceived( sender As Object, e As IO.Ports.SerialDataReceivedEventArgs ) Handles sppuerto.DataReceived

    Dim buffer As String
    '------- WORKS FOR EL05 -----------------
    buffer = sppuerto.ReadLine
    txtrecibe.Text = buffer.Substring(4, 5)
End Sub

但现在我正在连接另一家制造商的新设备,但ReadLine 出现异常:

System.dll 中出现“System.IO.IOException”类型的未处理异常

附加信息:La operación de E/S se anuló por una salida de subproceso o por una solicitud de aplicación"

异常信息的英文版是

由于线程退出或应用程序请求,I/O 操作已中止


我让它与 ReadExisting 一起工作,但它一直在读取,并且永远不会像 ReadLine 那样停止

Private Sub sppuerto_DataReceived( sender As Object, e As IO.Ports.SerialDataReceivedEventArgs ) Handles sppuerto.DataReceived

    Dim buffer As String

    '------------- WORKS WITH NEW INDICATOR BUT UNREADABLE----------------
    buffer = sppuerto.ReadExisting
    txtrecibe.Text = buffer

End Sub

我环顾四周,但所有帖子都涉及 C# 实现,我真的不想深入探讨,因为与我阅读的内容完全不同。也在 Java 中。

有人在 VB.NET 中尝试过吗?如果需要,我可以粘贴更多代码。

编辑: 按请求添加完整代码(不是很长)

Imports System.IO.Ports

Public Class Form1
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        CheckForIllegalCrossThreadCalls = False
        buscarpuerto()
    End Sub

    Private Sub buscarpuerto()

        Try
            cmbPort.Items.Clear()
            For Each puerto As String In My.Computer.Ports.SerialPortNames
                cmbPort.Items.Add(puerto)
            Next
            If cmbPort.Items.Count > 0 Then
                cmbPort.SelectedIndex = 0

            Else
                MsgBox(" NO HAY PUERTO DISPONIBLES ")
            End If
        Catch ex As Exception
            MsgBox(ex.Message, MsgBoxStyle.Critical)
        End Try

    End Sub

    Private Sub btnconectar_Click(sender As Object, e As EventArgs) Handles btnconectar.Click
        Try
            With sppuerto
                .BaudRate = Int32.Parse(CboBaudRate.Text)
                .DataBits = 8
                .Parity = IO.Ports.Parity.None
                .StopBits = 1
                .PortName = cmbPort.Text
                .Open()

                If .IsOpen Then
                    lblestado.Text = "CONECTADO"
                Else
                    MsgBox("NO SE PUDO CONECTAR", MsgBoxStyle.Critical)
                End If


            End With
        Catch ex As Exception

        End Try
    End Sub

    Private Sub btndesconectar_Click(sender As Object, e As EventArgs) Handles btndesconectar.Click
        sppuerto.Close()
        lblestado.Text = "DESCONECTADO"
    End Sub

    Private Sub sppuerto_DataReceived(sender As Object, e As IO.Ports.SerialDataReceivedEventArgs) Handles sppuerto.DataReceived

        Dim buffer As String
        Dim x As String
        buffer = ""

        '------- WORKS FOR EL05 -----------------

        'buffer = sppuerto.ReadLine
        'txtrecibe.Text = buffer.Substring(4, 5)


        '------------- WORKS WITH NEW INDICATOR BUT UNREADABLE----------------
        x = sppuerto.ReadExisting
        buffer = buffer + x
        txtrecibe.Text = buffer


    End Sub

    Private Sub btnenviar_Click(sender As Object, e As EventArgs) Handles btnenviar.Click
        If sppuerto.IsOpen Then
            sppuerto.WriteLine(txtenvia.Text)
        Else
            MsgBox("NO ESTAS CONECTADO", MsgBoxStyle.Exclamation)
        End If
    End Sub

    Private Sub btnsalida_Click(sender As Object, e As EventArgs) Handles btnsalida.Click
        If lblestado.Text = ("CONECTADO") Then
            MsgBox("DESCONECTARSE DEL SISTEMA", MsgBoxStyle.Exclamation, "AYUDA")
        Else
            Close()
        End If
    End Sub
End Class

【问题讨论】:

  • 字符串不是缓冲区。
  • 什么是“EL05 设备”?
  • 您错误地使用了SerialPortDataReceived 事件只能与ReadExisting() 方法一起使用,您不应在_DataReceived 事件处理程序中执行任何阻塞调用。
  • “同样使用 Java。” - Java 完全不同(不仅是一种不同的语言,而且是完全不同的 API 设计和串行端口库),至少对于 C# 代码示例,您使用的是同一个库 (System.IO.Ports)所以这些答案和示例可以翻译成 VB.NET。
  • 另外,出于好奇,当微软明确表示 VB.NET 在不久的将来不会成为 .NET 生态系统的一部分时,您为什么还要使用 VB.NET?

标签: vb.net serial-port


【解决方案1】:

我怀疑您的新设备没有完全接收到数据。您可能需要测试传入的数据缓冲区以查看其长度是否仍在增加。仅当设备完成将数据发送到缓冲区时,您才会 ReadExisting。

Dim x = SerialPort1.BytesToRead

Application.DoEvents()

Do While SerialPort1.BytesToRead <> x
     x = SerialPort1.BytesToRead
     Application.DoEvents()
Loop

请注意,这将阻止您的代码运行,直到设备完成写入。此外,如果您的计算机速度较慢,并且 COM 设备不断发送数据,您可能会在比较 BytesToRead 数字之前在缓冲区中获得一个新字符串,并且永远不会中断。

您可能还希望将串行端口的 ReceivedBytesThreshold 更改为仅在接收到多个字节而不是默认的一个字节时触发 DataReceived 事件。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-02-17
    • 2023-03-23
    • 2014-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多