基本的串口监听应用程序






4.87/5 (66投票s)
扫描已安装的串口,查询支持的波特率,并开始监听选定的串口。
引言
这是一个用 C# 实现的基本串口(COM 端口)监听示例。该应用程序连接到一个发送 ASCII 文本的 GPS 设备进行测试,但串口监听部分是完全基于字节的。
CodeProject 缺少一个简单的串口应用程序。串口监听应用程序通常只是一个更大解决方案的一部分,而此应用程序除了列出可用的 COM 端口、列出所选 COM 端口的可用波特率以及开始发送数据外,不执行任何其他操作。在这个解决方案中,一个窗体将数据转换为 ASCII 文本并在文本框中显示。
使用代码
串口处理代码被放置在一个名为 SerialPortManager
的类中。该类包含启动和停止监听串口数据的的方法。
查找已安装的串口
代码没有简单地假设串口的数量,也没有让用户事先知道,而是查找已安装的串口。通过在 SerialPortManager
类的构造函数中进行的调用,可以获得一个串口字符串数组。
public SerialPortManager()
{
// Finding installed serial ports on hardware
_currentSerialSettings.PortNameCollection =
System.IO.Ports.SerialPort.GetPortNames();
_currentSerialSettings.PropertyChanged +=
new System.ComponentModel.PropertyChangedEventHandler
(_currentSerialSettings_PropertyChanged);
// If serial ports is found, we select the first found
if (_currentSerialSettings.PortNameCollection.Length > 0)
_currentSerialSettings.PortName =
_currentSerialSettings.PortNameCollection[0];
}
更新所选设备支持的波特率
当用户选择一个串口时,会查询支持的波特率。根据硬件的不同,可能支持不同的波特率集合。从 COMMPROP 结构 中的 dwSettableBaud
字段是所有支持的波特率的集合。
private void UpdateBaudRateCollection()
{
_serialPort = new SerialPort(_currentSerialSettings.PortName);
_serialPort.Open();
// Getting COMMPROP structure, and its property dwSettableBaud.
object p = _serialPort.BaseStream.GetType().GetField("commProp",
BindingFlags.Instance | BindingFlags.NonPublic).GetValue(_serialPort.BaseStream);
Int32 dwSettableBaud = (Int32)p.GetType().GetField("dwSettableBaud",
BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public).GetValue(p);
_serialPort.Close();
_currentSerialSettings.UpdateBaudRateCollection(dwSettableBaud);
}
串口设置
名为 SerialSettings
的类包含当前选定的串口设置,还包括不同设置属性的替代列表。所有内容都数据绑定到 GUI。
开始监听串口
串口使用当前选定的设置实例化。
// Connects to a serial port defined through the current settings
public void StartListening()
{
// Closing serial port if it is open
if (_serialPort != null && _serialPort.IsOpen)
_serialPort.Close();
// Setting serial port settings
_serialPort = new SerialPort(
_currentSerialSettings.PortName,
_currentSerialSettings.BaudRate,
_currentSerialSettings.Parity,
_currentSerialSettings.DataBits,
_currentSerialSettings.StopBits);
// Subscribe to event and open serial port for data
_serialPort.DataReceived +=
new SerialDataReceivedEventHandler(_serialPort_DataReceived);
_serialPort.Open();
}
实际的串口读取
实际的串口读取在线程池中运行。当串口接收到数据时,会引发一个事件并调用 _serialPort_DataReceived
。
void _serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
int dataLength = _serialPort.BytesToRead;
byte[] data = new byte[dataLength];
int nbrDataRead = _serialPort.Read(data, 0, dataLength);
if (nbrDataRead == 0)
return;
// Send data to whom ever interested
if (NewSerialDataRecieved != null)
NewSerialDataRecieved(this, new SerialDataEventArgs(data));
}
接收到的字节数组被发送给监听该事件的那些对象。SerialDataEventArgs
类包含一个字节数组。
停止监听
我们通过简单地关闭串口来停止监听。请注意,如果您在窗体中的事件处理中使用 Invoke
,这可能会导致 UI 线程死锁。
/// Closes the serial port
public void StopListening()
{
_serialPort.Close();
}
为了解决这种可能的死锁,需要使用 BeginInvoke
。而且,这通常也是一个好的做法。
if (this.InvokeRequired)
{
// Using this.Invoke causes deadlock when closing serial port,
// and BeginInvoke is good practice anyway.
this.BeginInvoke(new EventHandler<SerialDataEventArgs>(
_spManager_NewSerialDataRecieved), new object[] { sender, e });
return;
}
摘要
提供了一个如何实现串口监听的相当简单的示例。
更新
- 2010 年 4 月 27 日 - 代码清理,并使 < > 在文章中显示。
- 2010 年 5 月 10 日 - 修复文章中的一些拼写错误。