我正在尝试绘制实时数据。一个电路快速发送数据,我知道第一个字节是'$',接下来的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;
}
我认为当计时器滴答时我应该有一个新字节,因为serialport快速发送数据并且数据在Read_Data1内部被更改。之后我将数均衡为零。因为数据仍然流动,我不希望我的阵列没有响了。然后我开始处理新的Read_Data2。我必须像前面说过的那样处理每个18个字节,所以我修剪了Read_Data2并删除了最后几个数据,并且我平衡Read_Data3[i]=Read_Data2[i];
然后使用包含Read_Data3的LinkedList
,我尝试编写一个删除的循环将其填入列表后的第一个数据。在处理LinkedList之后,lastCount等于零,因为我应该根据新数据集设置新的大小。看起来逻辑是真的,但我有一个问题。有时脉冲传感器数据列入音频数据。我的意思是数据应该在listPulse中,但它会进入listAudio。
首先,我想知道方法是正确的方法。我的意思是使用计时器是一个快速数据的好主意?请分享您的意见。如果您有更好的方法,请告诉我或提供参考文章或样本的链接。谢谢。
答案 0 :(得分:0)
尝试以这种方式修改代码:
byte[] Read_Data3;
LinkedList<byte> data;
object w=new object(w)
public void DrawingAudioData(byte[] data) //This method works inside timer.
{
lock(w}
{
//Your previous code here
}
}
通过这种方式,你不应该再有关于listPulse,listAuido,Read_Data3,Read_Data2之间的混合数据的问题。
为了正常工作,该方法必须在一段时间内执行&lt;计时器
答案 1 :(得分:0)
我将使用带有锁或互斥锁的双缓冲来控制对缓冲区的访问,而不是计时器,缓冲区将是用于读取和写入的共享资源。此外,从SerialPort.DataReceived事件内部调用时的SerialPort.Read(byte [],int,int)方法已在新线程上自动执行。
当您尝试同时读取和写入相同的内存位置时,会出现问题。解决此问题的一种方法是使用2个缓冲区(字节类型的数组),并在图形代码从另一个读取时写入其中一个缓冲区。在这种情况下,缓冲区称为共享资源,应对其访问进行管理。您可以使用锁,但我通常为每个缓冲区使用一个互斥锁。实例化互斥锁后,调用“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方法搜索字节的代码。您还需要学习如何编写对绘图数据方法的线程安全调用,以便可以通过除创建它之外的线程调用它。 Thread-safe method