SerialPort类的用法与示例
文章目录
- SerialPort类的用法与示例
-
-
- 1. 串口硬件信号定义
- 2. 串口端口号搜索
- 3. 串口属性参数设置
- 4. 串口发送信息
- 5. 串口接收信息
- 串口工具类
- 串口使用注意事项
-
从Microsoft .Net 2.0版本以后,就默认提供了 System.IO.Ports.SerialPort类,用户可以非常简单地编写少量代码就完成串口的信息收发程序。本文将介绍如何在PC端用C# .Net 来开发串口应用程序。
1. 串口硬件信号定义
DB9 Connector 信号定义
文章图片
针脚 | 信号 | 定义 | 作用 |
---|---|---|---|
1 | DCD | 载波检测 | Received Line Signal Detector(Data Carrier Detect) |
2 | RXD | 接收数据 | Received Data |
3 | TXD | 发送数据 | Transmit Data |
4 | DTR | 数据终端准备好 | Data Terminal Ready |
5 | SGND | 信号地 | Signal Ground |
6 | DSR | 数据准备好 | Data Set Ready |
7 | RTS | 请求发送 | Request To Send |
8 | CTS | 清除发送 | Clear To Send |
9 | RI | 振铃提示 | Ring Indicator |
一个最简单的办法:
string[] portList = System.IO.Ports.SerialPort.GetPortNames();
// 静态方法
还有一种通过调用API的方法来获取实现,可以获取详细的完整串口名称,对于USB-to-COM虚拟串口来说特别适用。它可以获取到与设备管理器中一样的名字,例如“Prolific USB-to-Serial Comm Port(COM34)”, 而上面的方法只能获取到“COM34”。
3. 串口属性参数设置
SerialPort类所包含的属性详见下表:
名称 | 说明 | |
---|---|---|
BaseStream | 获取 Stream 对象的基础 SerialPort 对象。 | |
BaudRate | 获取或设置串行波特率。 | |
BreakState | 获取或设置中断信号状态。 | |
BytesToRead | 获取接收缓冲区中数据的字节数。 | |
BytesToWrite | 获取发送缓冲区中数据的字节数。 | |
CanRaiseEvents | 获取一个值,该值指示组件是否可以引发一个事件。(继承自 Component。) | |
CDHolding | 获取端口的载波检测行的状态。 | |
Container | 获取 IContainer ,其中包含 Component。(继承自 Component。) | |
CtsHolding | 获取“可以发送”行的状态。 | |
DataBits | 获取或设置每个字节的标准数据位长度。 | |
DesignMode | 获取一个值,该值指示是否 Component 当前处于设计模式。(继承自 Component。) | |
DiscardNull | 获取或设置一个值,该值指示 null 字节在端口和接收缓冲区之间传输时是否被忽略。 | |
DsrHolding | 获取数据设置就绪 (DSR) 信号的状态。 | |
DtrEnable | 获取或设置一个值,该值在串行通信过程中启用数据终端就绪 (DTR) 信号。 | |
Encoding | 获取或设置传输前后文本转换的字节编码。 | |
Events | 获取的事件处理程序附加到此列表 Component。(继承自 Component。) | |
Handshake | 使用 Handshake 中的值获取或设置串行端口数据传输的握手协议。 | |
IsOpen | 获取一个值,该值指示 SerialPort 对象的打开或关闭状态。 | |
NewLine | 获取或设置用于解释 ReadLine 和 WriteLine 方法调用结束的值。 | |
Parity | 获取或设置奇偶校验检查协议。 | |
ParityReplace | 获取或设置一个字节,该字节在发生奇偶校验错误时替换数据流中的无效字节。 | |
PortName | 获取或设置通信端口,包括但不限于所有可用的 COM 端口。 | |
ReadBufferSize | 获取或设置 SerialPort 输入缓冲区的大小。 | |
ReadTimeout | 获取或设置读取操作未完成时发生超时之前的毫秒数。 | |
ReceivedBytesThreshold | 获取或设置 DataReceived 事件发生前内部输入缓冲区中的字节数。 | |
RtsEnable | 获取或设置一个值,该值指示在串行通信中是否启用请求发送 (RTS) 信号。 | |
Site | 获取或设置 ISite 的 Component。(继承自 Component。) | |
StopBits | 获取或设置每个字节的标准停止位数。 | |
WriteBufferSize | 获取或设置串行端口输出缓冲区的大小。 | |
WriteTimeout | 获取或设置写入操作未完成时发生超时之前的毫秒数。 |
SerialPort mySerialPort = new SerialPort("COM2");
// 构造参数指定串口名
//serialPort.PortName = "COM2";
mySerialPort.BaudRate = 9600;
mySerialPort.Parity=Parity.None;
mySerialPort.StopBits = StopBits.One;
mySerialPort.DataBits = 8;
mySerialPort.Open();
// 打开串口// DataReceived是串口类的一个事件,通过+=运算符订阅事件,如果串口接收到数据就触发事件,调用DataReceive_Method事件处理方法
mySerialPort.DataReceived += new SerialDataReceivedEvenHandler(DataReceive_Method);
// 事件处理方法
public static void DataReceive_Method(object sender, SerialDataReceivedEventArgs e)
{
//sender是事件触发对象,通过它可以获取到mySerialPort
SerialPort mySerialPort = (SerialPort)sender;
}mySerialPort.Close();
// 关闭串口
4. 串口发送信息
SerialPort类定义了多种方法用于串口发送信息。
Write(Byte[], Int32, Int32)
使用缓冲区中的数据将指定数量的字节写入串行端口【C#|SerialPort类的用法与示例】注意一字节(Byte)是8个比特(bit),而一个十六进制数是4个比特,两个十六进制数就是8个比特,即一个字节。所以要想发送十六进制数就得用写入字节的函数。
byte[] t = new byte[2];
t[0] = 0xAA;
t[1] = 0xBB;
串口对象.Write(t,0,2);
==
Write(Char[], Int32, Int32)
==使用缓冲区中的数据将指定数量的字符写入串行端口==
Write(String)
==将指定的字符串写入串行端口==
WriteLine(String)
==将指定的字符串和NewLine值写入输出缓冲区下面是一个简单的例子说明如何通过串口发送字符串和字节数据:
private static void SendSampleData()
{
SerialPort port = new SerialPort(
"COM1", 9600, Parity.None, 8, StopBits.One);
port.Open();
port.Write("Hello World");
port.Write(new byte[] { 0x0A, 0xE2, 0xFF }, 0, 3);
port.Close();
}
下面是如何发送一个文本文件的例子:
private static void SendTextFile(SerialPort port, string FileName)
{
port.Write(File.OpenText(FileName).ReadToEnd());
}
下面是如何发送一个二进制文件的例子:
private static void SendBinaryFile(SerialPort port, string FileName)
{
using (FileStream fs = File.OpenRead(FileName))
port.Write((new BinaryReader(fs)).ReadBytes((int)fs.Length), 0, (int)fs.Length);
}
5. 串口接收信息
SerialPort类定义了多种方法用于串口接收信息。
Read(Byte[], Int32, Int32)
从SerialPort输入缓冲区读取一些字节,并将那些字节写入字节数组中指定的偏移量处Read(Byte[], Int32, Int32)
从SerialPort输入缓冲区读取一些字符,并将那些字符写入字符数组中指定的偏移量处ReadByte()
从SerialPort输入缓冲区中同步读取一个字节ReadChar()
从SerialPort输入缓冲区中同步读取一个字符ReadExisting()
在编码的基础上,读取SerialPort对象的流和输入缓冲区中所有立即可用的字节ReadLine()
一直读取到输入缓冲区中的NewLine值ReadTo(String)
一直读取到输入缓冲区中的指定value的字符串通常一个比较常见的用法就是将串口里面立即能用的字符或数据读取然后打印在textbox等控件中显示。
private SerialPort port = new SerialPort("COM1",
9600, Parity.None, 8, StopBits.One);
port.DataReceived += new
SerialDataReceivedEventHandler(port_DataReceived);
port.Open();
private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
Console.WriteLine(port.ReadExisting());
}
另外还有一种应用场合是需要缓存一段串口接收数据,然后在缓存数据中查找有用信息,这时可以采用下面例子所用的办法。
SerialPort com = new SerialPort(SerialPort.GetPortNames()[0],
9600, Parity.None, 8, StopBits.One);
List bBuffer = new List();
string sBuffer = String.Empty;
com.DataReceived += new SerialDataReceivedEventHandler(com_DataReceived);
com.Open();
void com_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
while (com.BytesToRead > 0)
bBuffer.Add((byte)com.ReadByte());
ProcessBuffer(bBuffer);
sBuffer += com.ReadExisting();
ProcessBuffer(sBuffer);
}private void ProcessBuffer(string sBuffer)
{}private void ProcessBuffer(List bBuffer)
{}
串口工具类
public class SerialPortUtils
{
public static SerialPort serialPort = null;
// 定义一个静态的串口对象///
/// 搜索串口
///
///
public static string[] GetPortNames()
{
return SerialPort.GetPortNames();
}///
/// 打开或者关闭串口
///
///
///
///
public static SerialPort OpenClosePort(string comName, int baud)
{
//串口未打开
if (serialPort == null || !serialPort.IsOpen)
{
serialPort = new SerialPort();
//串口名称
serialPort.PortName = comName;
//波特率
serialPort.BaudRate = baud;
//数据位
serialPort.DataBits = 8;
//停止位
serialPort.StopBits = StopBits.One;
//校验位
serialPort.Parity = Parity.None;
//打开串口
serialPort.Open();
//串口数据接收事件实现
serialPort.DataReceived += new SerialDataReceivedEventHandler(ReceiveData);
return serialPort;
}
//串口已经打开
else
{
serialPort.Close();
return serialPort;
}
}///
/// 接收数据
///
///
///
public static void ReceiveData(object sender, SerialDataReceivedEventArgs e)
{
SerialPort _SerialPort = (SerialPort)sender;
int _bytesToRead = _SerialPort.BytesToRead;
byte[] recvData = https://www.it610.com/article/new byte[_bytesToRead];
_SerialPort.Read(recvData, 0, _bytesToRead);
//向控制台打印数据
Debug.WriteLine("收到数据:" + recvData);
}///
/// 发送数据
///
///
///
public static bool SendData(byte[] data)
{
if (serialPort != null && serialPort.IsOpen)
{
serialPort.Write(data, 0, data.Length);
Debug.WriteLine("发送数据:" + data);
return true;
}
else
{
return false;
}
}
}
串口使用注意事项
参考:https://blog.csdn.net/wuyazhe/article/details/5606276
Open()打开串口的时候会创建一个监听线程ListenThread,DataReceived事件就是在这个线程进行处理的,与此同时还有一个主线程即UIThread,这个时候要注意线程同步问题。
在DataReceived事件处理函数中,一般是调用Read()方法读取串口缓存区数据,读取完后进行容错处理,之后解析数据,解析完成后更新UI。在监听线程中是无法更新主线程的UI的,所以必须调用Invoke方法回到主线程更新UI。但是由于Invoke是同步函数,在UI未完成更新之前,监听线程一直停在DataReceived事件处理函数中。此时主线程如果调用Close()函数关闭串口,由于监听线程的资源还没来得及释放,造成死锁。
解决方法就是用BeginInvoke异步调用去更新UI。
推荐阅读
- c#|C#中如何将字符串转换成流,同时如何将流转换成字符串()
- C#速成指南(从入门到进阶,实战WPF与Unity3D开发吾爱)
- 正则表达式|c#正则表达式——匹配不同类型的一个字符
- C#|C# 正则替换 Regex.Replace
- WPF|基于WPF的桌面宠物开发(一) (WPF简介+环境搭建+简单界面)
- c#|VS册程序设计C#---问卷调查系统
- c#课设|c#单机考试系统
- OpenCV|OpenCV在图像上画正弦曲线(c++)
- 数据结构|数据结构课程设计——学生成绩查询与分析系统(简单详细版,含讲解)