c# - SerialPort RS-485和通信限制

时间:2011-05-25 16:19:27

标签: c# performance serial-port communication

我正在尝试通过串口与使用RS-485的设备进行通信。一切正常,直到我们试图加强通信来测试卡的速度限制,然后似乎发生奇怪的问题。我们基本上发送第一个命令,其中图像作为参数,然后是另一个命令来显示该图像。在每个命令之后,卡片回答说命令很好。但是我们很快就达到了限制,并且该卡应该可以处理更多。

所以我想知道,因为传输和接收是通过相同的线路,如果存在某种数据冲突?我应该等待接收所有数据吗? SerialDataReceivedEventHandler在这种情况下是否太慢,我应该继续在单独的线程中读取while循环中的字节,并在完成消息到达后发出其他线程的信号吗?

其他信息:

  • 我们已经有了一个通信协议:startdelimiter,data, CRC16,enddelimiter
  • 发送2个命令是我们这样做的方式,无法更改。
  • BaudRate定义为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 ......在第一个命令之后我需要至少睡20ms才能使卡不崩溃。所以我猜这是卡需要接收/处理整个图像到它的像素的时间。和数据的冲突不应该真正发生,因为我等到整个消息到达,这意味着问题不在我的意思!是! :p

1 个答案:

答案 0 :(得分:1)

有几点指示:

  • 发送后,您需要在读取响应之前等待传输缓冲区空事件。它是非托管的EV_TXEMPTY,我不记得它是如何封装在托管端 - 我们的RS485代码早于.NET comport组件。

  • 您可以使用timeBeginPeriod(1)调用重新编程定时器芯片,以在Thread.Sleep()上获得1毫秒的分辨率。

  • 为了它的价值,我们只在发送后短暂(1毫秒)休眠,然后进入一个读取循环,我们继续尝试从端口读取(再次,读取尝试之间有1毫秒的延迟),直到已收到完整响应(或直到超时或重试计数器耗尽)。

这是timeBeginPeriod的导入声明 - 我不相信它可以在.NET中直接使用(但是?):

[DllImport("winmm.dll")]
internal static extern uint timeBeginPeriod(uint period);   

我希望这会有所帮助。