65.9K
CodeProject 正在变化。 阅读更多。
Home

基本的串口监听应用程序

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.87/5 (66投票s)

2010 年 4 月 26 日

CPOL

2分钟阅读

viewsIcon

556445

downloadIcon

81931

扫描已安装的串口,查询支持的波特率,并开始监听选定的串口。

SerialPortListenerApp

引言

这是一个用 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 日 - 修复文章中的一些拼写错误。
© . All rights reserved.