SerialPort类问题

我试图让串口接收正确的消息时遇到很多问题。 它不断截断消息。 这是我的代码,我将尝试在代码之后详细说明。

public SerialComms(SerialPort sp) { this.sp = sp; this.sp.Open(); this.sp.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived); do { Console.WriteLine("port open waiting message"); Console.ReadKey(); } while(!_terminate); this.sp.Close(); } void sp_DataReceived(object sender, SerialDataReceivedEventArgs e) { string dataReceived; StringComparer strComp = StringComparer.OrdinalIgnoreCase; SerialPort sp = (SerialPort)sender; int i = sp.BytesToRead; byte[] _byte = new byte[i]; char[] _char = new char[i]; sp.read(_byte, 0, i); dataReceived = Encoding.UTF8.GetString(_byte); //dataReceived = new string(_char); //dataReceived = sp.ReadExisting(); if (strComp.Equals("00000000000000"), dataReceived)) _terminate = true; Console.WriteLine(dataReceived); } 

现在我有一个测试项目,我们用它来测试生产中使用传统软件的串行com-我知道这样运行正常。 我已经将一个串行监视器连接到端口,并且通过传输发送的消息没有任何问题。 当我第一次发送消息如012345678901234时,它通常会很好,在接收端,显示器显示它通过; 但是,当它打印到控制台时,它会在第一条消息后被截断。 我在端口监视器和控制台输出上附加消息的屏幕截图(显示的笑脸和心脏是转换的前缀字节 – 为什么它是一个心脏和笑脸我不知道)

好的,所以我无法发布图片,因为我没有足够的声誉这样做。 我将在下面的控制台中写出输出的内容(在这种情况下,由于某种原因,它也截断了第一条消息:()

在串口监视器上,正在传输的消息如下(我发送了三次,每次消息发送之间有几秒的延迟时间):
02 31 32 33 34 35 36 37 38 39 30 31 32 33 34 03 .12345678901234。
02 31 32 33 34 35 36 37 38 39 30 31 32 33 34 03 .12345678901234。
02 31 32 33 34 35 36 37 38 39 30 31 32 33 34 03 .12345678901234。

在控制台上我收到以下内容(☺和♥字符是02和03,它们是STX和ETX消息,是我们传输的标准信息):
☺123456
78901234♥

123
456
7890
123
4♥

123
456
7890
123
4♥

这个问题让我发疯! 请帮忙! 遗产是使用过时的MSCommLib,我们正在转向.Net 4

这在任何通信协议中都是正常和常见的。 网络上的TCP也具有此属性。 字节作为流传输 ,而不是数据包。 因此,当您的DataReceived事件处理程序触发时,您只知道您有一些可用的字节。 在处理之前,您需要将接收字节组合成完整的响应。

这需要一种协议 ,一种识别您获得完整响应的方法。 你有一个,那些STX和ETX字节告诉你。 特别是ETX,STX是一种过滤掉连接设备时可能获得的噪声字节的方法。

一个非常简单的方法是将NewLine属性设置为(char)3并调用ReadLine()。

更好的方法是过滤STX帮助您消除的噪音,同时避免死锁情况:

 private const int MaxResponse = 42; private const int STX = 2; private const int ETX = 3; private byte[MaxResponse] response; private int responseLength; void sp_DataReceived(object sender, SerialDataReceivedEventArgs e) { var sp = (SerialPort)sender; int cnt = sp.BytesToReceive; for (int ix = 0; ix < cnt; ++ix) { byte b = (byte)sp.ReadByte(); if (responseLength == 0 && b != STX) continue; if (b != ETX) response[responseLength++] = b; else { var str = Encoding.ASCII.GetString(response, 0, responseLength); HandleResponse(str); responseLength = 0; } } } 

并编写HandleResponse()方法来处理您收到的数据。

可能有两个问题的组合。

首先,使用流时常见的错误是因为你从Read请求i字节并不意味着Read实际上会读取那么多字节,这不太可能是你的问题,但是你应该知道它, 看看这个问题的答案是什么正确的模式 。

第二个问题是流是流,而不是消息。 它不知道你发送了☺12345678901234♥ ,它只是知道它在最后一次检查和现在之间收到了☺123456 ,它应该向用户报告该信息。

您需要修改您的读取代码以保持缓冲数据,直到它收到下一个然后获取整个缓冲的字节数组并将其发送给用户。 这就是沿线发送的全部原因,它允许接收器能够检测到它何时到达消息的开头或结尾。