首页 文章

多个SerialPort实时返回

提问于
浏览
1

我在C#中创建了一个数据记录应用程序 . 它通过SerialPort类连接到4个USB传感器 . 我在每个字节上触发了数据接收事件阈值 . 收到数据后,程序会检查该字节是否为行尾 . 如果不是,则将输入添加到缓冲区 . 如果是行结束,程序会添加时间戳并将数据和时间戳写入文件(每个输入源都会获得一个专用文件) .

使用多个COM端口输入时出现问题 . 我在输出文件中看到的是:

4个文件中的任何一个:

...
timestamp1 value1
timestamp2 value2
timestamp3 value3
value4
value5
value6
timestamp7 value7
...

所以,它看起来是计算机速度不够快,无法在下一个值到达之前获得所有4个中断 . 我有充分的理由相信这是罪魁祸首,因为有时我会看到这样的输出:

...
timestamp value
timestamp value
value
val
timestamp ue
timestamp value
...

这可能是由于我将处理器关联性更改为仅在Core 2上运行 . 我这样做是因为我使用的时间戳是用处理器周期计算的,所以我不能有多个时间参考,具体取决于哪个核心是运行 . 我在下面放了一些代码片段;任何可能有助于删除时间戳的建议将不胜感激!

public mainLoggerIO()
    {
        //bind to one cpu
        Process proc = Process.GetCurrentProcess();
        long AffinityMask = (long)proc.ProcessorAffinity;
        AffinityMask &= 0x0002; //use only the 2nd processor
        proc.ProcessorAffinity = (IntPtr)AffinityMask;

        //prevent any other threads from using core 2
        Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;
        Thread.CurrentThread.Priority = ThreadPriority.Highest;

        long frequency = Stopwatch.Frequency;
        Console.WriteLine("  Timer frequency in ticks per second = {0}",
            frequency);
        long nanosecPerTick = (1000L * 1000L * 1000L) / frequency;
        Console.WriteLine("  Timer is accurate within {0} nanoseconds",
            nanosecPerTick);

        if (Stopwatch.IsHighResolution)
            MessageBox.Show("High Resolution Timer Available");
        else
            MessageBox.Show("No High Resolution Timer Available on this Machine");

        InitializeComponent();
    }

等等 . 每个数据返回中断如下所示:

private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
    {
        //serialPort1.DataReceived = serialPort1_DataReceived;
        rawPort1Data = "";
        rawPort1Data = serialPort1.ReadExisting();
        this.Invoke((MethodInvoker)delegate { returnTextPort1(); });
    }

returnTextPort#()方法是:

private void returnTextPort1()
    {
        if (string.Compare(saveFileName, "") == 0)//no savefile specified
            return;
        bufferedString += rawPort1Data;
        if(bufferedString.Contains('\r')){
            long timeStamp = DateTime.Now.Ticks;
            textBox2.AppendText(nicknames[0] + " " + timeStamp / 10000 + ", " + rawPort1Data);
            //write to file
            using (System.IO.StreamWriter file = new System.IO.StreamWriter(@saveFileName, true))
            {
                 file.WriteLine(nicknames[0] + " " + timeStamp / 10000 + ", " + rawPort1Data);//in Ms
            }
            bufferedString = "";
        }

    }

1 回答

  • 1

    更简洁的方法是在数据接收事件处理程序和处理结果数据的单独线程之间使用 ConcurrentQueue<T> . 这样,事件处理程序可以立即返回AND而不是以完全非线程安全的方式修改 rawPort1 数据,您可以转移到线程安全的解决方案 .

    创建一个从并发队列读取的线程,写入文件并调用UI更改 . 请注意,写入文件不应该在UI线程上 .

    您的 ConcurrentQueue<T> 可以在将要实现的类 T 中捕获:端口号,接收的数据以及接收它的时间戳 .

    另请注意, DateTime.Now 很少是正确的答案,对于大多数地方,当夏令时开始或结束时,它每年跳两个小时,而不是 DateTime.UtcNow . 但请注意,您似乎没有尝试使用 StopWatch 代码获得的准确性 .

    您不需要操作进程或线程优先级来执行此操作:串行端口有一个缓冲区,只要您有效地处理它,就不会错过数据 .

相关问题