【发布时间】:2011-09-01 22:14:45
【问题描述】:
我正在尝试通过串行端口使用 RS-485 与设备通信。一切正常,直到我们尝试增强通信以测试卡的速度限制,然后似乎出现了奇怪的问题。我们基本上是发送带有图像作为参数的第一个命令,然后发送另一个命令来显示该图像。在每个命令之后,卡片都会回答说命令很受欢迎。但是我们很快就达到了极限,而这张卡应该可以处理更多的事情。
所以我想知道,由于传输和接收是通过同一条线路进行的,是否存在某种数据冲突?我应该等待接收所有数据吗? SerialDataReceivedEventHandler 在这种情况下是否太慢了,我是否应该在单独的线程中继续读取 while true 循环中的字节,并在收到完整消息后向其他线程发出信号?
其他信息:
- 我们已经有了一个通信协议:startdelimiter、data、 CRC16,结束分隔符
- 发送 2 个命令是我们的做法,无法更改。
- 波特率定义为 115200
- 工程师仍在处理卡中的程序,因此问题也可能在他身上。
- 英语不是我的母语,所以如果我不清楚,请随时询问... :)
我认识到 SerialPort 编程不是我的强项,我一直在尝试寻找某种包装器,但没有找到适合我需要的包装器。如果有人向我求婚,那就太好了,或者有人知道可能出了什么问题。 无论如何,这里有一些编码:
线程发送帧:
public void SendOne()
{
timerLast = Stopwatch.GetTimestamp();
while (!Paused && conn.ClientConnState == Connexion.ConnectionState.Connected)
{
timerNow = Stopwatch.GetTimestamp();
if ((timerNow - timerLast) / (double)Stopwatch.Frequency >= 1 / (double)fps)
{
averageFPS.Add((int)((double)Stopwatch.Frequency / (timerNow - timerLast)) + 1);
if (averageFPS.Count > 10) averageFPS.RemoveAt(0);
timerLast = Stopwatch.GetTimestamp();
if (atFrame >= toSend.Count - 1)
{
atFrame = 0;
if (!isLoop)
Paused = true;
}
SendColorImage();
}
}
public void SendColorImage()
{
conn.Write(VIP16.bytesToVIP16(0x70C1, VIP16.Request.SendImage, toSend[++atFrame]));
WaitForResponse();
conn.Write(VIP16.bytesToVIP16(0x70C1, VIP16.Request.DisplayImage, VIP16.DisplayOnArg));
WaitForResponse();
}
private void WaitForResponse()
{
Thread.Sleep(25);
}
所以 WaitForResponse() 至关重要,因为如果我在卡应答之前发送另一个命令,它会发疯。虽然我讨厌使用 Thread.Sleep() 因为它不是很准确,而且它会将我的速度限制在 20fps,而且如果我使用低于 25ms 的东西,则更有可能发生崩溃的风险。所以我正准备将 Thread.Sleep 更改为“读取字节,直到收到整个消息”并忽略 DataReceivedEvent ......只是想知道我是否完全偏离了轨道?
发送很多!
更新 1
首先感谢 Brad 和 500 - 内部服务器错误!但我现在决定坚持使用 .NET 串行端口并提高 Thread.Sleep 的准确性(使用 timebeginperiod)。我决定等待收到完整的响应,然后使用 ManualResetEventSlim(为了速度)同步我的线程:
public static ManualResetEventSlim _waitHandle = new ManualResetEventSlim(false);
然后我将 SendColorIMage 更改为:
public void SendColorImage()
{
conn.Write(VIP16.bytesToVIP16(0x70C1, VIP16.Requetes.SendImage, toSend[++atFrame]));
WaitForResponse();
conn.Write(VIP16.bytesToVIP16(0x70C1, VIP16.Requetes.DisplayImage, VIP16.DisplayOnArg));
WaitForResponse2();
}
private void WaitForResponse()
{
Connexion._waitHandle.Wait(100);
Thread.Sleep(20);
}
private void WaitForResponse2()
{
Connexion._waitHandle.Wait(100);
//Thread.Sleep(5);
}
使用 SerialDataReceivedEventHandler 调用:
public void Recevoir(object sender, SerialDataReceivedEventArgs e)
{
if (!msg.IsIncomplete)
msg = new Vip16Message();
lock (locker)
{
if (sp.BytesToRead > 0)
{
byte[] byteMsg = new byte[sp.BytesToRead];
sp.Read(byteMsg, 0, byteMsg.Length);
msg.Insert(byteMsg);
}
}
if (!msg.IsIncomplete)
{
_waitHandle.Set();
if (MessageRecu != null)
MessageRecu(msg.toByte());
}
}
所以我发现在第二个命令之后我根本不需要调用 Thread.Sleep ......而在第一个命令之后我需要睡眠至少 20 毫秒才能使卡不崩溃。所以我想这是卡需要接收/处理整个图像到它的像素的时候了。 AND 数据冲突不应该真的发生,因为我等到整个消息到达,这意味着问题不在我的尽头!是的! :p
【问题讨论】:
-
.NET串口类一直让我很头疼。它在 .NET 4.0 中变得更好,但我仍然遇到问题,尤其是使用 USB 适配器。我强烈推荐 CommStudio。效果很好。您可以在此处获得免费版本:componentsource.com/products/commstudio/downloads.html?rv=42917 完整版没有花里胡哨,但串行端口部分应该是您所需要的。
标签: c# performance serial-port communication