温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

利用C#怎么读取串口连接

发布时间:2021-01-05 14:17:34 来源:亿速云 阅读:300 作者:Leah 栏目:开发技术

本篇文章为大家展示了利用C#怎么读取串口连接,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。

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

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

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

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

具体代码如下:

// Open Com    _serialPort = new SerialPort(com, baud);    if (_serialPort.IsOpen) _serialPort.Close();    // Set the read / write timeouts    _serialPort.ReadTimeout = 500;    _serialPort.WriteTimeout = 500;    // Set read / write buffer Size,the default of value is 1MB    _serialPort.ReadBufferSize = 1024 * 1024;    _serialPort.WriteBufferSize = 1024 * 1024;    _serialPort.Open();    // Discard Buffer    _serialPort.DiscardInBuffer();    _serialPort.DiscardOutBuffer();

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

二、串口发送

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

#region Send     /// <summary>     /// 发送消息(byte数组)     /// </summary>     /// <param name="buffer"></param>     /// <param name="offset"></param>     /// <param name="count"></param>     public void Send(byte[] buffer, int offset, int count)     {       lock (_mux)       {         _serialPort.Write(buffer, offset, count);         _sendCount += (count - offset);       }     }     /// <summary>     /// 发送消息(字符串)     /// </summary>     /// <param name="encoding">字符串编码方式,具体方式见<see cref="Encoding"/></param>     /// <param name="message"></param>     public void Send(Encoding encoding , string message)     {       lock (_mux)       {         var buffer = encoding.GetBytes(message);         _serialPort.Write(buffer, 0, buffer.Length);         _sendCount += buffer.Length;       }     }     #endregion

三、串口接受

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

#region Receive     private void PushMessage()     {       _serialPort.DataReceived += (sender, e) =>       {         lock (_mux)         {           if (_serialPort.IsOpen == false) return;           int length = _serialPort.BytesToRead;           byte[] buffer = new byte[length];           _serialPort.Read(buffer, 0, length);           _receiveCount += length;           _messageQueue.Enqueue(buffer);           _messageWaitHandle.Set();         }       };     }     /// <summary>     /// 获取串口接受到的内容     /// </summary>     /// <param name="millisecondsToTimeout">取消息的超时时间</param>     /// <returns>返回byte数组</returns>     public byte[] TryMessage(int millisecondsToTimeout = -1)     {       if (_messageQueue.TryDequeue(out var message))       {         return message;       }       if (_messageWaitHandle.WaitOne(millisecondsToTimeout))       {         if (_messageQueue.TryDequeue(out message))         {           return message;         }       }       return default;     }     #endregion

四、完整代码与测试结果

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

using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.IO.Ports; using System.Linq; using System.Runtime.Serialization; using System.Text; using System.Threading; using System.Threading.Tasks; namespace SerialportDemo {   public class SSerialPort   {     private SerialPort _serialPort;     private readonly ConcurrentQueue<byte[]> _messageQueue;     private readonly EventWaitHandle _messageWaitHandle;     private int _receiveCount, _sendCount;     private readonly object _mux;     public int ReceiveCount     {       get => _receiveCount;     }     public  int SendCount     {       get => _sendCount;     }     public SSerialPort(string com, int baud )     {       // initialized       _mux=new object();       _receiveCount = 0;       _sendCount = 0;       _messageQueue = new ConcurrentQueue<byte[]>();       _messageWaitHandle = new EventWaitHandle(false, EventResetMode.AutoReset);       // Open Com       OpenCom(com.ToUpper(),baud);       // Receive byte       PushMessage();     }     private void OpenCom(string com, int baud)     {       // Open Com       _serialPort = new SerialPort(com, baud);       if (_serialPort.IsOpen) _serialPort.Close();       // Set the read / write timeouts       _serialPort.ReadTimeout = 500;       _serialPort.WriteTimeout = 500;       // Set read / write buffer Size,the default of value is 1MB       _serialPort.ReadBufferSize = 1024 * 1024;       _serialPort.WriteBufferSize = 1024 * 1024;       _serialPort.Open();       // Discard Buffer       _serialPort.DiscardInBuffer();       _serialPort.DiscardOutBuffer();     }     #region Static     /// <summary>     /// 获取当前计算机的串行端口名的数组     /// </summary>     /// <returns></returns>     public static string[] GetPortNames()     {       return SerialPort.GetPortNames();     }     #endregion     #region Receive     private void PushMessage()     {       _serialPort.DataReceived += (sender, e) =>       {         lock (_mux)         {           if (_serialPort.IsOpen == false) return;           int length = _serialPort.BytesToRead;           byte[] buffer = new byte[length];           _serialPort.Read(buffer, 0, length);           _receiveCount += length;           _messageQueue.Enqueue(buffer);           _messageWaitHandle.Set();         }       };     }     /// <summary>     /// 获取串口接受到的内容     /// </summary>     /// <param name="millisecondsToTimeout">取消息的超时时间</param>     /// <returns>返回byte数组</returns>     public byte[] TryMessage(int millisecondsToTimeout = -1)     {       if (_messageQueue.TryDequeue(out var message))       {         return message;       }       if (_messageWaitHandle.WaitOne(millisecondsToTimeout))       {         if (_messageQueue.TryDequeue(out message))         {           return message;         }       }       return default;     }     #endregion     #region Send     /// <summary>     /// 发送消息(byte数组)     /// </summary>     /// <param name="buffer"></param>     /// <param name="offset"></param>     /// <param name="count"></param>     public void Send(byte[] buffer, int offset, int count)     {       lock (_mux)       {         _serialPort.Write(buffer, offset, count);         _sendCount += (count - offset);       }     }     /// <summary>     /// 发送消息(字符串)     /// </summary>     /// <param name="encoding">字符串编码方式,具体方式见<see cref="Encoding"/></param>     /// <param name="message"></param>     public void Send(Encoding encoding , string message)     {       lock (_mux)       {         var buffer = encoding.GetBytes(message);         _serialPort.Write(buffer, 0, buffer.Length);         _sendCount += buffer.Length;       }     }     #endregion     /// <summary>     /// 清空接受/发送总数统计     /// </summary>     public void ClearCount()     {       lock (_mux)       {         _sendCount = 0;         _receiveCount = 0;       }     }     /// <summary>     /// 关闭串口     /// </summary>     public void Close()     {       _serialPort.Close();     }   } }

测试代码如下:

class Program   {     static void Main(string[] args)     {       Console.WriteLine($"该计算机可使用的串口列表:{string.Join(",", SSerialPort.GetPortNames())}");       Console.Write("请输入需要打开的串口:");       string port = Console.ReadLine();       SSerialPort com = new SSerialPort(port, 57600);       Console.WriteLine($"串口 {port} 打开成功...");       Console.Write("请输入需要打开的串口发送的消息:");       string text = Console.ReadLine();       while (true)       {         com.Send(Encoding.Default, text);         Console.WriteLine($"总共发送 {com.SendCount}");         var message = com.TryMessage();         if (message != null)         {           Console.WriteLine($"{DateTime.Now.ToString("HH:mm:ss fff")} {Encoding.Default.GetString(message)}");           //// TEST:从添加延时可以测试到,接受消息和处理消息必须分不同线程处理。因为对于消息的处理或多或少都需要耗时,这样容易造成消息处理不及时。而添加到队列后,我们可以随时取出处理           //System.Threading.Thread.Sleep(100*1);         }         Console.WriteLine($"总共接受 {com.ReceiveCount}");       }       Console.ReadKey();     }   }

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

上述内容就是利用C#怎么读取串口连接,你们学到知识或技能了吗?如果还想学到更多技能或者丰富自己的知识储备,欢迎关注亿速云行业资讯频道。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI