SerialPort 串口通信

SerialPort 串口的参数:
View Code
public class KeySerialConfig
{
public string PortName { get; set; }

public int BaudRate { get; set; }

public int DataBits { get; set; }

public StopBits SerialStopBits { get; set; }

public Parity SerialParity { get; set; }
}

SerialPort 通信协议类

View Code
1 public class KeyProtocol:IDisposable
2 {
3 SerialPort _serialPort;
4 KeySerialConfig _serialConfig;
5 KeyPackageResolver _resolver;
6
7 public event EventHandler<KeyPackageReceivedEventArgs> KeyPackageReceived;
8 public event EventHandler<KeyPackageSendedEventArgs> KeyPackageSended;
9
10 public KeyProtocol (KeySerialConfig config)
11 {
12 this._serialConfig = config;
13 InitSerialPort();
14 _resolver = new KeyPackageResolver();
15 }
16
17 ~KeyProtocol()
18 {
19 Dispose();
20 }
21
22 public void InitSerialPort()
23 {
24 if (_serialPort != null)
25 {
26 _serialPort.Dispose();
27 }
28 _serialPort = new SerialPort();
29 _serialPort.PortName = this._serialConfig.PortName;
30 _serialPort.BaudRate = this._serialConfig.BaudRate;
31 _serialPort.DataBits = this._serialConfig.DataBits;
32 _serialPort.Parity = this._serialConfig.SerialParity;
33 _serialPort.StopBits = this._serialConfig.SerialStopBits;
34 _serialPort.ReadTimeout = 3000;
35 }
36
37 public void Start()
38 {
39 if (!_serialPort.IsOpen)
40 {
41 _serialPort.Open();
42 }
43 }
44
45 public void Stop()
46 {
47 if (_serialPort.IsOpen)
48 {
49 _serialPort.Close();
50 }
51 }
52
53 public void SendPackage(KeyPackage package)
54 {
55 byte[] sendData = package.ToBytes();
56 _serialPort.Write(sendData, 0, sendData.Length);
57  #if(LOGGING)
58 LogMgr.Logger.DebugFormat("【发送】{0} | {1}{2}",
59 Formatter.ToHex(package.ToBytes()),
60 KeyDataHelper.GetDesc(package),
61 Environment.NewLine);
62  #endif
63 OnKeyPackageSended(new KeyPackageSendedEventArgs(package));
64 }
65
66 private void OnKeyPackageSended(KeyPackageSendedEventArgs e)
67 {
68 EventHandler<KeyPackageSendedEventArgs> handler=this.KeyPackageSended;
69 if (handler!=null)
70 {
71 handler(this,e);
72 }
73 }
74
75 private void OnPackageReceived(KeyPackageReceivedEventArgs keyPackageReceivedEventArgs)
76 {
77 EventHandler<KeyPackageReceivedEventArgs> handler = this.KeyPackageReceived;
78 if (handler != null)
79 {
80 handler(this, keyPackageReceivedEventArgs);
81 }
82 }
83
84 public KeyPackage ReceivePackage()
85 {
86 try
87 {
88 KeyPackage package = _resolver.Resolve(_serialPort.BaseStream);
89  #if(LOGGING)
90 if (package.Command == CommandCode.NAK)
91 {
92 LogMgr.Logger.ErrorFormat("钥匙发送报文{0}错误,{1}",
93 KeyDataHelper.GetDesc((NAKType)package.Data[package.Data.Length - 1]),
94 Environment.NewLine);
95 }
96 else
97 {
98 LogMgr.Logger.DebugFormat("【接收】{0} | {1}{2}",
99 Formatter.ToHex(package.ToBytes()),
100 KeyDataHelper.GetDesc(package),
101 Environment.NewLine);
102 }
103  #endif
104 return package;
105 }
106 catch (TimeoutException exp)
107 {
108 throw exp;
109 }
110 }
111
112 #region IDisposable成员
113 bool _isDispose = false;
114 public void Dispose()
115 {
116 if(!_isDispose)
117 {
118 _serialPort.Close();
119 _serialPort.Dispose();
120 _isDispose = true;
121 GC.SuppressFinalize(this);
122 }
123 }
124 #endregion
125 }

报文解析类:

View Code
1 /// <summary>
2 /// 报文解析
3 /// </summary>
4   public class KeyPackageResolver
5 {
6 Queue<byte> _headerQueue = new Queue<byte>(KeyPackage.Header.Length);
7
8 public KeyPackage Resolve(Stream stream)
9 {
10 try
11 {
12 KeyPackage package = new KeyPackage();
13 int dataLen;
14
15 //读取报文头
16   while (true)
17 {
18 while (_headerQueue.Count < KeyPackage.Header.Length)
19 {
20 _headerQueue.Enqueue((byte)stream.ReadByte());
21 }
22 if (!BitUtility.CompareBytes(_headerQueue.ToArray(), KeyPackage.Header))
23 {
24 _headerQueue.Dequeue();
25 continue;
26 }
27 else
28 {
29 _headerQueue.Clear();
30 break;
31 }
32 }
33
34 dataLen = BitUtility.GetUInt16HL(new byte[] { (byte)stream.ReadByte(), (byte)stream.ReadByte() }, 0);
35 if (dataLen == 0 || dataLen > KeyPackage.MAX_DATA_LENGTH)
36 {
37 //throw new Exception();
38 //数据错误
39   KeyPackage nakPackage = KeyDataHelper.CreateNAKPackage(
40 package.Command, package.Data, NAKType.DataError);
41 return nakPackage;
42 }
43
44 package.Command = (CommandCode)stream.ReadByte();
45 package.Data = new byte[dataLen - 1];
46 if (package.Data.Length != 0)
47 GetData(stream, package.Data, 0, package.Data.Length);
48
49 byte crc = (byte)stream.ReadByte();
50 if (crc != package.CRC)
51 {
52 //校验错误
53   KeyPackage nakPackage = KeyDataHelper.CreateNAKPackage(
54 package.Command, package.Data, NAKType.CrcError);
55 return nakPackage;
56 }
57
58 return package;
59 }
60 catch (PackageResolvedException exp)
61 {
62 throw exp;
63 }
64 catch (TimeoutException exp)
65 {
66 throw exp;
67 }
68 catch (Exception exp)
69 {
70 throw new PackageResolvedException("数据包解析错误", exp, PackageResolvedException.ResolvedErrorType.UnknownError);
71 }
72 }
73
74 /// <summary>
75 /// 从流中读取指定长度的数据
76 /// </summary>
77 /// <param name="data"></param>
78 /// <param name="startIndex"></param>
79 /// <param name="count"></param>
80 /// <returns></returns>
81 int GetData(Stream stream, byte[] data, int startIndex, int count)
82 {
83 int readDataCount = 0;
84 int readFail = 0;
85 while (true)
86 {
87 int read = stream.Read(data, readDataCount, count - readDataCount);
88 readDataCount += read;
89 if (readDataCount == count)
90 {
91 break;
92 }
93 else if (read == 0)
94 {
95 readFail++;
96 if (readFail > 20)
97 {
98 throw new Exception("从流读取数据失败");
99 }
100 System.Threading.Thread.Sleep(10);
101 }
102 }
103 if (readFail != 0)
104 Debug.Print("【读取错误重试次数】{0} ", readFail);
105 return readDataCount;
106 }
107
108 }

也可以采用SerialPort自带的接收数据事件来解析。

View Code
1 /// <summary>
2 /// 接收到数据时发生
3 /// </summary>
4 /// <param name="sender"></param>
5 /// <param name="e"></param>
6 void _serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
7 {
8 int byteCount = _serialPort.BytesToRead;
9 if (byteCount < 1)
10 return;
11
12 byte[] buffer = new byte[byteCount];
13 _serialPort.Read(buffer, 0, byteCount);
14
15 ResolverReceiveData(buffer);
16
17 }
18
19 /// <summary>
20 /// 解析数据
21 /// </summary>
22 /// <param name="buffer"></param>
23 public void ResolverReceiveData(byte[] buffer)
24 {
25 MemoryStream ms = new MemoryStream();
26 MemoryStream frame = new MemoryStream();
27 Package package = new Package();
28
29 int incomeCount = buffer.Length;
30 //原来缓存中还有字节,则先加入
31 if (_receiveBuffer.Length > 0)
32 {
33 byte[] tempBuffer = _receiveBuffer.ToArray();
34 ms.Write(tempBuffer, 0, tempBuffer.Length);
35 _receiveBuffer.SetLength(0);
36 }
37 //写入刚接受的数据
38 ms.Write(buffer, 0, buffer.Length);
39
40 int handerPos = 0;//操作位置
41 int handerFlag = 0;//操作标志 <0 不操作 0:报文头 1:报文长度 2:命令码 3:数据 4:CRC
42 //int repeatCount = 0;//重复次数
43 ms.Position = 0;//流起始位置
44 int dataLength = 0;//报文长度
45
46 Queue<byte> _headerQueue = new Queue<byte>(Package.Header.Length);
47 while((handerPos < ms.Length))
48 {
49 //repeatCount++;
50 #region
51 if (handerFlag < 0)
52 {
53
54 }
55 else if (handerFlag == 0)
56 {
57 while (_headerQueue.Count < Package.Header.Length)
58 _headerQueue.Enqueue((byte)ms.ReadByte());//读入报文头
59
60 if (!Infrastructure.Bit.BitUtility.CompareBytes(_headerQueue.ToArray(), Package.Header))
61 {
62 _headerQueue.Dequeue();
63 handerPos++;//不相等位置后移一位,标志不变
64 handerFlag = 0;
65 if (handerPos > ms.Length)
66 {
67 break;
68 }
69 }
70 else
71 {
72 _headerQueue.Clear();
73 handerPos += Package.Header.Length;//位置后移报文头长度,标志变为读取报文长度
74 handerFlag = 1;
75 }
76 }
77 else if (handerFlag ==1)
78 {
79 //报文长度 2位16进制组成
80 dataLength = Infrastructure.Bit.BitUtility.GetUInt16HL(new byte[] { (byte)ms.ReadByte(), (byte)ms.ReadByte() }, 0);
81 handerPos +=2;
82 handerFlag =2;
83 if (dataLength == 0 || dataLength > Package.MAX_DATA_LENGTH)
84 {
85 //break;
86 throw new PackageResolvedException(
87 string.Format("数据长度错误,应在1-{0}之间,实际为 {1}", Package.MAX_DATA_LENGTH, dataLength),
88 PackageResolvedException.ResolvedErrorType.DataError);
89 }
90 }
91 else if (handerFlag ==2)
92 {
93 //命令码
94 package.Command = (CommandCode)ms.ReadByte();
95 handerPos +=1;
96 handerFlag=3;
97 }
98 else if (handerFlag ==3)
99 {
100 //数据 报文长度减去命令码长度
101 package.Data = new byte[dataLength - 1];
102 if (package.Data.Length != 0)
103 {
104 byte[] data = new byte[dataLength - 1];
105 for (int i = 0; i < data.Length; i++)
106 {
107 data[i] = (byte)ms.ReadByte();
108 }
109 package.Data = data;
110 }
111 handerPos+=package.Data.Length;
112 handerFlag=4;
113 }
114 else
115 {
116 //CRC
117 byte crc = (byte)ms.ReadByte();
118 if (crc != package.CRC)
119 throw new PackageResolvedException(
120 string.Format("CRC数据效验错误,应为 0x{0:X2},实际为 0x{1:X2}", package.CRC, crc),
121 PackageResolvedException.ResolvedErrorType.CRCError);
122 handerPos += 1;
123 handerFlag=5;
124 //包解析完成
125 OnPackageReceived(new PackageReceivedEventArgs(package));
126 break;
127
128 }
129 #endregion
130
131 }
132 //将为用到的数据加回缓存
133 if (handerPos <= ms.Length)
134 {
135 //接收到不完整包时,将数据保存
136 if (handerFlag > 0 && handerFlag < 5)
137 {
138 ms.Position = 0;
139 handerPos = 0;
140 }
141 else
142 ms.Position = handerPos;
143
144 byte[] tempBuffer = new byte[ms.Length - handerPos];
145 ms.Read(tempBuffer, 0, tempBuffer.Length);
146
147 _receiveBuffer.SetLength(tempBuffer.Length);
148 _receiveBuffer.Position = 0;
149 _receiveBuffer.Write(tempBuffer, 0, tempBuffer.Length);
150
151 }
152
153 }

posted on 2011-04-14 16:44  源远流长  阅读(493)  评论(0)    收藏  举报

导航