Es gibt da zig Optionen. Alleine bei .NET hast du die Wahl zwischen C#, Visual C++ und Visual Basic (vergiss aber letzteres. Es ist Schrott). Delphi geht auch. Oder Java. Oder C++ und Qt.
Delphi und .NET sind halt wegen den GUI Editoren sehr schön. Java hat da etwas Abstriche, ist aber vom Programmieren her sehr ähnlich.
Aber so oder so musst du lernen wie die Komponenten funktionieren und die Grundlagen der jeweiligen Sprachen.
Delphi/Object Pascal ist da wie schon gesagt von der Syntax her anders als C++. C# funktioniert auch anders als C++, aber die Syntax ist bewusst sehr ähnlich. Das ist wieder Geschmackssache. Exotisch ist Pascal nicht, aber man muss sich dran gewöhnen.
Ich habe mal meine .NET/C# Serial Klasse angehängt wenn du das nehmen willst.
Anmerkungen dazu:
1.) Es sind zwei Klassen Communicator und SerialCommunicator. Die Idee dahinter war, dass man nur eine Ober-Klasse mit virtuellen Methoden hat und dann spezialisierte Unterklassen hat. Dadurch können die gleichen GUI Elemente sowohl ober Serial als auch z.B. Ethernet kommunizieren.
Das ist für dich nicht relevant. Du kannst auch Communicator weglassen. Dann musst du aber bei SerialCommunicator das ": Communicator" bei der Klassen Definition entfernen und die "override"s bei den Methoden
2.) Es gibt zwei Konstruktoren:
public SerialCommunicator(Action dataCallback, Action errorCallback)
public SerialCommunicator(Action callback)
Man muss hier ein oder zwei Methoden übergeben:
errorCallback ist für Status- und Fehler-Meldungen wie ""Fehler beim Öffnen des Com Ports!" oder "Fehler beim Schreiben!". Ich gebe das auf einer RichTextBox aus, aber man könnte auch die Konsole nehmen, wenn man es nicht auf dem GUI haben will.
dataCallback ist für normale Daten und wird aufgerufen wenn eine Zeile eingelesen wurde
Ich habe das getrennt, weil ich die Daten Parsen muss. dataCallback geht dann auf einen Parser statt den empfangenen Text direkt auszugeben.
Man kann mit dem zweiten Konstuktor nur einen einen Callback angeben. Dann wird beides gleich behandelt.
Man kann auch einfach null übergeben. Dann wird an der entsprechende Stelle nichts gemacht. z.B. keine Fehler/Meldungen oder auch keine empfangenen Daten ausgeben (wenn man wirklich nur PC -> Arduino möchte).
3.) Der Callback (bzw. eine Methode die von diesem aufgerufen wird) muss Invoke für die GUI Elemente verwenden! Serial läuft in einem eigenen Thread und kann nicht direkt auf das GUI Thread zugreifen. Das sieht dann z.B. so aus:
private void UpdateLabel(Label label, string text)
{
if (label.InvokeRequired)
{
label.BeginInvoke((MethodInvoker)delegate
{
label.Text = text;
});
}
else
label.Text = text;
}
Hier für ein Label, aber analog für alle anderen Komponenten. Durch BeginInvoke() und den Delegate wird dass dann auf dem GUI Thread ausgeführt.
Dann kann der Parser z.B. das machen:
public void ParseSerialData(string text)
{
double value = Double.Parse(text.Substring(2), CultureInfo.InvariantCulture);
string str = value.ToString("F1");
if (text.StartsWith("xx"))
UpdateLabel(label1, str);
else if (text.StartsWith("yy"))
UpdateLabel(label2, str);
}
Wenn der String dann so aussieht: "xx12.45" wird die Gleitkomma-Zahl mit einer Nachkomma-Stelle gewandelt und entsprechend dem was am Anfang steht auf eines der Labels geschrieben.
Die Serial Klasse ruft dann automatisch ParseSerialData() auf und dieses greift über UpdateLabel() auf die GUI Komponenten zu.
Wenn du keine Kommunikation zum PC willst, kannst du das auch erst mal ignorieren und die Status/Fehler-Meldungen auf Console.Write() ausgeben. Die erscheinen dann in der IDE im im Output Fenster. Da muss man nicht mit Invoke() arbeiten.
4.) Verbindungsaufbau geht so:
private Communicator _communicator; //globale Variable
public MainForm() //Haupt-Konstruktor
{
_communicator = new SerialCommunicator(ParseSerialData, TextBoxPrintln);
}
Hier hat man erst mal nur ein Objekt. Dann kann man im Programm den Comport und die Baudrate setzten:
_communicator.SetComPort(...);
_communicator.SetBaudrate(...);
Der ComPort ist dabei einfach ein String, z.B. COM3. Da gibt es auch SerialPort.GetPortNames() was die verfügbaren Ports als String Array liefert. Das kann man dann einer ListBox eintragen oder ein Menü daraus erstellen.
Dann kann mit _communicator.Connect() verbinden oder mit _communicator.Disconnect() trennen
5.) Die Parse-Methode wird erst aufgerufen wenn eine mit CR+LF eingelesen Zeile angekommen ist. Also alles was mit println() gesendet wird ist ein Datensatz.
6.) In den Standard Beispielen zur .NET Serial Klasse wird der DataReceived Event Handler aufgerufen. Das habe ich auch schon gemacht, aber hat mir zuletzt kaum funktioniert. Er hat nicht immer ausgelöst, wodurch das ganze extrem verzögert wurde. Davon liest man auch im Internet immer mal wieder.
Deshalb die Sache mit dem Timer in der Serial Klasse der einfach ständig nachfragt ob Daten da sind.
Serial.zip (1.24 KB)