COMport.Readline() 问题:溢出缓冲区和字符串操作
COMport.Readline() Issues : Flooded buffer and string manipulation
我有一个体重秤,可以将恒定输出输出到串行端口。我制作了一个每 3 秒循环一次以读取秤上最新重量的应用程序,该循环使用 Async
Sub,然后使用 Await Task.Run(Sub()
然后休眠 3 秒。我有 2 个问题。
首先,缓冲区充满了数据,因此如果您减轻重量,比如 100 磅,它仍会读取缓冲区中的旧数据,同时秤上的实际重量为 0。但它会慢慢下降3 秒。我尝试在 Backgroundworker 中连续循环 readline()
但比例仍然输出很快。我应该在 readline()
之前尝试 'DiscardBuffer()' 吗?还是有别的阅读方法?
代码:COM 端口属性
With COMScale 'COM Port Properties
.PortName = cmbPorts.Text 'COM Port Name
.Parity = IO.Ports.Parity.None
.DataBits = 8
.StopBits = IO.Ports.StopBits.One
.BaudRate = 9600
.ReceivedBytesThreshold = 1
.NewLine = vbCr
.ReadTimeout = 5000
End With
代码:后台工作人员
Private Sub BackgroundWorker1_DoWork(sender As Object, e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
WeightA = 0
COMScale.DiscardInBuffer()
Try
COMScale.ReadTimeout = 10000
Do
Dim Incoming As String = COMScale.ReadLine()
If Incoming Is Nothing Then
Exit Do
Else
WeightA &= Incoming
End If
Loop
Catch ex As TimeoutException
WeightA = "N/A"
MsgBox(COMScale.PortName & "Timed Out")
Finally
'If com1 IsNot Nothing Then com1.Close()
lblWeightA.Text = WeightA
End Try
End Sub
第二期是秤输出的字符串,像这样...
“5?” & ChrW(2) & ChrW(2) & "??j" & ChrW(2) & "; 47" & ChrW(2) & ChrW(2) & ChrW(2) & ChrW(2) & "?? j" & ChrW(2) & "; 475" & ChrW(2) & ChrW(2) & ChrW(2) & "??j" & ChrW(2) & "; 475 00"
体重秤上写着 47.5 磅
我只需要末尾的“475”数字但带有小数点,因此字符串为 47.5 。我唯一能想到的是 Right(string)
我在使用 Right(String)
时看到的问题是它可能是 1000 磅、100 磅或 10 磅,所以它会切断我需要的东西。我最好的选择是什么?
您的应用程序不应休眠 3 秒,而应连续读取。那么缓冲区将不会填满。
因此,让您的 BackgroundWorker 运行 进入一个循环。也不要修改后台工作人员的任何 UI 元素。而是使用 ReportProgress 将其发送到表单。
Private Sub BackgroundWorker1_DoWork(sender As Object, e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
COMScale.DiscardInBuffer()
Dim buffer As String
While e.Cancel = False
Try
buffer &= COMScale.ReadLine()
buffer = ProcessBuffer(buffer)
Catch ex As TimeoutException
BackgroundWorker1.ReportProgress(0, ex)
End Try
End While
End Sub
Private Sub BackgroundWorker1_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
If TypeOf e.UserState Is TimeoutException Then
lblWeightA.Text = "N/A"
MessageBox.Show("Timeout")
ElseIf TypeOf e.UserState Is Decimal Then
lblWeightA.Text = CDec(e.UserState).ToString()
End If
End Sub
Private Function ProcessBuffer(inputBuffer As String)
'Parse your string. Looking for the last occurrence of the data you need.
If extractedPortion IsNot Nothing
BackgroundWorker1.ReportProgress(0, Decimal.Parse(extractedPortion))
End If
Return leftOverChacters
End Function
我有一个体重秤,可以将恒定输出输出到串行端口。我制作了一个每 3 秒循环一次以读取秤上最新重量的应用程序,该循环使用 Async
Sub,然后使用 Await Task.Run(Sub()
然后休眠 3 秒。我有 2 个问题。
首先,缓冲区充满了数据,因此如果您减轻重量,比如 100 磅,它仍会读取缓冲区中的旧数据,同时秤上的实际重量为 0。但它会慢慢下降3 秒。我尝试在 Backgroundworker 中连续循环 readline()
但比例仍然输出很快。我应该在 readline()
之前尝试 'DiscardBuffer()' 吗?还是有别的阅读方法?
代码:COM 端口属性
With COMScale 'COM Port Properties
.PortName = cmbPorts.Text 'COM Port Name
.Parity = IO.Ports.Parity.None
.DataBits = 8
.StopBits = IO.Ports.StopBits.One
.BaudRate = 9600
.ReceivedBytesThreshold = 1
.NewLine = vbCr
.ReadTimeout = 5000
End With
代码:后台工作人员
Private Sub BackgroundWorker1_DoWork(sender As Object, e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
WeightA = 0
COMScale.DiscardInBuffer()
Try
COMScale.ReadTimeout = 10000
Do
Dim Incoming As String = COMScale.ReadLine()
If Incoming Is Nothing Then
Exit Do
Else
WeightA &= Incoming
End If
Loop
Catch ex As TimeoutException
WeightA = "N/A"
MsgBox(COMScale.PortName & "Timed Out")
Finally
'If com1 IsNot Nothing Then com1.Close()
lblWeightA.Text = WeightA
End Try
End Sub
第二期是秤输出的字符串,像这样...
“5?” & ChrW(2) & ChrW(2) & "??j" & ChrW(2) & "; 47" & ChrW(2) & ChrW(2) & ChrW(2) & ChrW(2) & "?? j" & ChrW(2) & "; 475" & ChrW(2) & ChrW(2) & ChrW(2) & "??j" & ChrW(2) & "; 475 00"
体重秤上写着 47.5 磅
我只需要末尾的“475”数字但带有小数点,因此字符串为 47.5 。我唯一能想到的是 Right(string)
我在使用 Right(String)
时看到的问题是它可能是 1000 磅、100 磅或 10 磅,所以它会切断我需要的东西。我最好的选择是什么?
您的应用程序不应休眠 3 秒,而应连续读取。那么缓冲区将不会填满。
因此,让您的 BackgroundWorker 运行 进入一个循环。也不要修改后台工作人员的任何 UI 元素。而是使用 ReportProgress 将其发送到表单。
Private Sub BackgroundWorker1_DoWork(sender As Object, e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
COMScale.DiscardInBuffer()
Dim buffer As String
While e.Cancel = False
Try
buffer &= COMScale.ReadLine()
buffer = ProcessBuffer(buffer)
Catch ex As TimeoutException
BackgroundWorker1.ReportProgress(0, ex)
End Try
End While
End Sub
Private Sub BackgroundWorker1_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
If TypeOf e.UserState Is TimeoutException Then
lblWeightA.Text = "N/A"
MessageBox.Show("Timeout")
ElseIf TypeOf e.UserState Is Decimal Then
lblWeightA.Text = CDec(e.UserState).ToString()
End If
End Sub
Private Function ProcessBuffer(inputBuffer As String)
'Parse your string. Looking for the last occurrence of the data you need.
If extractedPortion IsNot Nothing
BackgroundWorker1.ReportProgress(0, Decimal.Parse(extractedPortion))
End If
Return leftOverChacters
End Function