【自己动手写上位机】串口通信
简单介绍
串口通信是指采用串行通信协议(serial communication)在一条信号线上
将数据一个比特一个比特地逐位进行传输的通信模式。
串口通信最重要的参数是波特率、数据位、停止位和奇偶校验。
对于两个进行通信的端口,这些参数必须匹配。
更深的概念自行百度。
一般的串口调试工具都是默认数据位为8,停止位1,奇偶校验0
C#串口类:SerialPort
编写串口助手时,可能会用到的一些属性和方法。
构造函数:
名称 | 描述 | |
---|---|---|
SerialPort() | 初始化 SerialPort 类的新实例。 | |
SerialPort(String) | 使用指定的端口名初始化 SerialPort 类的新实例。 | |
SerialPort(String, Int32) | 使用指定的端口名和波特率初始化 SerialPort 类的新实例。 | |
SerialPort(String, Int32, Parity) | 使用指定的端口名、波特率和奇偶校验位初始化 SerialPort 类的新实例。 | |
SerialPort(String, Int32, Parity, Int32) | 使用指定的端口名、波特率、奇偶校验位和数据位初始化SerialPort 类的新实例。 | |
SerialPort(String, Int32, Parity, Int32, StopBits) | 使用指定的端口名、波特率、奇偶校验位、数据位和停止位初始化 SerialPort 类的新实例。 |
属性:
名称 | 描述 | |
---|---|---|
BaudRate | 获取或设置串行波特率。 | |
BytesToRead | 获取接收缓冲区中数据的字节数。 | |
Handshake | 使用 Handshake 中的值获取或设置串行端口数据传输的握手协议。 | |
IsOpen | 获取一个值,该值指示 SerialPort 对象的打开或关闭状态。 | |
NewLine | 获取或设置用于解释 ReadLine 和 WriteLine 方法调用结束的值。 | |
Parity | 获取或设置奇偶校验检查协议。 | |
PortName | 获取或设置通信端口,包括但不限于所有可用的 COM 端口。 | |
ReadBufferSize | 获取或设置 SerialPort 输入缓冲区的大小。 | |
ReadTimeout | 获取或设置读取操作未完成时发生超时之前的毫秒数。 | |
ReceivedBytesThreshold | 获取或设置 DataReceived 事件发生前内部输入缓冲区中的字节数。 | |
StopBits | 获取或设置每个字节的标准停止位数。 | |
WriteBufferSize | 获取或设置串行端口输出缓冲区的大小。 | |
WriteTimeout | 获取或设置写入操作未完成时发生超时之前的毫秒数。 |
方法:
名称 | 描述 | |
---|---|---|
Close | 关闭端口连接,将 IsOpen 属性设置为 false,并释放内部Stream 对象。 | |
GetPortNames | 获取当前计算机的串行端口名的数组。 | |
MemberwiseClone(Boolean) | 创建当前 MarshalByRefObject 对象的浅表副本。 (继承自MarshalByRefObject。) | |
Open | 打开一个新的串行端口连接。 | |
Read(Byte[], Int32, Int32) | 从 SerialPort 输入缓冲区读取一些字节并将那些字节写入字节数组中指定的偏移量处。 | |
Read(Char[], Int32, Int32) | 从 SerialPort 输入缓冲区中读取一些字符,然后将这些字符写入字符数组中指定的偏移量处。 | |
ReadByte | 从 SerialPort 输入缓冲区中同步读取一个字节。 | |
ReadChar | 从 SerialPort 输入缓冲区中同步读取一个字符。 | |
ReadExisting | 在编码的基础上,读取 SerialPort 对象的流和输入缓冲区中所有立即可用的字节。 | |
ReadLine | 一直读取到输入缓冲区中的 NewLine 值。 | |
ReadTo | 一直读取到输入缓冲区中的指定 value 的字符串。 | |
Write(String) | 将指定的字符串写入串行端口。 | |
Write(Byte[], Int32, Int32) | 使用缓冲区中的数据将指定数量的字节写入串行端口。 | |
Write(Char[], Int32, Int32) | 使用缓冲区中的数据将指定数量的字符写入串行端口。 | |
WriteLine | 将指定的字符串和 NewLine 值写入输出缓冲区。 |
SerialPort类并不一定符合我们的需求,个人喜欢封装为新的类实现一些自定义功能,
而且封装会使程序比较模块化,清晰方便。当然,不封装也行。
接下来,对SerialPort类进行封装:
我将新类命名为Comm,使它继承SerialPort类
public class Comm : SerialPort
{
}
接收数据缓存
public StringBuilder RevData;//接收的数据
发送、接收字节计数:
public ulong SendCount
{
set;
get;
}
public ulong GetCount
{
set;
get;
}
计数清零:
public void ClearCount()
{
SendCount = 0;
GetCount = 0;
}
设置串口类基本参数:
该方面用来设置串口的基本参数,由于Parity(校验)和StopBit(停止位)是枚举类型,所以需要用switch判断语句
public void CommSetting(String port, String baudRate, String dataBit, String parity, String stopBit)
{
PortName = port;
BaudRate = int.Parse(baudRate);
DataBits = int.Parse(dataBit);
switch (parity)
{
case "无":
Parity = Parity.None; break;
case "奇校验":
Parity = Parity.Odd; break;
case "偶校验":
Parity = Parity.Even; break;
}
switch (stopBit)
{
case "1":
StopBits = StopBits.One; break;
case "1.5":
StopBits = StopBits.OnePointFive; break;
case "2":
StopBits = StopBits.Two; break;
}
}
发送、接收是否是十六进制:
public bool IsHexData
{
get;
set;
}
public bool RevIsHexData
{
get;
set;
}
是否自动换行:
public bool SendNewLine
{
get;
set;
}
串口发送:
串口发送有16进制和字符串两种方式,需要说明的是,
以字符串形式发送时需要使用Encoding.Default.GetBytes()对字符串进行字符编码,
在接收也需要相同函数进行字符解码,这样中文就不会出现乱码了
public void WriteData(string data)
{
if (IsHexData)
{
MatchCollection mc = Regex.Matches(data, @"(?i)[\da-f]{2}");
List<byte> buf = new List<byte>();//填充到这个临时列表中
//依次添加到列表中
foreach (Match m in mc)
{
buf.Add(byte.Parse(m.Value, System.Globalization.NumberStyles.HexNumber));
}
if (SendNewLine)
{
buf.Add(0x0A);
// buf.Add(0x0D);
}
//转换列表为数组后发送
this.Write(buf.ToArray(), 0, buf.Count);
SendCount = SendCount + (ulong)buf.Count;
}
else
{
byte[] bf = new byte[data.Length];
bf = Encoding.Default.GetBytes(data);
this.Write(bf, 0, bf.Length);
if (SendNewLine)
{
this.Write("\r\n");
SendCount = SendCount + 2;
}
SendCount = SendCount + (ulong)bf.Length;
}
}