Mit Delphi Daten in ein vorhandenes Arduino Programm übertragen

Hallo Forenmitglieder,

ich habe bis jetzt mein Quellcode für den Arduino soweit dass er grundlegend dass macht was ich möchte. :grin:

Jetzt möchte ich gerne mit Delphi, oder gibt es bessere Lösungen?, Daten nicht mehr fest im Arduino festschreiben sonder per GUI an das Board übertragen.

Leider konnte ich bis jetzt keine Anweisungen finden die da weiter helfen, im moment scheitert es schon an dem Aufbau mit dem Com Port.

Kann mir da jemand weiterhelfen? Oder mir Tips geben? :kissing:

Vielen lieben Dank

Andreas

Ist Geschmackssache. Wenn du Delphi/Pascal schon beherrscht dann verwende das ruhig. Wenn du sowieso was neues lernen muss würde ich .NET/C# empfehlen. Dafür gibt es eine kostenlose, professionelle Entwicklungsumgebung und zig Anleitungen. Aber andere Sprachen/Laufzeitumgebungen gehen genauso.

Das klingt doch auch gut, da ich fast ein neuling in Delphi, bin bin ich für fast alles offen :wink: Ich habe sogar über meine Schule das MS Visual Studio, vielleicht versuche ich mich mal damit.

Du kannst auch mal warten. Hier gibt es jemanden der seine GUIs mit Delphi schreibt. Mir fällt aber nicht mehr ein wer.

Delphi ist nicht schlecht. Damit hatte ich vor ca. 15 Jahren mal gearbeitet. Ich fand es auf jeden Fall weit besser als Visual Basic. Mit serieller Kommunikation hatte ich aber nichts gemacht.

Hallo, Als erstes musst du dir eine Delphi comport komponente suchen und installieren. Weist du wie man das macht ? Welche Delphi Version hast du ?

Meist sind dort schon Beispielprojekte dabei mit denen du schon mal sehen kannst was dort so kommt. Must nur noch evtl. den Comport und Baudrate anpassen.

Dann geht es halt ans parsen der Daten. Dein Arduino sendet ja die Daten mit dem Protokoll das du dir ausgedacht hast. z.b ein Zeichen das die Datenblöcke trennt, ich nehme meist das '#' .

PS: Delphi ist keine schlechte Wahl, ich habe damals mit Pascal angefangen. Der Code ist nicht so kompakt wie C++ aber wohl auch deshalb leichter zu verstehen. Das du aber den Arduino schon in C programmierst und auch Delpi newbie bist wäre es fast besser du schaust dir Visual C++ an.

rudirabbit: Dann geht es halt ans parsen der Daten. Dein Arduino sendet ja die Daten mit dem Protokoll das du dir ausgedacht hast.

Er will es anders herum. Daten an den Arduino senden.

Dann muss man aber dort Einlesen und Parsen. Also gleiches Problem, anderer Code. Da gibt es auch viele Schrott Beispiele. Oder Beispiele die sehr stark auf bestimmte Anwendungen zugeschnitten sind (z.B. genau drei Integer übertragen) und kaum zu verallgemeinern sind.

Ok dann habe ich das falsch verstanden, also parsen auf den Arduino in C(++) Ich finde als Umsteiger das die strtok Funktion dazu absolut perfekt geeignet ist.

Genau :slight_smile:

Einlesen und Parsen eines Komma-getrennten Strings der durch eine Linefeed abgeschlossen ist:

const int SERIAL_BUFFER_SIZE = 41;
const int MAX_VALUES = 10;

char serialBuffer[SERIAL_BUFFER_SIZE];
int values[MAX_VALUES];

void setup()
{
  Serial.begin(115200);
}

void loop()
{
  if (readSerial())
    parseSerial();
}

bool readSerial()
{
  static byte index;

  while (Serial.available())
  {
    char c = Serial.read();

    if (c >= 32 && index < SERIAL_BUFFER_SIZE - 1)
    {
      serialBuffer[index++] = c;
    }
    else if (c == '\n')
    {
      serialBuffer[index] = '\0';
      index = 0;
      return true;
    }
  }
  return false;
}

void parseSerial()
{
  int numbersRead = 0;
  char* ptr = strtok(serialBuffer, ",");

  while (ptr != NULL && numbersRead < MAX_VALUES)
  {
    values[numbersRead++] = atoi(ptr);
    ptr = strtok(NULL, ",");
  }

  for (int i = 0; i < numbersRead; i++)
    Serial.println(values[i]);
  Serial.println();
}

Das values Array ist natürlich nicht unbedingt nötig. Man kann auch gleich was anderes mit den Zahlen machen. Kommt auf die Anwendung an

@Serenifly : Dein Beispielcode ist natürlich perfekt. Meine Umsetzung des Parsens mit strtok war damals ähnlich, ein paar Dinge machst du aber besser :)

EddyErdmann will Daten von einer GUI mit dem Arduino verarbeiten Dann sollte aber der Arduino auch ein ACK zurückschicken um in der GUI anzuzeigen das der Arduino dies akzeptiert hat.

Somit sind wir auch auf der PC Seite beim "Parsen". Bzw das ACK auswerten.

Hallo,

vielen Dank für die vielen Antworten.

Ich arbeite an einem Abschlussprojekt wo ich gerne drei Magnetventile ansteuern möchte, diese sollen Wassertropfen erzeugen die dann einen Buchstaben darstellen sollen. Daher möchte ich gerne dass der Benutzer mittels GUI eine Zeichenkette eingeben kann und diese dann auf den Arduino übertragen. Hierzu möchte ich noch zwei andere Werte übertragen, die Anzahl der Wiederholungen und den Zeitintervall.

Ich hoffe ich konnte mein Problem euch etwas besser vermitteln.

Andreas

Das klingt spannend: Mit 3 Tropfen-Erzeugern beliebige Buchstaben darstellen. ??? Will ich sehen :wink:

Als GUI den SerialMonitor nehmen reicht nicht?
Dann könntest du dich auf das wirklich interessante konzentrieren.

Ansonsten:
Wenn du nicht auf Delphi festgelegt bist: Mit .net und VisualStudio ist serielle Kommunikation mit einem Arduino kein Problem. Da wirst du sicher geholfen.

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)

Hallo an alle, besonders an Serenifly,

vielen dank ihr, besonders Serenifly hat mir sehr weiter geholfen.

Ich schaue mal dass ich jetzt weiter kommen.

Schönen Gruß

Andreas

Sehe gerade, dass ich da bei den Serial Dateien einen kleinen Fehler gemacht habe. Da ist noch meine Namespace Definition drin. Damit geht das bei dir nicht. Das müsstest du entweder auf deinen Namespace anpassen (Standardmäßig der Projekt Name) oder die Namespace Sache einfach löschen. Das ist in ein paar Sekunden gemacht. Ich hänge aber mal eine ausgebesserte Version an (die auch ein paar überflüssige using Direktiven weniger hat).

Einfach in das Projekt-Verzeichnis kopieren, und dann Shift+Alt+A drücken um die Dateien zu dem Projekt hinzuzufügen.

Was auch noch interessant ist ist die Antwort von Brandon hier:

Damit kann man automatisch den Com-Port feststellen. So muss man nichts mehr auswählen. :slight_smile:

Geht bei mir auf einem Standard Arduino perfekt, aber nicht auf einer Variante mit FTDI Adapter. Den findet diese Methode nicht mal unter einem anderen Namen.

Eventuell muss man das machen damit er das Management Assembly findet:
https://danieladeniji.wordpress.com/2011/03/22/microsoft-visual-studio-error-the-type-or-namespace-name-managementscope-could-not-be-found-are-you-missing-a-using-directive-or-an-assembly-reference/
Dann geht wie sonst auch using System.Management;

Wenn man mit Google nach “Delphi Serial” sucht findet man aber auch viel. Wobei einige der angebotenen Serial Komponenten kostenpflichtig sind.

Serial.zip (1.24 KB)