【发布时间】:2010-11-17 14:27:45
【问题描述】:
我刚刚开始学习如何通过 C# GUI 从我的硬件发送和接收数据。
谁能详细说明如何读取串口数据?
【问题讨论】:
-
Managing serial ports in C# 的可能重复项
-
反过来:链接的帖子是这个帖子的副本。请将此问题用作规范副本。
标签: c# serial-port
我刚刚开始学习如何通过 C# GUI 从我的硬件发送和接收数据。
谁能详细说明如何读取串口数据?
【问题讨论】:
标签: c# serial-port
SerialPort (RS-232 Serial COM Port) in C# .NET
本文介绍如何使用 .NET 中的SerialPort 类来读取和写入数据,确定您的机器上可用的串行端口,以及如何发送文件。它甚至涵盖了端口本身的引脚分配。
示例代码:
using System;
using System.IO.Ports;
using System.Windows.Forms;
namespace SerialPortExample
{
class SerialPortProgram
{
// Create the serial port with basic settings
private SerialPort port = new SerialPort("COM1",
9600, Parity.None, 8, StopBits.One);
[STAThread]
static void Main(string[] args)
{
// Instatiate this class
new SerialPortProgram();
}
private SerialPortProgram()
{
Console.WriteLine("Incoming Data:");
// Attach a method to be called when there
// is data waiting in the port's buffer
port.DataReceived += new
SerialDataReceivedEventHandler(port_DataReceived);
// Begin communications
port.Open();
// Enter an application loop to keep this thread alive
Application.Run();
}
private void port_DataReceived(object sender,
SerialDataReceivedEventArgs e)
{
// Show all the incoming data in the port's buffer
Console.WriteLine(port.ReadExisting());
}
}
}
【讨论】:
我花了很多时间来使用SerialPort 类,并最终决定改用SerialPort.BaseStream 类。可以看源码:SerialPort-source 和 SerialPort.BaseStream-source 深入了解。 我创建并使用了如下所示的代码。
核心功能
public int Recv(byte[] buffer, int maxLen)
名称和工作方式类似于“知名”套接字的recv()。
意思是
TimeoutException。maxLen字节.
public class Uart : SerialPort
{
private int _receiveTimeout;
public int ReceiveTimeout { get => _receiveTimeout; set => _receiveTimeout = value; }
static private string ComPortName = "";
/// <summary>
/// It builds PortName using ComPortNum parameter and opens SerialPort.
/// </summary>
/// <param name="ComPortNum"></param>
public Uart(int ComPortNum) : base()
{
base.BaudRate = 115200; // default value
_receiveTimeout = 2000;
ComPortName = "COM" + ComPortNum;
try
{
base.PortName = ComPortName;
base.Open();
}
catch (UnauthorizedAccessException ex)
{
Console.WriteLine("Error: Port {0} is in use", ComPortName);
}
catch (Exception ex)
{
Console.WriteLine("Uart exception: " + ex);
}
} //Uart()
/// <summary>
/// Private property returning positive only Environment.TickCount
/// </summary>
private int _tickCount { get => Environment.TickCount & Int32.MaxValue; }
/// <summary>
/// It uses SerialPort.BaseStream rather SerialPort functionality .
/// It Receives up to maxLen number bytes of data,
/// Or throws TimeoutException if no any data arrived during ReceiveTimeout.
/// It works likes socket-recv routine (explanation in body).
/// Returns:
/// totalReceived - bytes,
/// TimeoutException,
/// -1 in non-ComPortNum Exception
/// </summary>
/// <param name="buffer"></param>
/// <param name="maxLen"></param>
/// <returns></returns>
public int Recv(byte[] buffer, int maxLen)
{
/// The routine works in "pseudo-blocking" mode. It cycles up to first
/// data received using BaseStream.ReadTimeout = TimeOutSpan (2 ms).
/// If no any message received during ReceiveTimeout property,
/// the routine throws TimeoutException
/// In other hand, if any data has received, first no-data cycle
/// causes to exit from routine.
int TimeOutSpan = 2;
// counts delay in TimeOutSpan-s after end of data to break receive
int EndOfDataCnt;
// pseudo-blocking timeout counter
int TimeOutCnt = _tickCount + _receiveTimeout;
//number of currently received data bytes
int justReceived = 0;
//number of total received data bytes
int totalReceived = 0;
BaseStream.ReadTimeout = TimeOutSpan;
//causes (2+1)*TimeOutSpan delay after end of data in UART stream
EndOfDataCnt = 2;
while (_tickCount < TimeOutCnt && EndOfDataCnt > 0)
{
try
{
justReceived = 0;
justReceived = base.BaseStream.Read(buffer, totalReceived, maxLen - totalReceived);
totalReceived += justReceived;
if (totalReceived >= maxLen)
break;
}
catch (TimeoutException)
{
if (totalReceived > 0)
EndOfDataCnt--;
}
catch (Exception ex)
{
totalReceived = -1;
base.Close();
Console.WriteLine("Recv exception: " + ex);
break;
}
} //while
if (totalReceived == 0)
{
throw new TimeoutException();
}
else
{
return totalReceived;
}
} // Recv()
} // Uart
【讨论】:
请注意,SerialPort.DataReceived 事件的使用是可选的。您可以使用SerialPort.ReadTimeout 设置适当的超时时间,并在向端口写入内容后连续调用SerialPort.Read(),直到获得完整响应。
此外,您可以使用SerialPort.BaseStream 属性来提取底层Stream 实例。使用Stream 的好处是您可以轻松地使用各种装饰器:
var port = new SerialPort();
// LoggingStream inherits Stream, implements IDisposable, needen abstract methods and
// overrides needen virtual methods.
Stream portStream = new LoggingStream(port.BaseStream);
portStream.Write(...); // Logs write buffer.
portStream.Read(...); // Logs read buffer.
更多信息请查看:
【讨论】: