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

问题描述

| 我正在尝试通过串行端口使用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 ...只是想知道我是否在这里完全偏离了轨道? Tx很多! 更新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,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,byteMsg.Length);
                msg.Insert(byteMsg);
            }
        }

        if (!msg.IsIncomplete)
        {
            _waitHandle.Set();
            if (MessageRecu != null)
                MessageRecu(msg.toByte());
        }
    }
因此,我发现在执行第二个命令之后,我根本不需要调用Thread.Sleep ...,在执行第一个命令之后,我需要休眠至少20ms以使卡不崩溃。所以我想这是卡需要接收/处理整个图像到其像素的时间。由于我要等到整个消息到达后才真正不会发生AND数据冲突,这意味着问题不在我的身边!是! :p     

解决方法

几个指针: 发送后,您将需要等待传输缓冲区为空的事件,然后再读取响应。它是EV_TXEMPTY的非托管形式,我不记得它是如何封装在托管方面的-我们的RS485代码早于.NET comport组件。 您可以使用timeBeginPeriod(1)调用对计时器芯片进行重新编程,以在Thread.Sleep()上获得1毫秒的分辨率。 对于它的价值,我们在发送后仅短暂睡眠(1毫秒),然后进入读取循环,在该循环中,我们继续尝试从端口读取(再次,两次读取之间有1毫秒的延迟),直到收到完整的响应为止收到(或者直到超时或重试计数器用尽)。 这是timeBeginPeriod的导入声明-我不认为它可以在.NET中直接使用(还可以吗?):
[DllImport(\"winmm.dll\")]
internal static extern uint timeBeginPeriod(uint period);   
我希望这有帮助。     

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...