0

リアルタイムデータをプロットしようとしています。回路はデータを高速で送信し、最初のバイトが「$」、次の 16 バイトがサウンド、最後のバイトが脈拍センサー データであることを知っています。最後のインデックス。

byte[] Read_Data1 = new byte[100000];
byte[] Read_Data2 = new byte[100000];
byte[] Read_Data3;
private void myPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    if (!myPort.IsOpen)
    return;
    while (myPort.BytesToRead > 0)
    {
        int bytes = myPort.BytesToRead;
        byte[] buffer = new byte[bytes];
        myPort.Read(buffer, 0, bytes);
        bytetobyte(Read_Data1, buffer, buffer.Length, count);
        count += buffer.Length;
    }
}
public void bytetobyte(byte[] Storage, byte[] databyte, int datacount, int count)
{
    //count comes from count += buffer.Lenght
    int abc;
    for (abc = 0; abc < datacount; abc++)
    {
        Storage[abc+count] = databyte[abc];
    }
}

次に、タイマーのティックで動作するメソッドを使用してデータの処理を開始します。最初のバイト「$」を削除し、16 バイトをリストに保存し、1 バイトを別のリストに保存する必要があります。メソッドは次のとおりです。

byte[] Read_Data3;
LinkedList<byte> data;
public void DrawingAudioData(byte[] data) //This method works inside timer.
{
    Read_Data2 = Read_Data1;
    int lastCount = count;
    int division = count / 18;
    int remaning = (count - 18 * division);

    Read_Data3 = new byte[count - remaning];

    for (int i = 0; i < count - remaning ; i++)
    {
        Read_Data3[i] = Read_Data2[i];
    }
    count = 0;

    IPointListEdit listAuido = curveAudio.Points as IPointListEdit;
    IPointListEdit listPulse = curvePulse.Points as IPointListEdit;

    XDate time = new XDate(DateTime.Now);

    if (Read_Data3 == null)
    return;
    data= new LinkedList<byte>(Read_Data3);

    if(data.First == null)
    return;
    if (data.Count >= 18 & data.ElementAt(0) == Convert.ToByte('$'))
    {
        data.Remove(veri.ElementAt(0));
        for (int x = 0; x < 16; x++)
        {
            listAuido.Add(time, data.ElementAt(0));
            data.Remove(data.ElementAt(0));
        }
        listPulse.Add(time, data.ElementAt(0));
        data.Remove(data.ElementAt(0));
    }
    lastCount = 0;
}

シリアルポートはデータを急速に送信し、データは Read_Data1 内で変更されるため、タイマーが刻むと新しいバイトが必要になると思います。その後、カウントをゼロに等しくします。データはまだ流れており、配列が範囲外になりたくないためです。次に、新しい Read_Data2 の処理を​​開始します。前に述べたように、18 バイトごとに処理する必要があるため、Read_Data2 をトリミングし、残りの最後のいくつかのデータを削除して、イコライズRead_Data3[i]=Read_Data2[i];します。LinkedListRead_Data3 が含まれているため、リストに入力した後に最初のデータを削除するループを記述しようとしました。LinkedList を処理した後、lastCount はゼロに等しくなります。これは、新しいデータ セットに従って新しいサイズを設定する必要があるためです。ロジックは正しいように見えますが、問題があります。脈拍センサーのデータが音声データにリストされることがあります。つまり、データは listPulse 内にある必要がありますが、listAudio に入ります。

まず、アプローチが正しいアプローチであることを知りたいです。タイマーを使用することは、迅速なデータには良い考えですか? ご意見をお聞かせください。より良い方法があれば、教えていただくか、参考記事やサンプルのリンクを教えてください。ありがとうございました。

4

2 に答える 2

0

タイマーの代わりに、ロックまたはミューテックスを使用したダブルバッファリングを使用して、読み取りと書き込みの共有リソースとなるバッファーへのアクセスを制御します。また、SerialPort.DataReceived イベント内から呼び出された SerialPort.Read(byte[],int,int) メソッドは、新しいスレッドで既に自動的に実行されています。

問題は、同じメモリ位置を同時に読み書きしようとすると発生します。これを回避する 1 つの方法は、2 つのバッファー (バイト型の配列) を使用し、グラフ作成コードがもう一方から読み取りを行っている間に、一方に書き込みを行うことです。この場合、バッファは共有リソースと呼ばれ、アクセスを規制する必要があります。ロックを使用することもできますが、通常はバッファーごとに 1 つのミューテックスを使用します。ミューテックスをインスタンス化した後、「WaitOne」メソッドを呼び出します。これにより、共有リソースを使用したい他のコードは、ミューテックスが解放されるまで強制的に待機します。このように見えるかもしれません。

  void OnDataReceived(object sender, SerialDataReceivedEventArgs e)
    {
        if (writeToBuffer1)
        {
            numToRead1 = SerialPort.BytesToRead;
            mutex1.WaitOne();
            numRead1 = SerialPort.Read(buffer1, 0, numToRead1);
            mutex1.ReleaseMutex();
            writeToBuffer1 = false;
            PlotData(buffer1, numRead1);
        }
        else
        {
            numToRead2 = SerialPort.BytesToRead;
            mutex2.WaitOne();
            numRead2 = SerialPort.Read(buffer2, 0, numToRead2);
            mutex2.ReleaseMutex();
            writeToBuffer1 = true;
            PlotData(buffer2, numRead2);
        }
    }

PlotData メソッドには、mutex1 と mutex2 へのアクセスも必要です。WaitOne メソッドと ReleaseMutex メソッドでバイトを読み取るコードを囲みます。また、作成されたスレッド以外のスレッドから呼び出せるように、プロット データ メソッドへのスレッド セーフな呼び出しを記述する方法を学習する必要があります。 スレッドセーフな方法

于 2013-11-15T17:24:49.413 に答える