.NET串口通讯解决方案
网上关于.NET串口通讯的文章不少,但大多只是一些对.NET串口通讯函数的简单封装,对于实际的操作和使用,并没有太直接的帮助。本人做过几个.NET下串口通讯的小项目,借鉴了一些前人的经验(特别是SharpGps)并结合自己的一些心得和体会,写下这篇文章,算是对自己这部分工作的一个总结。
本来这篇文章的题目叫“.NET串口通讯设计”,想想觉得如果叫这个名字,那就没有写下去的必要了(网上这样的文章大把)。至于这篇文章配得上“解决方案”这四个字否? (我也不知道~) 言归正传,正文开始…
- 设计概要
SerialPort.cs
ComEvent.cs
Enumerations.cs
以及各种协议的具体实现类,如XXX_imp.cs
- 通讯基础类SerialPort.cs
主要封装一些.Net串口通讯已实现的一些常用方法,这个类和网上大多数介绍.Net串口通讯的文章所介绍的差不多,唯一不同的地方是在接收部分的处理(注:接收部分采用了异步的方式),利用了.Net的事件机制,将“接收数据”这一事件根据事件类型(即协议),告知给协议的具体实现类进行相应的处理。
public class SerialPort : IDisposable { private System.IO.Ports.SerialPort com; private bool disposed = false; internal event RevMsgDelegate MsgDelegate; public SerialPort() { com = new System.IO.Ports.SerialPort(); //默认参数 com.PortName = "com1"; com.BaudRate = 9600; com.DataBits = 8; com.StopBits = StopBits.One; com.Parity = Parity.None; com.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler); disposed = false; } public void Dispose() { if (!this.disposed) { this.Stop(); com = null; } disposed = true; GC.SuppressFinalize(this); } ~SerialPort() { Dispose(); } /// <summary> /// 数据接受响应函数 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e) { Thread.Sleep(500); System.IO.Ports.SerialPort sp = (System.IO.Ports.SerialPort)sender; String indata = sp.ReadExisting(); //接受数据消息 将接受到的数据分类 然后转发给响应的imp if (MsgDelegate != null) { RevMsgEventArgs RevEventArgs = new RevMsgEventArgs(); RevEventArgs.MsgType = GetCommType(indata); MsgDelegate(indata, RevEventArgs); } } /// <summary> /// 反馈数据类型识别 /// </summary> /// <param name="sentence"></param> /// <returns></returns> private GTCommType GetCommType(string sentence) {
//具体根据协议,进行类别的判断
//...... return commType; } public bool Write(String cmd) { try { com.Write(cmd); } catch (System.Exception e) { return false; } return true; } public bool Open() { try { com.Open(); } catch (System.IO.IOException ex) { return false; } return true; } public bool IsPortOpen { get { return com.IsOpen; } } public void Stop() { if (com != null) if (com.IsOpen) com.Close(); } public String PortName { get { return com.PortName; } set { if (value != null) com.PortName = value; } } public int BaudRate { get { return com.BaudRate; } set { if (value != 0) com.BaudRate = value; } } public int DataBits { get { return com.DataBits; } set { if (value != 0) com.DataBits = value; } } public StopBits Stopbits { get { return com.StopBits; } set { if (value != 0) com.StopBits = value; } } public Parity parity { get { return com.Parity; } set { if (value != 0) com.Parity = value; } } }
- ComEvent.cs
定义代理(事件的载体)以及事件的内容,主要包含两个代理:(1)接收数据代理RevMsgDelegate, 用来将DataReceivedHandler中接收到数据分发给相应的imp (2)UI代理UIMsgDelegate, 用来将imp类中处理好的数据发送给UI以实现相应的逻辑,例如数据的呈现等界面操作。 注: 如果通讯是在线程中处理的,那么UI的响应需要调用Invoke方法实现。
//接收数据代理 internal delegate void RevMsgDelegate(object sender, RevMsgEventArgs e); internal class RevMsgEventArgs : EventArgs //接受数据事件内容 { public GTCommType MsgType;//接受到的数据类型 } //UI事件代理 public delegate void UIMsgDelegate(object sender, UIMsgEventArgs e); public class UIMsgEventArgs : EventArgs { //UI事件内容
//......
}
- Enumerations.cs
事件类型的枚举。
public enum CommMsgType { //通讯事件 //...... } public enum UIMsgType { //UI事件 //...... }
- 协议的具体实现类
主要的功能是接收RevMsgDelegate代理发送过来的事件,根据当前协议的内容,对数据进行解析并通过UIMsgDelegate发送相应的界面事件,驱动相关联的界面操作。本类主要是根据实际情况进行封装,所以在此不多说,只列出一些重要的操作。
public class XXX_imp { private SerialPort _port; //UI事件 public event UIMsgDelegate UIMsg; UIMsgEventArgs UIEventArgs; public XXX_imp(SerialPort port) { _port = port; //绑定数据接受事件 port.MsgDelegate += new RevMsgDelegate(Parse); } private void Parse(object sender, RevMsgEventArgs e) { if (e.MsgType == GTCommType.XXX) { //解析数据 //......
} }#region 接口 //根据需要的业务逻辑编写有关方法 //...... #endregion }
到此本文就告一段落, 本人是.Net的初学者,只是略懂皮毛,写这篇文章更主要的目的还是希望大家能多多指点,有不足和改进的地方希望能予以指出。