C# 如何从串口读写
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1243070/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to Read and Write from the Serial Port
提问by
I just start to learn how to send and receive data from my hardware through the C# GUI.
我刚刚开始学习如何通过 C# GUI 从我的硬件发送和接收数据。
Can anyone please write a detail how to readdata from the serial port?
谁能写一个详细的如何从串口读取数据?
回答by Robert Harvey
SerialPort (RS-232 Serial COM Port) in C# .NET
This article explains how to use the SerialPort
class in .NET to read and write data, determine what serial ports are available on your machine, and how to send files. It even covers the pin assignments on the port itself.
C# .NET 中的 SerialPort(RS-232 串行 COM 端口)
本文解释了如何使用SerialPort
.NET 中的类来读取和写入数据、确定您的机器上可用的串行端口以及如何发送文件。它甚至涵盖了端口本身的引脚分配。
Example Code:
示例代码:
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());
}
}
}
回答by Leonid Vasilev
Note that usage of a SerialPort.DataReceived
event is optional. You can set proper timeout using SerialPort.ReadTimeout
and continuously call SerialPort.Read()
after you wrote something to a port until you get a full response.
请注意,SerialPort.DataReceived
事件的使用是可选的。您可以使用设置适当的超时SerialPort.ReadTimeout
并SerialPort.Read()
在向端口写入内容后继续调用,直到获得完整响应。
Moreover you can use SerialPort.BaseStream
property to extract an underlying Stream
instance. The benefit of using a Stream
is that you can easily utilize various decorators with it:
此外,您可以使用SerialPort.BaseStream
属性来提取底层Stream
实例。使用 a 的好处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.
For more information check:
有关更多信息,请检查:
- Top 5 SerialPort Tipsarticle by Kim Hamilton, BCL Team Blog
- C# await event and timeout in serial port communicationdiscussion on StackOverflow
- Kim Hamilton 的5 大串行端口技巧文章,BCL 团队博客
- C# await 事件和超时在StackOverflow 上的串行端口通信讨论中
回答by Yakov
I spent a lot of time to use SerialPortclass and has concluded to use SerialPort.BaseStreamclass instead. You can see source code: SerialPort-sourceand SerialPort.BaseStream-sourcefor deep understanding. I created and use code that shown below.
我花了很多时间来使用SerialPort类,最终决定使用SerialPort.BaseStream类。可以看源码:SerialPort-source和 SerialPort.BaseStream-source深入理解。我创建并使用了如下所示的代码。
The core function
public int Recv(byte[] buffer, int maxLen)
has name and works like "well known" socket'srecv()
.It means that
- in one hand it has timeout for no any data and throws
TimeoutException
. - In other hand, when any data has received,
- it receives data either until
maxLen
bytes - or short timeout (theoretical 6 ms) in UART data flow
- it receives data either until
- in one hand it has timeout for no any data and throws
核心函数
public int Recv(byte[] buffer, int maxLen)
具有名称,其工作方式类似于“众所周知的”套接字的recv()
.这意味着
- 一方面,它没有任何数据并抛出超时
TimeoutException
。 - 另一方面,当接收到任何数据时,
- 它接收数据直到
maxLen
字节 - 或 UART 数据流中的短超时(理论 6 ms)
- 它接收数据直到
- 一方面,它没有任何数据并抛出超时
.
.
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