Hallo Community,
Ich habe folgendes Problem:
Ich bin dabei ein GUI in Visual Studio 2017 mit C# zu programmieren, mit
dem ich die Ausgänge meines Arduino's durch Buttons steuern kann. Dazu
sende ich einfach Daten über USB zum Arduino, welcher dann die Ausgänge
dementsprechend aktiviert. Soweit kein Problem, allerdings möchte ich
beim erneuten öffnen der Anwendung (z.B. nach Absturz) den aktuellen
Status der Ausgangs-Pins abragen und visuell durch verschiedene
Hintergrundfarben der Buttons anzeigen lassen. Das Arduino Sketch ist
bereits fertig, doch das C# Script bereitet mir Probleme, da ich ja die
ankommenden Daten vom Arduino vergleichen muss und wenn diese korrekt
sind soll sich ja die Hintergrundfarbe der Buttons ändern.
Wäre sehr dankbar, wenn ihr Vorschläge bzw. Code-Beispiele für mich
hättet ;)
Hier das Arduino Sketch:
Chris V. schrieb:> allerdings möchte ich> beim erneuten öffnen der Anwendung (z.B. nach Absturz) den aktuellen> Status der Ausgangs-Pins
dann sendest du dem arduino von deinem programm (nicht script) aus beim
start ein 'S' und wertest das ergebnis aus. was genau ist denn das
konkrete problem?
Sende einfach vom Arduino jede Sekunde den aktuellen Stand. Damit sparst
du dir das explizite Anfragen vom PC. Funktioniert dann auch wenn man
den Arduino neu startet.
Chris V. schrieb:> Soweit kein Problem, allerdings möchte ich> beim erneuten öffnen der Anwendung (z.B. nach Absturz) den aktuellen> Status der Ausgangs-Pins abragen und visuell durch verschiedene> Hintergrundfarben der Buttons anzeigen lassen. Das Arduino Sketch ist> bereits fertig, doch das C# Script bereitet mir Probleme, da ich ja die> ankommenden Daten vom Arduino vergleichen muss und wenn diese korrekt> sind soll sich ja die Hintergrundfarbe der Buttons ändern
suche dir ein I2C EEPROM 8-pin DIL gesockelt, ich nutze das der im Modul
Echtzeit Uhr DS3231, ist leichter und billiger auszutauschen als den
Controller.
Schreibe jede Änderung rein in ein Array und bei Neustart wird es wieder
eingelesen!
Serielle Kommunikation
SerialEvent
https://www.arduino.cc/en/Tutorial/SerialEvent
Chris V. schrieb:> beim erneuten öffnen der Anwendung (z.B. nach Absturz)Sven A. schrieb:> warum brauche ich ein eeprom, wenn ich eine c# anwendung auf einem> rechner neustarte?
also meine Arduino starten nache jedem Ansprechen der seriellen
Schnittstelle neu, ist dem Bootloader geschuldet und dann weiss mein
Arduino nicht mehr wie der Status der externen Komponenten ist, Rolladen
oben unten? Uhrzeit, Sommer Winter?, deswegen habe ich den Status im
EEPROM um auch zur Umstellung zu wissen was gilt, sonst ist man in der
Zeitschleife gefangen.
http://www.der-postillon.com/2013/10/in-zeitschleife-gefangener-mann-stellt.html
Wenn der vom TO das abfragen kann braucht er es ja nicht, war nur so
eine Idee.
Dr. Sommer schrieb:> Sende einfach vom Arduino jede Sekunde den aktuellen Stand. Damit sparst> du dir das explizite Anfragen vom PC. Funktioniert dann auch wenn man> den Arduino neu startet.
Das Anfragen vom PC ist ja nicht das Problem. Mein Problem ist dass ich
nicht weiß wie ich die Daten vom Arduino auswerten kann um damit dann
irgendetwas zu machen im C# Programm (z.B. die Farbe der Buttons
ändern). Das Problem hätte ich ja auch wenn ich jede Sekunde den Stand
übermitteln würde.
Chris V. schrieb:> Mein Problem ist dass ich nicht weiß wie ich die Daten vom Arduino> auswerten kann um damit dann> irgendetwas zu machen im C# Programm (z.B. die Farbe der Buttons> ändern). Das Problem hätte ich ja auch wenn ich jede Sekunde den Stand> übermitteln würde.
dann passt aber
Chris V. schrieb:> Ich bin dabei ein GUI in Visual Studio 2017 mit C# zu programmieren
dein ich programmiere NICHT....
du öffnest ein File Handle comN, liest ein, parst den Text und
reagierst.
Das ist doch auf jedem Compi gleich oder irre ich mich?
unter C in lcc32 war das so:
hCom = CreateFile(comPRTstr(comm.com__-1),GENERIC_READ |
GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);
du wirst doch Beispiele in Visual Studio 2017 finden?
https://stackoverflow.com/questions/45515093/how-to-write-read-data-to-a-file-in-visual-studio-2017
Joachim B. schrieb:> du öffnest ein File Handle comN, liest ein, parst den Text und> reagierst.>> Das ist doch auf jedem Compi gleich oder irre ich mich?>>>> unter C in lcc32 war das so:>> hCom = CreateFile(comPRTstr(comm.com__-1),GENERIC_READ |> GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);
Naja ich möchte ja die Daten nicht in eine Datei schreiben oder
sonstiges. Ich lese einfach Daten aus der seriellen Schnittstelle, um
diese im Programm zu visualisieren.
Da viele anscheinend mein Problem nicht ganz verstanden haben, hier mal
ein Beispiel zu meinem Versuchsaufbau in C#. Mein Problem ist jetzt
diese if-Abfrage, die so nicht funktioniert. Dafür suche ich eine Lösung
Chris V. schrieb:> Da viele anscheinend mein Problem nicht ganz verstanden haben, hier mal> ein Beispiel zu meinem Versuchsaufbau in C#. Mein Problem ist jetzt> diese if-Abfrage, die so nicht funktioniert.>
1
>if(input.Equals("0"))
2
>{
3
>button.BackColor=Color.Transparent;
4
>}
5
>elseif(input.Equals("1"))
6
>{
7
>button.BackColor=Color.Green;
8
>}
9
>
Kein Wunder, dass sie nicht funktioniert. Du prüfst auf Sachen, die dein
Arduino zu keiner Zeit sendet. Der Fehler liegt also nicht im
C#-Programm, sondern im Arduino-Programm.
Tip: Eine ASCII-Tabelle könnte dir helfen...
c-hater schrieb:> in Wunder, dass sie nicht funktioniert. Du prüfst auf Sachen, die dein> Arduino zu keiner Zeit sendet
Das ist nicht wahr.
Chris V. schrieb:> private void button_Click(object sender, EventArgs e)> {> serialport.WriteLine("S");>> string input = serialport.ReadLine();Chris V. schrieb:> switch (data) {>.....> case 'S':> Serial.println(state1);> break;
Chris V. schrieb:> Naja ich möchte ja die Daten nicht in eine Datei schreiben oder> sonstiges. Ich lese einfach Daten aus der seriellen Schnittstelle, um> diese im Programm zu visualisieren.Chris V. schrieb:> Da viele anscheinend mein Problem nicht ganz verstanden haben
nein DU verstehst nicht, auch die serielle Schnittstelle ist ein File
unter windows (DOS, Linux usw.), das musst du zum Lesen öffnen sonst
kommst du nicht an den Inhalt
Serial.println(state1);
dann sende doch "gruen" "rot"
Chris V. schrieb:> string input = serialport.ReadLine();>> if (input.Equals("0"))
"0" != 0
"1" != 1
if (input.Equals("gruen"))
if (input.Equals("rot"))
Joachim B. schrieb:> das musst du zum Lesen öffnen sonst> kommst du nicht an den Inhalt
Hat der doch. Der Comport ist anfangs an geöffnet und nirgendwo
geschlossen worden.
Ich vermute, dass der Puffer geleert worden, nachdem C# ein Zeichenkette
erhalten hat.
Chris V. schrieb:> if (input.Equals("0"))> {> button.BackColor = Color.Transparent;> }> else if (input.Equals("1"))> {> button.BackColor = Color.Green;> }
Bei C# GUI und diesem Programmierstil erschauere ich.
Ja, das ist der Weg, den glaub ich, jeder C-Starter in C# nimmt, aber er
wird schnell unendlich unübersichtlich. Eine GUI ist kein uC.
Investiere die Zeit dich für 1-3 Stunden in die Grundlagen WPF/MVVM
einzulesen. Du wirst es dir in alle Ewigkeiten danken.
Mein Vorschlag:
- Der PC ist der Master und der Arduino ist der Slave, der nur dann
antwortet wenn er gefragt wird.
- Jedes Telegramm hat ein Startzeichen (z.B. *) und einen Endzeichen
(z.B. <CR>)
- Der PC löscht öffnet den COM löscht den Empfangspuffer schickt ein
Telegramm (*xxxxxx<cr>) und wartet z.B. 50ms.
- der Slave anwortet
- der PC übernimmt die Daten aus dem InBuffer und schließt die
COM-Schnittstelle wieder.
- Dann kann der PC in Ruhe schauen was vom Slave gemeldet wurde.
Vorteile:
- Ist sicher und zuverlassig (timeout)
- erzeugt keine Abstürze oder Endlosschleifen
- Implemtierung am Slave kann man einfach mit LK Term oder anderen
Terminalprgrammen testen.
(so mache ich es immer und es funktioniert sehr zuverlässig)
Noch eine eventuelle Fehlerquelle:
Chris V. schrieb:> string input = serialport.ReadLine();
Also String Input ist ein Zeichenkette (string) und kein Char.
Da liefert ein Vergleich zwischen string und char immer "false" zurück.
Tany schrieb:> Hat der doch. Der Comport ist anfangs an geöffnet und nirgendwo> geschlossen worden.
OK aber das passt trotzdem nicht
state1 = 0;
case 'S':
Serial.println(state1);
zu dem hier
if (input.Equals("0"))
er schickt 0 und will lesen "0"
ausserdem schrieb er:
Chris V. schrieb:> Naja ich möchte ja die Daten nicht in eine Datei schreiben
trotzdem muss er ein File Handle öffnen
Sven A. schrieb:> dafür gibt es ja direkt die serialport-klasse. da muss man dann kein> file öffnen.
OK ich bin nicht der c# progger, aber was ist mit
Joachim B. schrieb:> state1 = 0;> case 'S':> Serial.println(state1);>> zu dem hier>> if (input.Equals("0"))
?
das sieht immer noch falsch aus
Chris V. schrieb:> case 'S':> Serial.println(state1);> break;
Versuche damit:
.....
Serial.println(state1+'0');
.....
und statt input.Equals() vlt. [if "0" in string] oder [Pos('0',
string)>0] (ich weiß nicht wie mann in C# formuliert...)
Die funktion serialport.ReadLine() liefert ein String mit Zeilenvorschub
zurück, man kann mit funktion Trim trimern, bevor man vergleich
[if (input.Equals("0"))...]
.....
Mach den Empfang der Daten mittels Event:
Für Deinen konkreten Fall machst Du einen Event-Handler und meldest ihn
beim SerialPort an (dieser Code wird automatisch erzeugt, wenn Du Dir
das im Designer zusammenklickst):
1
serialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
Der Handler zum empfangen der Daten könnte etwa so aussehen:
Was empfängst Du denn genau mit dieser Zeile? Welchen Wert hat input?
1
string input = serialport.ReadLine();
Habe gerade mal nachgeschaut, die Methode wartet ab, bis ein NewLine
kommt und entfernt dann das NewLine (siehe
https://msdn.microsoft.com/de-de/library/system.io.ports.serialport.readline(v=vs.110).aspx).
Die Frage ist natürlich, ob das richtige NewLine kommt (\r, \n oder
\r\n). Einfach mal einen Breakpoint setzen und schauen, wo es hängt und
dann melden.
Falls Du Dein Programm später noch erweitern willst empfehle ich Dir,
den serialPort_DataReceived-Event zu verwenden. Damit wartet Dein
Programm nicht auf die Eingabe, ist also nicht blockiert bis etwas
kommt, sondern läuft weiter. Einfach bei den Eigenschaften des
SerialPorts auf Ereignisse umschalten (Blitzsymbol) und auf DataReceived
doppelklicken, dann wird automatisch die Methode erstellt.
Chris V. schrieb:> Da viele anscheinend mein Problem nicht ganz verstanden haben,
dann ist es meistens falsch erläutert...
Dr. Sommer schrieb:> Sende einfach vom Arduino jede Sekunde den aktuellen Stand.
würde ich auch bevorzugen und dann den eventhandler dazu
Tany schrieb:> [Pos('0',> string)>0]
das bringt auch nichts. dann haben wir immer noch (ich schreibe jetzt
mal in dezimal) 0!= 48 (die ascii präsentation von 0, auf die hier
geprüft wird)
Chris V. schrieb:> as Anfragen vom PC ist ja nicht das Problem. Mein Problem ist dass ich> nicht weiß wie ich die Daten vom Arduino auswerten kann um damit dann> irgendetwas zu machen im C# Programm (z.B. die Farbe der Buttons> ändern). Das Problem hätte ich ja auch wenn ich jede Sekunde den Stand> übermitteln würde.
Suchtipp:
"Arduino CmdMessenger"