.NET 如何实现与串口设备通信

一、前言

串口是串行接口(Serial Port) 的简称,是一种常用于电子设备间通讯的全双工扩展接口。常见的有RS-232标准一般应用在计算机与外部设备之间进行数据传输(有25针或9针连接器)。我们现在的计算机基本上已经看不到串口,我们可以通过USB适配器来将COM端口转换为USB接口进行连接。今天我们来了解.NET 如何用C#语言编写代码实现与这些设备进行通信。

二、串口通信

串口通信包括通信时序、通讯速率、数据传输。

常用的通讯速率有2400bps、4800bps、9600bps、19200bps、38400bps、115200bps。

我们通过下图对串口的通信时序进行简单了解,串口时序由起始位、数据位、校验位、停止位组成。

.NET 如何实现与串口设备通信_第1张图片

下表对时序组成进行说明

名称 描述
起始位 占用1位,低电平有效。
数据位 可以是5位、6位、7位、8位,其中最常用为8位。
校验位 占用1位,无校验位时不占用。
偶校验(even parity):校验原则是,数据位和校验位中1的个数为偶数
奇校验(odd parity):校验原则是,数据位和校验位中1的个数为奇数
无校验(odd parity):即时序图中没有校验位
(Space):校验位总为0
(Mark):校验位总为1
停止位 占用1位、1.5位、2位,高电平有效

三、SerialPort类

.NET的框架类库提供了SerialPort类,可用SerialPort类来配置和管理串口的属性,可用于发送和接收数据。SerialPort类的常用属性包括PortName、BaudRate、Parity、DataBits、StopBits、Handshake、ReadTimeout和WriteTimeout等。这些属性用于指定串口的名称、波特率、校验位、数据位、停止位、握手协议以及读取和写入数据时的超时时间等。

  • 属性

    红色是类常用的属性,在我们使用类时根据连接设备情况进行属性的配置。

.NET 如何实现与串口设备通信_第2张图片

  • 方法

    我们先配置类的属性,然后使用 Open() 方法打开串口,使用 Write() 方法发送数据,使用 Read() 方法读取数据,并使用 Close() 方法关闭串口。

    • .NET 如何实现与串口设备通信_第3张图片
  • 事件

    在发送和接收数据时,我们也可以使用事件来处理数据的到达和发送完成。

四、示例

我们先定义波特率与数据位二个枚举类型:

  /// 
  /// 波特率
  /// 
  [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文库icon-default.png?t=N7T8https://download.csdn.net/download/Funniyuan/88804184

总结

SerialPort是一个非常方便用于实现与串口设备进行通信的类库,对从事硬件对接开发、嵌入式开发的人,难免会用到这个类。我在工作过程中也用到了这个类来实现与称重设备、高拍仪设备等的数据读取。

获取更多C#知识可关注【dotNet开发技术分享】公众号

你可能感兴趣的:(.net,单片机,stm32)