Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/305.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
STM32和C#应用程序中的UART通信错误_C#_Arduino_Stm32 - Fatal编程技术网

STM32和C#应用程序中的UART通信错误

STM32和C#应用程序中的UART通信错误,c#,arduino,stm32,C#,Arduino,Stm32,请原谅我这个令人困惑的问题。我发现它很难描述,因为它涉及面广,令人厌烦。读了它,你就会知道为什么 我在这个问题上纠缠了一个多月,至今没有多大进展。我使用STM32(安装在BluePill板上的STM32F103C8)通过FT232r串行USB转换器与C#应用程序通信。完整的通信协议有点复杂。我在这里编写的代码过于简单,可以非常准确地解释我的问题 STM32执行以下操作 在初始设置中 串行。从2000000开始(是的,它非常高,但我用示波器分析过,信号非常健康;阻抗匹配和时钟抖动非常准确) 等待

请原谅我这个令人困惑的问题。我发现它很难描述,因为它涉及面广,令人厌烦。读了它,你就会知道为什么

我在这个问题上纠缠了一个多月,至今没有多大进展。我使用STM32(安装在BluePill板上的STM32F103C8)通过FT232r串行USB转换器与C#应用程序通信。完整的通信协议有点复杂。我在这里编写的代码过于简单,可以非常准确地解释我的问题

STM32执行以下操作

在初始设置中

  • 串行。从2000000开始(是的,它非常高,但我用示波器分析过,信号非常健康;阻抗匹配和时钟抖动非常准确)

  • 等待来自C#end的命令进入循环

  • 在循环中,它执行以下操作

  • 在串行端口上发送长度为N的字节缓冲区。数据包结构为0xAA,N字节,1字节校验和
  • 重复这个循环
  • 在C#端(伪代码)

  • 新线程(()=>{while(true)IOTick();Thread.Sleep(30);}).Start() readBytes定义为

     int readBytes(byte[] buffer, int count, int timeout)
        {
            var st = DateTime.Now;
            for (int i = 0; i < count; i++)
            {
                var b_ = read(timeout);
                if (b_ == -1)
                    return i;
                buffer[i] = (byte)b_;
                timeout -= (int)(DateTime.Now - st).TotalMilliseconds;
            }
            return count;
        }
    
    
        int buffer2ReadIndex = 0;
        byte[] buffer2= new byte[0];
    
        int read(int timeout)
        {
            DateTime start = DateTime.Now;
    
            if (buffer2.Length == 0)
            {
                while (SerialPortObject.BytesToRead <= 0)
                {
                    if ((DateTime.Now - start).TotalMilliseconds > timeout)
                        return -1;
                    System.Threading.Thread.Sleep(30);
                }
                buffer2 = new byte[SerialPortObject.BytesToRead];
                sp.Read(buffer2, 0, buffer2.Length);
            }
            if (buffer2.Length > 0)
            {
                var b = buffer2[buffer2ReadIndex];
                buffer2ReadIndex++;
                if (buffer2ReadIndex >= buffer2.Length)
                {
                    buffer2ReadIndex = 0;
                    buffer2 = new byte[0];
                }
                return b;
            }
            return -1;
        }
    
    int readBytes(字节[]缓冲区、int计数、int超时)
    {
    var st=DateTime.Now;
    for(int i=0;i0)
    {
    var b=buffer2[buffer2ReadIndex];
    buffer2ReadIndex++;
    如果(buffer2ReadIndex>=buffer2.Length)
    {
    buffer2ReadIndex=0;
    buffer2=新字节[0];
    }
    返回b;
    }
    返回-1;
    }
    
    现在,一切都按预期进行。数据包接收软件事件不迟于每30毫秒(windows滴答时间)触发一次。如果必须在STM端的每个数据包发送之间等待,则问题开始。首先,我怀疑我用于每个数据包发送之间的某些任务的I2C导致了与串行数据的某些硬件或软件冲突,从而导致数据损坏。但后来我注意到,只有在每个数据包发送之间使用Arduino delay()引入1毫秒的延迟,才会发生同样的情况。现在几乎每秒接收1K个数据包。在成功的报头异常后,几乎每10个数据包中就有1个未完全交付或交付的校验和已损坏,从而导致C#应用程序丢失数据包报头。新的头跟踪显然需要刷新一些字节,从而在通信中丢失一些数据包。即使对于一个能够承受5%数据包丢失的应用来说,这听起来也不算太糟糕,但奇怪的是,当这种异常发生时,数据包接收到的软件中断会在每几百个连续事件后等待超过1秒


    我在这里完全瞎了。即使尝试使用115200波特率,也会以略低的损耗率进行相同的损耗。应该注意的是,在9600波特时,问题不会发生。这是我现在得到的唯一提示。

    看来我找到了答案

    在深入挖掘SerialPort和SerialPort.base stream类并进行一些文档阅读和基准测试之后,我观察到: SerialPort.BytesToRead更新不统一。DataReceived事件似乎正在跟踪它。当字节达到~200kHz(波特率=2Mbps)时,它几乎会立即更新(最坏的情况是在30ms内)。当它们以约20kHz或更低的频率(使用micrcontroller在时间上均匀间隔)出现时,SerialPort.BytesToRead最多需要400ms才能更新。只有经过十几次30毫秒的更新后才会发生这种情况

    因此,观察到这一点,我可以说SerialPort.BytesToRead在两个条件下更新。数据到达后经过了一段时间(此时间不限于30毫秒),或者数据过快


    这是一种奇怪的行为。发生此异常时,不会丢失任何数据。毫不奇怪,在全带宽(200KBps,波特率为2Mbps)下工作时,0.06%的字节丢失。

    Thread.Sleep(30)有点令人担忧。您可以在每个循环中占用所有处理器时间,只要处理器在需要完成其他工作时让步;尝试
    Thread.Sleep(1)或者,重写代码,使其使用硬件中断而不是轮询从串行端口检索数据(这可能是更好的方法)。请看一个例子。@RobertHarvey,据我理解,Thread.Sleep(1)不会比Sleep(30)好多少。现在不是窗户滴答作响的时间吗?i、 e.一旦线程产生,windows不会在25-30毫秒之前返回上下文?@RobertHarvey。关于硬件中断,它在MS docs here()上说,串行端口不能保证接收到的每个字节都有一个事件。另外,它需要一个与我的协议不符的EOF字符。
    。。。不能保证接收到的每个字节都有一个事件
    ——这是正确的。您必须读得更远一点:
    使用BytesToRead属性来确定要从缓冲区读取的数据量。
     int readBytes(byte[] buffer, int count, int timeout)
        {
            var st = DateTime.Now;
            for (int i = 0; i < count; i++)
            {
                var b_ = read(timeout);
                if (b_ == -1)
                    return i;
                buffer[i] = (byte)b_;
                timeout -= (int)(DateTime.Now - st).TotalMilliseconds;
            }
            return count;
        }
    
    
        int buffer2ReadIndex = 0;
        byte[] buffer2= new byte[0];
    
        int read(int timeout)
        {
            DateTime start = DateTime.Now;
    
            if (buffer2.Length == 0)
            {
                while (SerialPortObject.BytesToRead <= 0)
                {
                    if ((DateTime.Now - start).TotalMilliseconds > timeout)
                        return -1;
                    System.Threading.Thread.Sleep(30);
                }
                buffer2 = new byte[SerialPortObject.BytesToRead];
                sp.Read(buffer2, 0, buffer2.Length);
            }
            if (buffer2.Length > 0)
            {
                var b = buffer2[buffer2ReadIndex];
                buffer2ReadIndex++;
                if (buffer2ReadIndex >= buffer2.Length)
                {
                    buffer2ReadIndex = 0;
                    buffer2 = new byte[0];
                }
                return b;
            }
            return -1;
        }