sobota, 8 kwietnia 2017

C# - Program komunikacyjny po Usarcie wersja V1.1

Tym razem chciałem przedstawić trochę zmienioną wersję programu komunikacyjnego po porcie COM.

Zmianie  uległ sposób wprowadzania danych oraz zostało dodane rysowanie wykresów dla procesora oraz dla portu COM. Usunąłem też dodatkowe zakładki, będą one dodawane w kolejnych wersjach programu.

Wykres danych od USART-u:


Tutaj w pierwszej kolejności został przygotowany program testowy dla Arduino Uno. Prezentuje się on następująco:

  1. int data = 0;
  2. void setup()
  3. {                
  4.   pinMode(13, OUTPUT);    
  5.   Serial.begin(115200);
  6.   while (!Serial) { ; }
  7.   Serial.println("Start_Dat_Proto_Chart");
  8. }
  9. void loop()
  10. {
  11.   for(data=0;data<300;data++)
  12.   {
  13.     Serial.print('[');
  14.     Serial.print(data);
  15.     Serial.print(';');
  16.     Serial.print(data+10);
  17.     Serial.print(';');
  18.     Serial.print(data+20);
  19.     Serial.print(';');
  20.     Serial.print(data+30);
  21.     Serial.println(']');
  22.     delay(1000);
  23.   }
  24. }

Jego zadaniem jest przesyłanie danych od 0 do 255 co 1 sekundę w odpowiednio przygotowanej ramce. Otwarcie następuje po wysłaniu znaku nawiasu "[", po tym znaku następuje przesłanie pierwszych danych, dalej po przecinku następne porcje danych są dodawane. Odzielenie poszczególnych znaków następuje przy wykorzystaniu znaku ";".

Teraz czas na opisanie programu od strony Visual Studio.

Okno programu prezentuje się następująco:


Tym razem dane wysyłane i odbierane od mikrokontrolera będą wypisywane w oknie tekstowym po lewej stronie. Wykres znajdujący się z prawej strony posłuży do rysowania wykresu, tych samych danych jakie będą wyświetlane w formie tekstowej.

Zasada odbierania danych jest identyczna co w poprzednim poście dotyczącym komunikacji poprzez UART. Różnica polega na wyłuskiwaniu pojedynczych danych z pakietu, i łączenia ich w całość.

Przykładowa ramka danych wygląda następująco:

[dane1,dane2,dane3,dane4]

Pobrane informacje są zamieniane na wartość int, która po zamianie rysuje wykres na ekranie. Maksymalnie można wyrysować jednocześnie cztery wykresy. Ilość danych wybiera się poprzez wykorzystanie checkboxa na dole ekranu. Dane do układu interpretowane są z wartości dziesiętnych wpisanych w kodzie ASCII. Funkcja obsługująca bufor wygląda następująco:

  1.         private void Check_Received_dat()
  2.         {
  3.             byte j=1;
  4.             byte i=0;
  5.             char[] chars = new char[10];
  6.             string datConverted;
  7.             char[] chars2 = new char[100];
  8.             chars2 = data2.ToCharArray();
  9.             richTextBoxTerminal.AppendText(data2);
  10.             if (chars2[0] == '[')
  11.             {
  12.                 i = 0; j = 1;
  13.                 while (chars2[j] != ';')
  14.                 {
  15.                     chars[i] = chars2[j];
  16.                     i++;
  17.                     j++;
  18.                 }
  19.                 datConverted = string.Join("", chars);
  20.                 int dat = int.Parse(datConverted);
  21.                 if (checkBoxSeries1.Checked == true)
  22.                 {
  23.                     chart1.Series["Series1"].Points.AddY(dat);
  24.                 }
  25.                 j++;
  26.                 i = 0;
  27.                 Array.Clear(chars, 010);
  28.                
  29.                 if(chars2[j] == ']')
  30.                 {
  31.                     return;
  32.                 }
  33.                
  34.                 //=============================================
  35.                 while (chars2[j] != ';')
  36.                 {
  37.                     chars[i] = chars2[j];
  38.                     i++;
  39.                     j++;
  40.                 }
  41.                 datConverted = string.Join("", chars);
  42.                 dat = int.Parse(datConverted);
  43.                 if (checkBoxSeries2.Checked == true)
  44.                 {
  45.                     chart1.Series["Series2"].Points.AddY(dat);
  46.                 }
  47.                 j++;
  48.                 i = 0;
  49.                 Array.Clear(chars, 010);
  50.                 if (chars2[j] == ']')
  51.                 {
  52.                     return;
  53.                 }
  54.                 //=============================================
  55.                 while (chars2[j] != ';')
  56.                 {
  57.                     chars[i] = chars2[j];
  58.                     i++;
  59.                     j++;
  60.                 }
  61.                 datConverted = string.Join("", chars);
  62.                 dat = int.Parse(datConverted);
  63.                 if (checkBoxSeries3.Checked == true)
  64.                 {
  65.                     chart1.Series["Series3"].Points.AddY(dat);
  66.                 }
  67.                 j++;
  68.                 i = 0;
  69.                 Array.Clear(chars, 010);
  70.                
  71.                 if (chars2[j] == ']')
  72.                 {
  73.                     return;
  74.                 }
  75.                 //=============================================
  76.                 while (chars2[j] != ']')
  77.                 {
  78.                     chars[i] = chars2[j];
  79.                     i++;
  80.                     j++;
  81.                 }
  82.                 datConverted = string.Join("", chars);
  83.                 dat = int.Parse(datConverted);
  84.                 if (checkBoxSeries4.Checked == true)
  85.                 {
  86.                     chart1.Series["Series4"].Points.AddY(dat);
  87.                 }
  88.                 Array.Clear(chars, 010);
  89.             }
  90.         }

W tej funkcji wypisywane są dane standardowo w oknie, po czym sprawdzany jest format bufora danych. Dalej pobrane dane są dzielone na poszczególne linie wykresu, po czym następuje konwersja na typ int. Kolejnym krokiem jest podanie danych

Wyczyszczenie przycisku następuje po kliknięciu mniejszego przycisku "Wyczyść". Przy zdarzeniu wywoływana jest następująca funkcja.

  1.         private void buttonWyczyscSend_Click(object sender, EventArgs e)
  2.         {
  3.             chart1.Series["Series1"].Points.Clear();
  4.             chart1.Series["Series2"].Points.Clear();
  5.             chart1.Series["Series3"].Points.Clear();
  6.             chart1.Series["Series4"].Points.Clear();
  7.         }

Wykres użycia procesora:


Działa on osobno, nie współpracuje z zakładką dotyczącą portu COM. Działa ona osobno:

Cała kontrolka składa się z dwóch przycisków oraz okna z wykresem:


W głównej części programu zdefiniowany jest nowy wątek, wraz z tablicą przechowującą wyniki pomiarów.

  1.         private Thread CPU_Use_Thread;
  2.         private double[] cpuArray = new double[500];

Do obsługi zdarzenia oraz rysowania tego wykresu wykorzystałem następujące funkcje 

  1.         #region CPU_Use_Draw_Chart
  2.         //----------------------------------------------------------------------
  3.         //Obsługa danych dla wykresu wykorzystania procesora
  4.         private void getPerformanceCounters()
  5.         {
  6.             var cpuperfCounter = new PerformanceCounter("Processor Information", "% Processor Time", "_Total");
  7.             while (true)
  8.             {
  9.                 cpuArray[cpuArray.Length - 1] = Math.Round(cpuperfCounter.NextValue(), 0);
  10.                 Array.Copy(cpuArray, 1, cpuArray, 0, cpuArray.Length - 1);
  11.                 if (ChartCpu_Use.IsHandleCreated)
  12.                 {
  13.                     this.Invoke((MethodInvoker)delegate { UpdateCpuChart(); });
  14.                 }
  15.             }
  16.         }
  17.         private void UpdateCpuChart()
  18.         {
  19.             ChartCpu_Use.Series["Series1"].Points.Clear();
  20.             for (int i = 0; i < cpuArray.Length - 1; i++)
  21.             {
  22.                 ChartCpu_Use.Series["Series1"].Points.AddY(cpuArray[i]);
  23.             }
  24.         }
  25.         private void button4_Click(object sender, EventArgs e)
  26.         {
  27.             CPU_Use_Thread = new Thread(new ThreadStart(this.getPerformanceCounters));
  28.             CPU_Use_Thread.IsBackground = true;
  29.             CPU_Use_Thread.Start();
  30.         }
  31.         private void button5_Click(object sender, EventArgs e)
  32.         {
  33.             CPU_Use_Thread.Abort();
  34.         }
  35.         //----------------------------------------------------------------------
  36.         #endregion

Program zmieniony można pobrać pod tym linkiem.