Cześć.
Mam pewien problem otóż napisałem prosty program w c# (Windows Form ) który komunikuję się z moim układem. Wybieram port com w ComboBox klikam połącz i wysysałam po rs 232 dane string "polaczono) na co mój układ odpowiada "ok" i tutaj mam problem jak odebrać dane i na nie zareagować i ewentualnie wyświetlić błąd jeżeli układ nie odpowie?
Pozdrawiam i dziękuje za każda wskazówkę ;)
Najlepiej użyj jakiejś biblioteki która ukryje pewne niemiłe aspekty komunikacji asynchronicznej i wystawie odbiór danych od urządzenia pod zwykłym C#'owym event'em. To może nie najpopularniejsze ale demonstruje jak bardzo może być to proste: https://github.com/genielabs/serialport-lib-dotnet/
Ważna rzecz jest taka że wątek użyty przez tą bibliotekę nie może bezpośrednio operować na GUI. Jeżeli chcesz zmienić GUI to musisz to robić przez Invoke (https://docs.microsoft.com/en-us/dotnet/desktop/winforms/controls/how-to-make-thread-safe-calls-to-windows-forms-controls?view=netframeworkdesktop-4.8).
Powodzenia!
Dziękuję za odpowiedź, w takim razie dużo nauki mnie czeka, myślałem że da się prościej ;)
Już odbieram dane z rs232 i wyświetlam w Rich TextBox . Nie wiem jak zrobić działanie na zasadzie program w c# wysyła string do układu a układ odpowiada OK. W jakie sposób po wysłaniu stringu czekać na odpowiedź układu?
serialPort1.Write(polaczenie);
//tutaj chcę czekać na odpowiedź układu czy dostał odpowiedź a jak nic nie dostanę wyświetlić błąd
private void SerialPortDataReceived(object sender, SerialDataReceivedEventArgs e)
{
var serialPort = (SerialPort)sender;
var data = serialPort.ReadExisting();
SetText(data);
}
delegate void SetTextCallback(string text);
private void SetText(string text)
{
if (this.rtxtDataArea.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.rtxtDataArea.AppendText(text);
}
}
W jaki sposób odczekać sekundę ale nie blokować programu to znaczy żeby w trakcie czekania był wstanie odebrać dane z rs232?
Zrobiłem taką protezę otóż działa to w taki sposób że jak od komentuję MessageBox.Show("komunikat "); to wyświetli mi się on i klikam ok w tym czasie program odbierze OK i wykonuję mi się if jednak jak za komentuję MessageBox.Show("komunikat "); to program zawiesza się w while (_tick < 3 ). Może kolega podpiwedzieć mniej więcej jak to zrobić bo nie jestem pewny czy mam dobrą koncepcję pomijając już wykonanie.
Pozdraiwiam
while (_tick < 3 )
{
//MessageBox.Show("komunikat ");
if (datainput == "OK")
{
MessageBox.Show("Polaczono ");
return;
}
}
if (_tick>=3) MessageBox.Show("Blad Polaczenia");
private void timer1_Tick(object sender, EventArgs e)
{
_tick++;
}
edit. skorzystałem z:
await Task.Delay(500);
edit 2:
Prawei moja funkcja działa dobrze lecz czasami odebrany string nie jest cały otóż wysyłam do PC "OK/n" , jednak czasami podczas pracy programu dostaję string "K/n" lub "/n" nie wiem czym jest to spowodowane. Oczywiście sprawdzałem to na terminalu i układ wysyła dane dobre. Zauważyłem że im mniej ustawię task.delay to problem staje się mneijszy.
string polaczenie = "programowanie" + "\r";
datainput = "no";
serialPort1.Write(polaczenie);
// await Task.Delay(500);
await Task.Delay(30);
if (datainput == "OK\n")
{
// MessageBox.Show("Polaczono ");
progressBar1.Value = 100;
}
else
{
// MessageBox.Show("Blad Polaczenia");
progressBar1.Value = 60;
}
Programowanie asynchroniczne, zadania (Task), ale chyba nie obie metody naraz - to, moim zdaniem, rozwiąże Twój problem.
O tym myślałem. Tam kody wykonywane asynchronicznie mają dość duże oczekiwanie - Task.Delay(3000).Wait(). Nic wtedy nie robią i można je przeplatać, aby wykorzystać te przerwy. Gdybyś chciał przeplatać kody coś robiące, to można np tak:
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
namespace AsyncBreakfast
{
class Program
{
const int n = 805_457_000;
static void Main(string[] args)
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
Coffee cup = PourCoffee();
Console.WriteLine("coffee is ready");
Task<Bacon> baconTask = Task.Run(() => FryBacon(3) );
Task<Egg> eggsTask = Task.Run(() => FryEggs(2));
Task<Toast> toastTask = Task.Run(() => ToastBread(2));
Juice oj = PourOJ();
Console.WriteLine("oj is ready");
baconTask.Wait();
Bacon bacon = baconTask.Result;
Console.WriteLine("bacon is ready");
eggsTask.Wait();
Egg eggs = eggsTask.Result;
Console.WriteLine("eggs are ready");
toastTask.Wait();
Toast toast = toastTask.Result;
ApplyButter(toast);
ApplyJam(toast);
Console.WriteLine("toast is ready");
Console.WriteLine("Breakfast is ready!");
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
string elapsedTime = string.Format("{0:00}:{1:00}:{2:00}.{3:00}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10);
Console.WriteLine("Czas wykonania " + elapsedTime);
Console.ReadKey();
}
private static Juice PourOJ()
{
Console.WriteLine("Pouring orange juice");
return new Juice();
}
private static void ApplyJam(Toast toast) =>
Console.WriteLine("Putting jam on the toast");
private static void ApplyButter(Toast toast) =>
Console.WriteLine("Putting butter on the toast");
private static Toast ToastBread(int slices)
{
for (int slice = 0; slice < slices; slice++)
{
Console.WriteLine("Putting a slice of bread in the toaster");
}
Console.WriteLine("Start toasting...");
for (int i = 0; i < n; i++) { }
Console.WriteLine("Remove toast from toaster");
return new Toast();
}
private static Bacon FryBacon(int slices)
{
Console.WriteLine($"putting {slices} slices of bacon in the pan");
Console.WriteLine("cooking first side of bacon...");
for (int i = 0; i < n; i++) { }
for (int slice = 0; slice < slices; slice++)
{
Console.WriteLine("flipping a slice of bacon");
}
Console.WriteLine("cooking the second side of bacon...");
for (int i = 0; i < n; i++) { }
Console.WriteLine("Put bacon on plate");
return new Bacon();
}
private static Egg FryEggs(int howMany)
{
Console.WriteLine("Warming the egg pan...");
for (int i = 0; i < n; i++) { }
Console.WriteLine($"cracking {howMany} eggs");
Console.WriteLine("cooking the eggs ...");
for (int i = 0; i < n; i++) { }
Console.WriteLine("Put eggs on plate");
return new Egg();
}
private static Coffee PourCoffee()
{
Console.WriteLine("Pouring coffee");
return new Coffee();
}
}
internal class Toast
{
public Toast()
{
}
}
internal class Bacon
{
public Bacon()
{
}
}
internal class Egg
{
public Egg()
{
}
}
internal class Juice
{
}
internal class Coffee
{
}
}
@Sadam2: Wywołuję funkcję FryBacon i dodaję ją do task dzięki czemu wykonuje się w tle?
Task<Bacon> baconTask = Task.Run(() => FryBacon(3));
W tym miejscu czekam na rezultat funkcji? ale z tego ro rozumiem nie blokująco?
baconTask.Wait();
Do czego służy klasa Bacon?
internal class Bacon
{
public Bacon()
{
}
}
Tak wygląda u mnie funkcja przycisku otwierająca port i sprawdzająca czy połączona się z układem:
private async void btnOpen_Click(object sender, EventArgs e)
{
try
{
serialPort1.PortName = cBoxCOMPORT.Text;
serialPort1.BaudRate = 115200;//Convert.ToInt32(CBoxBaudRate.Text);
serialPort1.DataBits = 8;// Convert.ToInt32(CBoxDataBits.Text);
serialPort1.StopBits = StopBits.One;
serialPort1.Parity = Parity.None;
serialPort1.Open();
serialPort1.DataReceived += SerialPortDataReceived;
string polaczenie = "programowanie" + "\r";
datainput = "no";
serialPort1.Write(polaczenie);
await Task.Delay(200);
if (datainput == "OK\n")
{
// MessageBox.Show("Polaczono ");
progressBar1.Value = 100;
}
else
{
// MessageBox.Show("Blad Polaczenia");
progressBar1.Value = 60;
}
btnOpen.Enabled = false;
btnClose.Enabled = true;
bntSendData.Enabled = true;
}
catch (Exception err)
{
MessageBox.Show(err.Message,"blad", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
@henryxxl: Trochę inaczej. W przykładzie na asynchroniczność, który podałeś, występuje Task.Delay... .Zastąp to pętlą for trwającą mniej więcej tyle samo (wszystkie tego wystąpienia) i zobacz wynik. Ilość obrotów tej pętli dobrałem na swojej maszynie - na Twojej może być inna. Cały przykład, który podałem, to jest jakby realizacja tego ich przykładu asynchronicznego w sytuacji, gdy nie ma zysku czasowego z asynchroniczności. Klasy Toast, Bacon i Egg niepotrzebnie mają konstruktory ale reszta, jak mi się zdaje, oddaje podany tam przebieg.
Funkcja FryBacon wykonuje się w tle równolegle do FryEggs i ToastBread. Na rezultat FryBacon czekasz blokująco - ale czekasz, bo chcesz wyświetlić wynik. W trakcie tego czekania nadal wykonują się FryEggs I ToastBread.
Dołóż sobie przycisk do wyświetlania jakiegoś komunikatu, wydłuż znacznie czas oczekiwania na odpowiedź i sam zobacz, czy oczekiwanie blokuje Ci interfejs użytkownika.