SerialPort控件委托方式显示接收的字符串有关问题
SerialPort控件委托方式显示接收的字符串问题
Dim strData As String
Dim mRecvByte() As Byte
Private Sub SerialPort1_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
Dim mSize As Integer = Me.SerialPort1.BytesToRead
ReDim mRecvByte(mSize - 1)
SerialPort1.Read(mRecvByte, 0, mSize)
BeginInvoke(New EventHandler(AddressOf ONMLoadA), SerialPort1.BytesToRead()) '使用委托方式显示接收的字符串
End Sub
Sub ONMLoadA(ByVal sender As System.Object, ByVal e As System.EventArgs) '委托
Dim i As Integer
For i = 0 To mRecvByte.Length 'mSize - 1
strData = strData & IIf(mRecvByte(i) > 15, Hex(mRecvByte(i)), "0" & Hex(mRecvByte(i))) & " "
Next
TextBox2.Text = strData '显示为16进制
TextBox3.Text = Len(strData) / 3
End Sub
1. 接收的数据,显示时,只有第一次接近正确值,然后就离真相越来越远
2. 代码运行中途,经常提示 红色部分 数组索引越界,有时一开始运行就报此错误
3. 求其他更好的解决方案
------解决方案--------------------
Dim strData As String
Dim mRecvByte() As Byte
Private Sub SerialPort1_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
Dim mSize As Integer = Me.SerialPort1.BytesToRead
ReDim mRecvByte(mSize - 1)
SerialPort1.Read(mRecvByte, 0, mSize)
BeginInvoke(New EventHandler(AddressOf ONMLoadA), SerialPort1.BytesToRead()) '使用委托方式显示接收的字符串
End Sub
Sub ONMLoadA(ByVal sender As System.Object, ByVal e As System.EventArgs) '委托
Dim i As Integer
For i = 0 To mRecvByte.Length 'mSize - 1
strData = strData & IIf(mRecvByte(i) > 15, Hex(mRecvByte(i)), "0" & Hex(mRecvByte(i))) & " "
Next
TextBox2.Text = strData '显示为16进制
TextBox3.Text = Len(strData) / 3
End Sub
1. 接收的数据,显示时,只有第一次接近正确值,然后就离真相越来越远
2. 代码运行中途,经常提示 红色部分 数组索引越界,有时一开始运行就报此错误
3. 求其他更好的解决方案
------解决方案--------------------
- VB.NET code
Imports System.IO.Ports Imports System.Text Public Class Form1 '声明一个通信端口对象,使用WithEvents关键字,以便可以引发事件 Dim WithEvents RS232 As SerialPort '声明一个委派类,并声明符合函数参数有一个,而其型态是字符串 Delegate Sub SetTextCallback(ByVal InputString As String) Dim inStr As String Dim i As Integer = 0 '************************************************************** '表单的Load事件中先将所有的通信端口先列出来 '将通信端口排序,并将第一个通信端口设为默认值 '************************************************************** Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load For Each sp As String In SerialPort.GetPortNames() cmbCOM.Items.Add(sp) Next cmbCOM.Sorted = True '排序 cmbCOM.SelectedIndex = 0 '第一个是默认选项 End Sub '************************************************************** '『打开通信端口』按钮的Click事件 '此事件将设定通信端口参数,并打开通信端口 '************************************************************** Private Sub btnStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStart.Click Dim mBaudRate As Integer Dim mParity As IO.Ports.Parity Dim mDataBit As Integer Dim mStopbit As IO.Ports.StopBits Dim mPortName As String mPortName = cmbCOM.SelectedItem.ToString '欲打开的通信端口 mBaudRate = 9600 '通信速度 mParity = Parity.Even '同位位检查设定 mDataBit = 7 '数据位设定值 mStopbit = StopBits.Two '停止位设定值 '建立一个通信端口对象 RS232 = New IO.Ports.SerialPort(mPortName, mBaudRate, mParity, mDataBit, mStopbit) RS232.Encoding = Encoding.ASCII '''' RS232.Encoding = Encoding.Unicode '设定编码方式为Unicode,以便能显示中文 If Not RS232.IsOpen Then '尚未打开 RS232.Open() '打开通信端口 RS232.ReceivedBytesThreshold = 1 '设定引发事件的阀值 btnSend.Enabled = True '致能传送按钮 Else MsgBox("~~通信端口打开错误(通信端口已被打开)~~", MsgBoxStyle.Critical Or MsgBoxStyle.OkCancel) End End If End Sub '************************************************************** '『传送』按钮的Click事件 '将欲传送的字符串通过串行端口送出去 '************************************************************** Private Sub btnSend_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSend.Click RS232.Write(txtSend.Text) '采用Write方法送出 End Sub '************************************************************** '『关闭通信端口』按钮的Click事件 '以Close方法关闭通信端口,并释放对象所占用的资源 '************************************************************** Private Sub btnClose_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnClose.Click If RS232 Is Nothing OrElse Not RS232.IsOpen Then '尚未打开 MsgBox("~~通信端口尚未打开~~", MsgBoxStyle.Critical Or MsgBoxStyle.OkCancel) Exit Sub End If RS232.Close() RS232 = Nothing '释放资源 End Sub '************************************************************** '『结束程序』按钮 的Click事件 '此事件将设定通信端口参数,并打开通信端口 '************************************************************** Private Sub btnEnd_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnEnd.Click If Not RS232 Is Nothing Then '判断是否已建立通信对象 If RS232.IsOpen Then RS232.Close() '若已打开,就将其关闭 End If End End Sub '************************************************************** '通信端口对象的DataReceived事件程序 '当有数据超过ReceivedBytesThreshold属性设定值会引发此事件 '接收的程序可以写在此事件程序中 '处理数据的部份必须另外以委派(Delagate)类予以处理,否则将会产生错误 '************************************************************** Private Sub RS232_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles RS232.DataReceived '在此范围内,不能直接将结果指定给txtReceive控制项的Text属性 '原因是事件的引发在不同的执行绪 If e.EventType <> SerialData.Chars Then Exit Sub '判断接收的数据是否为字符 Dim inData As String = RS232.ReadExisting '取得字符串 DisplayText(inData) '显示数据 End Sub '************************************************************** '委派子程序 '处理上述通信端口的接收事件 '由于欲将数据显示到接收文字框中,因此必须检查是否由另外的Thread '所呼叫的,若是,则必须先建立委派对象 'Invoke用于在拥有控制项基础视窗控制代码的执行绪上执行委派 '************************************************************** Private Sub DisplayText(ByVal comData As String) '如果呼叫txtReceive的是另外的执行绪,传回True Try If Me.txtReceive.InvokeRequired Then '利用委派型别建立委派对象,并指定委派的函数 Dim d As New SetTextCallback(AddressOf ShowString) '用大括号 {} 括住初始值,藉以初始化阵列的值。 Me.Invoke(d, New Object() {comData}) '以指定的引数清单叫用函数 Else '相同的执行绪 ShowString(comData) '将收到的数据填入接收文字框中 End If Catch ex As Exception 'MsgBox(ex.ToString) Finally End Try End Sub '************************************************************** '显示数据的函数 '************************************************************** Private Sub ShowString(ByVal comData As String) ' Region(将数据存入缓冲) Dim s As String = comData Try If comData.Length < 13 Then Exit Sub s = comData.Substring(comData.IndexOf(Chr(2)), 10) '判断首字符 s = s.ToCharArray '转换成数组来理解 If s(1) = "M" Then '判断是否稳定 Label4.Text = "稳定" Else Label4.Text = "动态" End If s = s.Substring(3, 7) '分离出重量数据 's = s(1) + s(2) + s(3) + s(4) + s(5) + s(6) s = Single.Parse(s) txtReceive.Text = s Catch ex As Exception Finally End Try ' end region End Sub '************************************************************** '通信端口的KeyPress事件,在此不让用户输入数据 '************************************************************** Private Sub cmbCOM_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles cmbCOM.KeyPress e.KeyChar = ChrW(0) '禁止用户在其中输入任何的文字 End Sub End Class