[英]What is the proper use of SerialPort.BaseStream.BeginRead?
我在使用從串口獲取不可靠數據的程序時遇到問題,我相信https://www.sparxeng.com/blog/software/must-use.net-system-io-ports-serialport#comments
這篇文章有一些答案——bytestoread 值似乎不穩定,當數據存在時並不總是調用回調,並且所有默認串行端口函數都不可靠,包括 datareceived 事件。 正是我在這個項目中所經歷的。 事實上,在整個串行端口的微軟文檔中,都有免責聲明和功能失敗的注釋。 它沒有的是當這些問題出現在您的應用程序中時的解決方案。
但是,當我嘗試使用文章中提供的解決方案時,似乎 output 永遠都是相同的第一個字節:“pppppppppppppppppppppppppppp” 我可以確認收到的第一個字節實際上是“p”,但為什么它沒有刪除該字節在閱讀並繼續,或收到任何字節之后,我不知道。 據我所知,它與文章中提出的解決方案完全相同。 這是代碼:
private void Form1_Shown(object sender, EventArgs e)
{
try
{
sp.Open();
SPDataHelper();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void SPDataHelper()
{
byte[] buffer = new byte[8000];
Action kickoffRead = null;
kickoffRead = delegate
{
sp.BaseStream.BeginRead(buffer, 0, buffer.Length, delegate (IAsyncResult ar)
{
try
{
int actualLength = sp.BaseStream.EndRead(ar);
byte[] received = new byte[actualLength];
Buffer.BlockCopy(buffer, 0, received, 0, actualLength);
sp_DataReceived(System.Text.Encoding.UTF8.GetString(received));//not called by the actual serialport anymore
}
catch (IOException exc)
{
WriteUUTWindow("Exception: "+exc.ToString());
}
kickoffRead();
}, null);
};
kickoffRead();
}
當我在分配后在“actuallength”上放置斷點時,它顯示 1,表明它從不在第一個字節之后讀取。 之后再也不會到達該分配和回調的斷點,但應用程序繼續發送垃圾郵件“p”。 知道這里發生了什么嗎?
如果您對使用BeginRead
感興趣,請嘗試以下操作 - 它已經過條形碼掃描儀測試:
創建一個class(名稱:HelperSerialPort.cs)
選項 1 :
HelperSerialPort.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.IO.Ports;
using System.Diagnostics;
namespace SerialPortTest
{
public enum PortBaudRate : int
{
Baud1200 = 1200,
Baud2400 = 2400,
Baud4800 = 4800,
Baud9600 = 9600,
Baud14400 = 14400,
Baud19200 = 19200,
Baud28800 = 28800,
Baud38400 = 38400,
Baud56000 = 56000,
Baud57600 = 57600,
Baud76800 = 76800,
Baud115200 = 115200,
Baud128000 = 128000,
Baud230400 = 230400,
Baud250000 = 250000,
Baud256000 = 256000
};
public class HelperSerialPort
{
public SerialPort Port { get; private set; } = null;
private string _dataReceived = string.Empty;
public HelperSerialPort(string portName, PortBaudRate baudRate = PortBaudRate.Baud9600)
{
Initialize(portName, baudRate);
}
private void Initialize(string portName, PortBaudRate baudRate = PortBaudRate.Baud9600)
{
//create new instance
this.Port = new SerialPort();
//set properties
Port.BaudRate = (int)baudRate;
Port.DataBits = 8;
Port.Parity = Parity.None; //use 'None' when DataBits = 8; if DataBits = 7, use 'Even' or 'Odd'
Port.DtrEnable = true; //enable Data Terminal Ready
Port.Handshake = Handshake.None;
Port.PortName = portName;
Port.ReadTimeout = 200; //used when using ReadLine
Port.RtsEnable = true; //enable Request to send
Port.StopBits = StopBits.One;
Port.WriteTimeout = 50;
//open
Port.Open();
Listen();
}
private void Listen()
{
byte[] buffer = new byte[65536];
IAsyncResult result = Port.BaseStream.BeginRead(buffer, 0, buffer.Length, delegate (IAsyncResult ar)
{
try
{
if (Port.IsOpen)
{
int bytesRead = Port.BaseStream.EndRead(ar);
byte[] received = new byte[bytesRead];
Buffer.BlockCopy(buffer, 0, received, 0, bytesRead);
_dataReceived = System.Text.Encoding.UTF8.GetString(received);
Debug.WriteLine("Info: " + DateTime.Now.ToString("HH:mm:ss:fff") + " - _dataReceived: " + _dataReceived);
Listen();
}
}
catch (IOException ex)
{
Debug.WriteLine("Error (Listen) - " + ex.Message);
}
}, null);
}
public void Dispose()
{
if (Port != null)
{
Port.Close();
Port.Dispose();
Port = null;
}
}
}
}
更新
這是另一個似乎也能正常工作的版本——它使用了對您的代碼稍作修改的版本。
選項 2 :
HelperSerialPort.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.IO.Ports;
using System.Diagnostics;
namespace SerialPortTest
{
public enum PortBaudRate : int
{
Baud1200 = 1200,
Baud2400 = 2400,
Baud4800 = 4800,
Baud9600 = 9600,
Baud14400 = 14400,
Baud19200 = 19200,
Baud28800 = 28800,
Baud38400 = 38400,
Baud56000 = 56000,
Baud57600 = 57600,
Baud76800 = 76800,
Baud115200 = 115200,
Baud128000 = 128000,
Baud230400 = 230400,
Baud250000 = 250000,
Baud256000 = 256000
};
public class HelperSerialPort
{
public SerialPort Port { get; private set; } = null;
private string _dataReceived = string.Empty;
public HelperSerialPort(string portName, PortBaudRate baudRate = PortBaudRate.Baud9600)
{
Initialize(portName, baudRate);
}
private void Initialize(string portName, PortBaudRate baudRate = PortBaudRate.Baud9600)
{
//create new instance
this.Port = new SerialPort();
//set properties
Port.BaudRate = (int)baudRate;
Port.DataBits = 8;
Port.Parity = Parity.None; //use 'None' when DataBits = 8; if DataBits = 7, use 'Even' or 'Odd'
Port.DtrEnable = true; //enable Data Terminal Ready
Port.Handshake = Handshake.None;
Port.PortName = portName;
Port.ReadTimeout = 200; //used when using ReadLine
Port.RtsEnable = true; //enable Request to send
Port.StopBits = StopBits.One;
Port.WriteTimeout = 50;
//open
Port.Open();
SPDataHelper();
}
private void SPDataHelper()
{
byte[] buffer = new byte[65536];
Action kickoffRead = null;
kickoffRead = delegate
{
IAsyncResult result = Port.BaseStream.BeginRead(buffer, 0, buffer.Length, delegate (IAsyncResult ar)
{
try
{
if (Port.IsOpen)
{
int bytesRead = Port.BaseStream.EndRead(ar);
byte[] received = new byte[bytesRead];
Buffer.BlockCopy(buffer, 0, received, 0, bytesRead);
_dataReceived = System.Text.Encoding.UTF8.GetString(received);
Debug.WriteLine("Info: " + DateTime.Now.ToString("HH:mm:ss:fff") + " - _dataReceived: " + _dataReceived);
kickoffRead();
}
}
catch (IOException ex)
{
Debug.WriteLine("Error (SPDataHelper) - " + ex.Message);
}
}, null);
};
kickoffRead();
}
public void Dispose()
{
if (Port != null)
{
Port.Close();
Port.Dispose();
Port = null;
}
}
}
}
選項 3
這是一個使用 SerialPort DataReceived
的選項。
HelperSerialPort.cs :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.IO.Ports;
using System.Diagnostics;
namespace SerialPortTest
{
public enum PortBaudRate : int
{
Baud1200 = 1200,
Baud2400 = 2400,
Baud4800 = 4800,
Baud9600 = 9600,
Baud14400 = 14400,
Baud19200 = 19200,
Baud28800 = 28800,
Baud38400 = 38400,
Baud56000 = 56000,
Baud57600 = 57600,
Baud76800 = 76800,
Baud115200 = 115200,
Baud128000 = 128000,
Baud230400 = 230400,
Baud250000 = 250000,
Baud256000 = 256000
};
public class HelperSerialPort : IDisposable
{
public SerialPort Port { get; private set; } = null;
private string _dataReceived = string.Empty;
public HelperSerialPort(string portName, PortBaudRate baudRate = PortBaudRate.Baud9600)
{
Initialize(portName, baudRate);
}
private void Initialize(string portName, PortBaudRate baudRate = PortBaudRate.Baud9600)
{
//create new instance
this.Port = new SerialPort();
//set properties
Port.BaudRate = (int)baudRate;
Port.DataBits = 8;
Port.Parity = Parity.None; //use 'None' when DataBits = 8; if DataBits = 7, use 'Even' or 'Odd'
Port.DtrEnable = true; //enable Data Terminal Ready
Port.Handshake = Handshake.None;
Port.PortName = portName;
Port.ReadTimeout = 200; //used when using ReadLine
Port.RtsEnable = true; //enable Request to send
Port.StopBits = StopBits.One;
Port.WriteTimeout = 50;
//subscribe to events
Port.DataReceived += Port_DataReceived;
Port.ErrorReceived += Port_ErrorReceived;
//open
Port.Open();
}
private void Port_ErrorReceived(object sender, SerialErrorReceivedEventArgs e)
{
Debug.WriteLine("Error: (sp_ErrorReceived) - " + e.EventType);
}
private void Port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
_dataReceived = Port.ReadExisting();
Debug.WriteLine("Info: " + DateTime.Now.ToString("HH:mm:ss:fff") + " - _dataReceived: " + _dataReceived);
}
public void Dispose()
{
if (Port != null)
{
//unsubscribe from events
Port.DataReceived -= Port_DataReceived;
Port.ErrorReceived -= Port_ErrorReceived;
Port.Close();
Port.Dispose();
Port = null;
}
}
}
}
用法:
HelperSerialPort helper = new HelperSerialPort("COM1");
注意:確保在使用完 SerialPort 后調用Dispose
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.