需要 .NET 串行端口帮助,主要涉及在多个“数据包”中接收的数据
我对通过 .net 通过串行端口发送数据非常陌生,并且在实现 TCP 对应项后我注意到我不会用串行那么容易地得到它!
因此,从顶部开始,我几乎已经实现了串行双向通信实现,但我只是陷入了一些问题: -
- 我的读取被拆分为多条消息,或者通过 COM 端口作为碎片响应接收,并且我不知道我可能需要什么设置,或者我应该如何以不同的方式编写代码来解决这个问题。 什么可能导致这种情况? 我正在
SerialPort_DataReceived 上的断点处检查消息。
基本上,数据应该发送为:
01: LS|DA090521|TI111043|q
02: PS|RN102|PTC|TA1040000|P#0|DA090521|TI111429|j
但它正在被分割(在每个请求的读取的随机位置)
01: LS|DA090521|TI111
02: 043|q
03: PS|RN102|PTC|TA1
04: 0000|P#0|DA090521|TI111429|j
-问题 1 已得到解答,感谢 Chris W. 和其他人! 我现在有了我期望从片段逐步构建的消息(寻找 STX、{msg body}、ETX),然后在消息完全构建时执行一个操作,并使用线程安全队列让它继续运行,非常高兴.
. 2. 我收到一个“|” 我几乎每个周期都会读取符号,这是由于我以某种方式错误设置的命令、串行通信的产物还是设备向我发送的内容? (但我不这么认为,因为超级终端连接显示该字符没有被连续发送。)
。 3. 您能否确认我在各个方法中正确读取和写入数据?
也谢谢大家看我的另外两个问题。
相关代码如下:
...
// COM3, 9600, None, 8, One
SerialPort = new SerialPort(comPort, baudRate, parity, dataBits, stopBits);
if (SerialPort.IsOpen) SerialPort.Close();
// SerialPort.RtsEnable = true; // Request-to-send
// SerialPort.DtrEnable = true; // Data-terminal-ready
SerialPort.ReadTimeout = 150; // tried this, but didn't help
SerialPort.WriteTimeout = 150; // tried this, but didn't help
SerialPort.Open();
SerialPort.DataReceived += new SerialDataReceivedEventHandler(SerialPort_DataReceived);
}
void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
// Process received data
SerialPort sp = (SerialPort)sender;
byte[] buffer = new byte[sp.BytesToRead];
int bytesRead = sp.Read(buffer, 0, buffer.Length);
// message has successfully been received
message = Encoding.ASCII.GetString(buffer, 0, bytesRead);
}
public bool SendMessage(string text)
{
// Only send message if a client is connected
if (SerialPort != null && SerialPort.IsOpen)
{
byte[] buffer = Encoding.ASCII.GetBytes(text);
SerialPort.Write(buffer, 0, buffer.Length);
}
}
I'm very new to sending data over a serial port through .net and I've noticed after implementing a TCP counterpart that I wouldn't get it that easy with serial!
So to start at the top, I am nearly there with my serial bi-directional communication implementation I am just getting stuck on a few things: -
- My reads are being split across multiple messages or received as a fragmented response over the COM port and I don't know what settings I might need, or how I should write the code differently to fix this. What could cause this? I am inspecting the message at a breakpoint on
SerialPort_DataReceived.
Basically the data should be sent as:
01: LS|DA090521|TI111043|q
02: PS|RN102|PTC|TA1040000|P#0|DA090521|TI111429|j
but it is being split (at random positions on each requested read)
01: LS|DA090521|TI111
02: 043|q
03: PS|RN102|PTC|TA1
04: 0000|P#0|DA090521|TI111429|j
- Question 1 has been answered, thanks Chris W. and others! I now have the message I expect being built from fragments progressively (looking out for STX, {msg body}, ETX) and then an action performed when message has been completely built, and got it going with a thread-safe Queue, very happy.
. 2. I am receiving a "|" symbol through my read nearly every cycle, is this due to a command I have set wrongly somehow, an artifact of Serial communication, or something the device is sending me? (I don't think so though, as Hyperterminal connectivity reveals this character is not being sent continuously.)
. 3. Can you confirm I am reading and writing data correctly in the respective methods.
Thanks guys for looking at my other two questions too.
Relevant code as follows:
...
// COM3, 9600, None, 8, One
SerialPort = new SerialPort(comPort, baudRate, parity, dataBits, stopBits);
if (SerialPort.IsOpen) SerialPort.Close();
// SerialPort.RtsEnable = true; // Request-to-send
// SerialPort.DtrEnable = true; // Data-terminal-ready
SerialPort.ReadTimeout = 150; // tried this, but didn't help
SerialPort.WriteTimeout = 150; // tried this, but didn't help
SerialPort.Open();
SerialPort.DataReceived += new SerialDataReceivedEventHandler(SerialPort_DataReceived);
}
void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
// Process received data
SerialPort sp = (SerialPort)sender;
byte[] buffer = new byte[sp.BytesToRead];
int bytesRead = sp.Read(buffer, 0, buffer.Length);
// message has successfully been received
message = Encoding.ASCII.GetString(buffer, 0, bytesRead);
}
public bool SendMessage(string text)
{
// Only send message if a client is connected
if (SerialPort != null && SerialPort.IsOpen)
{
byte[] buffer = Encoding.ASCII.GetBytes(text);
SerialPort.Write(buffer, 0, buffer.Length);
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这是正常的、预期的、不可避免的行为。 TCP 数据传输也可能发生这种情况。 对于串行接口来说,它只是无尽的字节流。 您的应用程序有责任将这些字节重新打包成数据包。
如果数据包边界的位置很重要,并且如果您无法通过查看接收到的数据来判断数据包边界应该在哪里,那么您可能需要重新考虑数据的格式,以便可以< /em> 告诉数据包边界在哪里。
该字符的十六进制值是多少? 查看将
Handshake
属性设置为XOnXOff
或RequestToSendXOnXOff
是否可以改善这种情况。This is normal, expected, inevitable behaviour. It can happen with data-over-TCP as well. To the serial interface it's just an endless stream of bytes. It's your application's responsibility to repackage those bytes into packets.
If the location of packet boundaries is important, and if you can't tell where the packet boundaries are supposed to be from looking at the received data, then you may need to rethink the format of the data so that you can tell where the packet boundaries are.
What's the hex value of that character? See whether setting the
Handshake
property toXOnXOff
orRequestToSendXOnXOff
improves the situation.在较低级别,串行端口可以决定何时触发数据接收事件。 它可能决定在“完整”数据包到达之前执行此操作。 但是,您的预期数据集中似乎有一个终止符字符。 如果是这样,您可以执行以下操作(请注意,我已更改您的 SerialPort 分配以避免语法混乱:
其中 Terminator 是包含终止字符的字符串。然后您可以使用 SerialPort.ReadLine() (和 SerialPort.WriteLine() 如果适用)这至少可能对您的第一个问题有所帮助。
At the lower level the serial port can decide when to trigger the data received event. It might decide to do that before the "full" packet has arrived. But, it looks like you have a terminator character in your expected data set. If so you can do the following (note I have changed your SerialPort assignment to avoid syntax confusion:
where Terminator is a string containing your termination character(s). Then you can use SerialPort.ReadLine() (and SerialPort.WriteLine() if that applies). This might at least help with your first issue.
我已经完成了大量的 Win32 串行端口编程,但只使用了一点 .NET,所以请对我的建议持保留态度。
正如其他人所说,这是完全正常的。 根据 DCE 端的设备类型,您可能需要自行重新包装。 我不确定你连接的是哪种类型的设备,所以我不能说更多。
如果您想获取更多数据,可以尝试以下操作:
如果您对线路上发生的事情感到好奇,请查看 SysInternals 的 PortMon,这是一款免费应用程序,可以在您通过线路传输数据时监听您的 com 端口。 这看起来很技术性,但实际上您只需要查看 IRP_MJ_WRITE 和 IRP_MJ_READ 命令,您就会在线上看到以字节为单位的长度以及通过线路发送的数据。 有了这个,您应该能够判断问题是否出在 .NET SerialPort 对象上,或者设备是否实际上正在发送“|” 过线了。
它看起来适合基于事件的数据接收方法。
I have done a lot of Win32 serial port programming, but just a little with .NET, so take my advice with a grain of salt.
As others have said, this is perfectly normal. Depending on what type of equipment is on the DCE side, you may have to do repacking yourself. I'm not sure what type of equipment you're hooked up to so I cannot really say much more.
If you want to get more data, you can try the following:
If you're curious about what is going over the line, check out PortMon from SysInternals, a free app that will snoop your com port while you're transferring data over the line. It seems technical, but really you just have to look at the IRP_MJ_WRITE and IRP_MJ_READ commands, and on the line you'll see the length in bytes and the data sent over the wire. With this you should be able to tell if the problem is the .NET SerialPort object or if the device is actually sending "|" over the line.
It looks proper for the event-based method of receiving data.