Witam,
Moim zadaniem jest napisanie aplikacji, która pobierze dane z SerialPort, przetworzy i wyświetli na wykresie. Do tego celu mam specjalną płytkę - moją na której siedzi STM32 i wysyła dane strumieniowo na żądanie aplikacji. Danych jest ograniczona ilość.
Aplikacja jest i działa, ale niestety podczas rejestracji danych wszystko jest zablokowane (jeden wątek). Postanowiłem ulepszyć to cudo i napisać wielowątkowo, tak aby dane były odświeżane na wykresie w "czasie rzeczywistym" oraz abym mógł przerwać rejestrację. Niestety czytanie o Multithreading w Google nie wiele mi na razie daje dlatego postanowiłem poprosić o wskazówki, przykładowe kody i ew. wyjaśnienia.
W mojej Aplikacji stworzyłem klasę board.cs która reprezentuje moją płytkę. Po wywołaniu metody RegisterData dzieje się to:
public void RegisterData(UInt16 TimeMeas)
{
intTimeMeas = (int)(TimeMeas) + 2;
RxData.Clear();
ActiveSignal = 1;
Usart.DiscardInBuffer();
string line = "Data=" + TimeMeas.ToString();
DataTransferIsComplete = false;
Console.WriteLine(line);
UsartTimer.Enabled = true;
Usart.WriteLine(line);
TimerTick = 0;
while (!DataTransferIsComplete)
{
Application.DoEvents();
System.Threading.Thread.Sleep(10);
}
RxData.Clear();
ActiveSignal = 2;
Usart.DiscardInBuffer();
line = "Data2?";
DataTransferIsComplete = false;
Console.WriteLine(line);
UsartTimer.Enabled = true;
Usart.WriteLine(line);
while (!DataTransferIsComplete)
{
System.Threading.Thread.Sleep(10);
Application.DoEvents();
}
}
Metoda jako argument przyjmuje czas rejestracji danych w [s]. Po wysłaniu do urządzenia polecenia: "Data=5\n" płytka odsyła mi przez 5 sekund dane. Po zakończeniu transferu, proszę o drugi zestaw danych poleceniem "Data2?\n" i odbieram.
Zmienna DataTransferIsComplete jest ustawiana w moim Timerze po przekroczeniu Timeoutu....
Poniżej odbiór danych i obsługa tick timera:
private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
TimerTick = 0;
byte[] data = new byte[Usart.BytesToRead];
Usart.Read(data, 0, data.Length);
RxData.AddRange(data);
}
catch (Exception ex)
{
throw ex;
}
}
private void UsartTimerTick(object sender, EventArgs e)
{
TimerTick++;
clk++;
UpdateProgress(100 * clk / (intTimeMeas * 10));
if (TimerTick > 20)
{
Console.WriteLine("Odebrano danych: " + RxData.Count);
UsartTimer.Enabled = false;
TimerTick = 0;
if (ActiveSignal == 1)
{
Data1 = ConvertRxDataToData(RxData);
}
else
{
Data2 = ConvertRxDataToDataTwo(RxData);
clk = 0;
UpdateProgress(0);
}
DataTransferIsComplete = true;
}
}
W każdym wywołaniu port_DataReceived jest zerowana zmienna TimerTick . Jeżeli dane przestają przychodzić to TimerTick przekracza 20 i rozpoczynam obliczenia na danych a dopiero na koniec po za klasą board wywołuje:
Chart.Series["Data1"].Points.DataBindY(board.GetData1());
Chart.Series["Data2"].Points.DataBindY(board.GetData2());
Jak widać odbieram dwa strumienie. Najpierw jeden, potem drugi. Zależy mi na tym aby ten pierwszy był w czasie rzeczywistym rysowany na charcie, ten drugi jest krótki i nie musi być.
Próbowałem dokonywać obliczeń i wyświetlać na wykresie metodzie port_DataReceived ale rzucało wyjątkiem, że dane są modyfikowane przez inny wątek. No bo przecież ta metoda działa już winnym wątku. Nie wiem za bardzo jak to połączyć więc proszę o jakieś wskazówki...