串口是串行接口(Serial Port) 的简称,是一种常用于电子设备间通讯的全双工扩展接口。常见的有RS-232标准一般应用在计算机与外部设备之间进行数据传输(有25针或9针连接器)。我们现在的计算机基本上已经看不到串口,我们可以通过USB适配器来将COM端口转换为USB接口进行连接。今天我们来了解.NET 如何用C#语言编写代码实现与这些设备进行通信。
串口通信包括通信时序、通讯速率、数据传输。
常用的通讯速率有2400bps、4800bps、9600bps、19200bps、38400bps、115200bps。
我们通过下图对串口的通信时序进行简单了解,串口时序由起始位、数据位、校验位、停止位组成。
下表对时序组成进行说明
名称 | 描述 |
---|---|
起始位 | 占用1位,低电平有效。 |
数据位 | 可以是5位、6位、7位、8位,其中最常用为8位。 |
校验位 | 占用1位,无校验位时不占用。 |
偶校验(even parity):校验原则是,数据位和校验位中1的个数为偶数 | |
奇校验(odd parity):校验原则是,数据位和校验位中1的个数为奇数 | |
无校验(odd parity):即时序图中没有校验位 | |
(Space):校验位总为0 | |
(Mark):校验位总为1 | |
停止位 | 占用1位、1.5位、2位,高电平有效 |
.NET的框架类库提供了SerialPort类,可用SerialPort类来配置和管理串口的属性,可用于发送和接收数据。SerialPort类的常用属性包括PortName、BaudRate、Parity、DataBits、StopBits、Handshake、ReadTimeout和WriteTimeout等。这些属性用于指定串口的名称、波特率、校验位、数据位、停止位、握手协议以及读取和写入数据时的超时时间等。
属性
红色是类常用的属性,在我们使用类时根据连接设备情况进行属性的配置。
方法
我们先配置类的属性,然后使用 Open() 方法打开串口,使用 Write() 方法发送数据,使用 Read() 方法读取数据,并使用 Close() 方法关闭串口。
事件
在发送和接收数据时,我们也可以使用事件来处理数据的到达和发送完成。
我们先定义波特率与数据位二个枚举类型:
///
/// 波特率
///
[Serializable]
public enum BaudRates
{
Baud1200 = 1200,
Baud2400 = 2400,
Baud4800 = 4800,
Baud9600 = 9600,
Baud14400 = 14400,
Baud19200 = 19200,
Baud38400 = 38400,
Baud115200 = 115200
}
///
/// 数据位
///
[Serializable]
public enum DataBits
{
///
/// 5位
///
Bit5=5,
///
/// 6位
///
Bit6 = 6,
///
/// 7位
///
Bit7 = 7,
///
/// 8位
///
Bit8 = 8
}
我这将对串口的操作封装在一个类上。
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO.Ports;
namespace Fountain.Net.Core.Com
{
///
/// 串空操作
///
public class OperationSerialPort
{
///
/// 数据接收
///
public event Action>? DataReceived;
///
/// 接收异常
///
public event SerialErrorReceivedEventHandler? ErrorReceived;
///
/// 定义一个对象
///
private SerialPort _SerialPort = new SerialPort();
private string _PortName = string.Empty;
///
/// 串口名称
///
public string PortName
{
get { return _PortName; }
set { _PortName = value; }
}
private BaudRates _BaudRate = BaudRates.Baud9600;
///
/// 波特率
///
public BaudRates BaudRate
{
get { return _BaudRate; }
set { _BaudRate = value; }
}
private Parity _Parity = Parity.None;
///
/// 校验位
///
public Parity Parity
{
get { return _Parity; }
set { _Parity = value; }
}
private StopBits _StopBits = StopBits.One;
///
/// 停止位
///
public StopBits StopBits
{
get { return _StopBits; }
set { _StopBits = value; }
}
private DataBits _DataBits = DataBits.Bit8;
///
/// 数据位
///
public DataBits DataBits
{
get { return _DataBits; }
set { _DataBits = value; }
}
///
/// 无参构造函数
///
public OperationSerialPort()
{
BoundEvents();
}
///
/// 绑定事件
///
private void BoundEvents()
{
this._SerialPort.DataReceived += new SerialDataReceivedEventHandler(SerialPort_DataReceived);
this._SerialPort.ErrorReceived += new SerialErrorReceivedEventHandler(SerialPort_ErrorReceived);
}
///
/// 存放接收待分析的字节
///
List _StoreReceivedbytes = new List();
///
/// 接收数据
///
private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
Thread.Sleep(80);
// 检查串口是否打开
if (this._SerialPort.IsOpen)
{
// 创建接收字节数组
Byte[] receivedBuffer = new Byte[this._SerialPort.BytesToRead];
// 读取数据
this._SerialPort.Read(receivedBuffer, 0, receivedBuffer.Length);
if (this.DataReceived != null)
{
// 数据处理 根据设备返回进行 我这里简单处理
string objReceiveWeight = Encoding.Default.GetString(receivedBuffer);
this._StoreReceivedbytes.Add(objReceiveWeight);
this.DataReceived(this._StoreReceivedbytes);
}
}
}
catch
{
}
}
///
/// 错误处理函数
///
private void SerialPort_ErrorReceived(object sender, SerialErrorReceivedEventArgs e)
{
if (this.ErrorReceived != null)
{
this.ErrorReceived(sender, e);
}
}
///
/// 端口是否已经打开
///
public bool IsOpen
{
get
{
return this._SerialPort.IsOpen;
}
}
///
/// 打开端口
///
///
public void Open()
{
try
{
if (this._SerialPort.IsOpen)
{
this._SerialPort.Close();
}
this._SerialPort.PortName = this._PortName;
this._SerialPort.BaudRate = (int)this._BaudRate;
this._SerialPort.Parity = this._Parity;
this._SerialPort.DataBits = (int)this._DataBits;
this._SerialPort.StopBits = this._StopBits;
this._SerialPort.Open();
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
///
/// 关闭端口
///
public void Close()
{
try
{
if (this._SerialPort.IsOpen)
{
this._SerialPort.DataReceived -= new SerialDataReceivedEventHandler(SerialPort_DataReceived);
this._SerialPort.ErrorReceived -= new SerialErrorReceivedEventHandler(SerialPort_ErrorReceived);
this._SerialPort.DiscardOutBuffer();
this._SerialPort.DiscardInBuffer();
this._SerialPort.Close();
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
///
///
///
public void DiscardBuffer()
{
this._SerialPort.DiscardInBuffer();
this._SerialPort.DiscardOutBuffer();
}
///
/// 写入数据
///
/// 字节数组
public void Write(byte[] writeBuffer, int offset, int count)
{
try
{
if (!(this._SerialPort.IsOpen))
{
this._SerialPort.Open();
}
this._SerialPort.Write(writeBuffer, offset, count);
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
///
/// 写入数据
///
/// 字节数组
public void Write(byte[] writeBuffer)
{
try
{
if (!(this._SerialPort.IsOpen))
{
this._SerialPort.Open();
}
this._SerialPort.Write(writeBuffer, 0, writeBuffer.Length);
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
///
/// 串口名称
///
///
public static List GetPortNames()
{
try
{
List portNameList = new List();
foreach (string portname in SerialPort.GetPortNames())
{
portNameList.Add(portname);
}
return portNameList;
}
catch(Exception ex)
{
throw new Exception(ex.Message);
}
}
///
/// 获取波特率
///
///
public static List GetBauRates()
{
try
{
List baudRatesList = new List();
foreach (BaudRates baudrate in Enum.GetValues(typeof(BaudRates)))
{
baudRatesList.Add((int)baudrate);
}
return baudRatesList;
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
///
/// 获取校验位
///
///
public static List GetParitys()
{
try
{
List paritysList = new List();
foreach (string parity in Enum.GetNames(typeof(Parity)))
{
paritysList.Add(parity);
}
return paritysList;
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
///
/// 获取数据位
///
public static List GetDataBits(IList obj)
{
try
{
List dataBitsList = new List();
foreach (DataBits databits in Enum.GetValues(typeof(DataBits)))
{
dataBitsList.Add((int)databits);
}
return dataBitsList;
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
///
/// 获取停止位
///
///
public static List GetStopBits()
{
try
{
List stopBitList = new List();
foreach (string stopbit in Enum.GetNames(typeof(StopBits)))
{
stopBitList.Add(stopbit);
}
return stopBitList;
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
}
}
如何调用:
using Fountain.Net.Core.Com;
using System.IO.Ports;
using System.Text;
namespace Fountain.Net.Com.Demo
{
public partial class FormSerialPort : Form
{
///
/// 定义串口操作对象
///
private OperationSerialPort operationSerialPort = new OperationSerialPort();
///
///
///
public FormSerialPort()
{
InitializeComponent();
}
///
///
///
///
///
private void FormSerialPort_Load(object sender, EventArgs e)
{
try
{
//
this.InitialCombox();
//
this.InitialPort();
}
catch
{
}
}
///
///
///
private void InitialCombox()
{
try
{
// 串口名称
this.CboPortname.DataSource = OperationSerialPort.GetPortNames();
// 停止位
this.CboStopBits.DataSource = OperationSerialPort.GetStopBits();
// 校验位
this.CboParity.DataSource = OperationSerialPort.GetParitys();
// 数据位
this.CboDataBits.DataSource = OperationSerialPort.GetDataBits();
// 波特率
this.CboBaudRates.DataSource = OperationSerialPort.GetBauRates();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
///
/// 串口接收数据处理
///
private void InitialPort()
{
try
{
this.operationSerialPort.DataReceived += new Action>(_StoreReceived =>
{
while (true)
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < _StoreReceived.Count - 1; i++)
{
sb.AppendLine(_StoreReceived[i]);
}
this.BeginInvoke(new Action(() => { this.RxtReceivecontent.Text = sb.ToString(); }));
}
});
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
///
/// 打开
///
///
///
private void BtnOpen_Click(object sender, EventArgs e)
{
try
{
this.operationSerialPort.PortName = Convert.ToString(this.CboPortname.SelectedValue);
this.operationSerialPort.BaudRate = (BaudRates)Enum.Parse(typeof(BaudRates), Convert.ToString(this.CboBaudRates.SelectedValue));
this.operationSerialPort.DataBits = (DataBits)Enum.Parse(typeof(DataBits), Convert.ToString(this.CboDataBits.SelectedValue));
this.operationSerialPort.Parity = (Parity)Enum.Parse(typeof(Parity), Convert.ToString(this.CboParity.SelectedValue));
this.operationSerialPort.StopBits = (StopBits)Enum.Parse(typeof(StopBits), Convert.ToString(this.CboStopBits.SelectedValue));
this.operationSerialPort.Open();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
///
/// 关闭
///
///
///
private void BtnClose_Click(object sender, EventArgs e)
{
try
{
this.operationSerialPort.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
///
/// 清空接收的内容
///
///
///
private void BtnClean_Click(object sender, EventArgs e)
{
try
{
this.RxtReceivecontent.Text = string.Empty;
}
catch (Exception exception)
{
MessageBox.Show(exception.Message);
}
}
}
}
.NET实现与串口设备通信代码示例资源-CSDN文库https://download.csdn.net/download/Funniyuan/88804184
总结
SerialPort是一个非常方便用于实现与串口设备进行通信的类库,对从事硬件对接开发、嵌入式开发的人,难免会用到这个类。我在工作过程中也用到了这个类来实现与称重设备、高拍仪设备等的数据读取。
获取更多C#知识可关注【dotNet开发技术分享】公众号