zoukankan      html  css  js  c++  java
  • C# 串口连接的读取与发送(附串口工具的编写源码)

    一、串口连接的打开与关闭

    串口,即COM口,在.NET中使用 SerialPort 类进行操作。串口开启与关闭,是涉及慢速硬件的IO操作,频繁打开或关闭会影响整体处理速度,甚至导致打开或关闭串口失败。非特殊情况,串口一次性打开后,在退出程序时关闭串口即可。在打开串口前,可以设置一些常用的参数。常用的参数如下:

    (1)串口的接受/发送超时时间:ReadTimeout/WriteTimeout。

    (2) 串口的接受/发送缓存区大小:ReadBufferSize/WriteBufferSize。

    具体代码如下:

     1             // Open Com
     2             _serialPort = new SerialPort(com, baud);
     3             if (_serialPort.IsOpen) _serialPort.Close();
     4 
     5             // Set the read / write timeouts
     6             _serialPort.ReadTimeout = 500;
     7             _serialPort.WriteTimeout = 500;
     8 
     9             // Set read / write buffer Size,the default of value is 1MB
    10             _serialPort.ReadBufferSize = 1024 * 1024;
    11             _serialPort.WriteBufferSize = 1024 * 1024;
    12 
    13             _serialPort.Open();
    14 
    15             // Discard Buffer
    16             _serialPort.DiscardInBuffer();
    17             _serialPort.DiscardOutBuffer();
    

    需要注意的是超出缓冲区的部分会被直接丢弃。因此,如果需要使用串口传送大文件,那接收方和发送方都需要将各自的缓冲区域设置的足够大,以便能够一次性存储下大文件的二进制数组。若条件限制,缓冲区域不能设置过大,那就需要在发送大文件的时候按照发送缓冲区大小分包去发送,接收方按顺序把该数组组合起来形成接受文件的二进制数组。

    二、串口发送

    SerialPort 类发送支持二进制发送与文本发送,需要注意的是文本发送时,需要知道转换的规则,一般常用的是ASCII、UTF7、UTF-8、UNICODE、UTF32。具体代码如下:

     1         #region Send
     2         /// <summary>
     3         /// 发送消息(byte数组)
     4         /// </summary>
     5         /// <param name="buffer"></param>
     6         /// <param name="offset"></param>
     7         /// <param name="count"></param>
     8         public void Send(byte[] buffer, int offset, int count)
     9         {
    10             lock (_mux)
    11             {
    12                 _serialPort.Write(buffer, offset, count);
    13                 _sendCount += (count - offset);
    14             }
    15         }
    16 
    17         /// <summary>
    18         /// 发送消息(字符串)
    19         /// </summary>
    20         /// <param name="encoding">字符串编码方式,具体方式见<see cref="Encoding"/></param>
    21         /// <param name="message"></param>
    22         public void Send(Encoding encoding , string message)
    23         {
    24             lock (_mux)
    25             {
    26                 var buffer = encoding.GetBytes(message);
    27                 _serialPort.Write(buffer, 0, buffer.Length);
    28                 _sendCount += buffer.Length;
    29             }
    30         }
    31         #endregion
    

    三、串口接受

    ​ 串口接受需要注意,消息接受与消息处理要代码分离。不能把流程处理的代码放入信息接受处,因为消息处理或多或少会有耗时,这会造成当发送方发送过快时,接受方的接受缓冲区会缓存多条消息。我们可以把接受到的消息放入队列中,然后在外部线程中,尝试去拿出该条消息进行消费。采用 “生产-消费”模式。具体代码如下:

     1      #region Receive
     2         private void PushMessage()
     3         {
     4             _serialPort.DataReceived += (sender, e) =>
     5             {
     6                 lock (_mux)
     7                 {
     8                     if (_serialPort.IsOpen == false) return;
     9                     int length = _serialPort.BytesToRead;
    10                     byte[] buffer = new byte[length];
    11                     _serialPort.Read(buffer, 0, length);
    12                     _receiveCount += length;
    13                     _messageQueue.Enqueue(buffer);
    14                     _messageWaitHandle.Set();
    15                 }
    16             };
    17         }
    18 
    19         /// <summary>
    20         /// 获取串口接受到的内容
    21         /// </summary>
    22         /// <param name="millisecondsToTimeout">取消息的超时时间</param>
    23         /// <returns>返回byte数组</returns>
    24         public byte[] TryMessage(int millisecondsToTimeout = -1)
    25         {
    26             if (_messageQueue.TryDequeue(out var message))
    27             {
    28                 return message;
    29             }
    30 
    31             if (_messageWaitHandle.WaitOne(millisecondsToTimeout))
    32             {
    33                 if (_messageQueue.TryDequeue(out message))
    34                 {
    35                     return message;
    36                 }
    37             }
    38             return default;
    39         }
    40         #endregion
    

    四、完整代码与测试结果

    ​ 串口工具类的完整代码如下:

    imgView Code

    ​ 测试代码如下:

    imgView Code

    使用串口工具测试如下,对于串口的接受如丝般顺滑。当我们在消息中增加测试延时后,就会发现当串口工具继续快速发送一段时间后关闭发送,发现使用队列后,依然没有丢失一条来自发送方的消息。

    img

    五、串口工具编写实例

    通过以上对串口的了解,我们模仿串口工具进行编程,完成如下:

    img img

    该串口工具采用WPF框架的MVVM模式进行开发,代码地址:https://github.com/Dwayne112401/MyProgra-SerialportTool

  • 相关阅读:
    halcon 常用算子中文解释说明(随时更新)
    傅里叶变换 fft_generic halcon
    phpStorm使用技巧及快捷键
    js控制文本框只能输入数字 及 常用字符对应ASCII码值
    Delphi 7 里没有加载的控件
    用VBA计算WPS 表格ET EXCEL中的行数和列数的多重方法
    PHP 把GBK编码转换为UTF8
    Oracle性能优化5-索引的不足
    Oracle性能优化4-索引
    Oracle性能优化3-sql优化一定要等价
  • 原文地址:https://www.cnblogs.com/dongweian/p/14232446.html
Copyright © 2011-2022 走看看