pi4j und die serielle Schnittstelle

Heute ist Stammtischzeit:
Jeden Donnerstag 20:30 Uhr hier im Chat.
Wer Lust hat, kann sich gerne beteiligen. ;)
  • Hallo Leute,

    nachdem ihr bei meinem letzten Problemchen schon so gut geholfen habt, hier mal mein aktuelles Problemchen.

    Ich möchte gern Daten vom µC per RS232 in den Pi einlesen. Dafür benutzt ich die "pi4j" Lib. Das Beispiel was dabei ist funktioniert auch super. Daten senden und empfangen geht damit problemlos. Aber ich möchte die Daten ja nicht per Konsole ausgeben, sondern im Programm weiter verarbeiten.

    Also habe ich das Beispiel einfach etwas angepasst.
    Original sah es so aus:

    Dann habe ich für die Konsole eine globale Variable eingefügt

    Code
    public String readData;

    und den entpsrechenden Code in der Schleife:

    Code
    readData = (event.getData() + System.getProperty("line.separator"));


    ersetzt.

    Das funktioniert scheinbar irgendwie, nur leider wird kein Event mehr ausgelöst der in die Variable was reinschreibt. Es wird also nur "null" zurück gegeben. Ausserdem wird kein Datum mehr gesendet. Also wird die komplette Funktion der Seriellen Schnittstelle irgendwie blockiert.

    Nach etwas Suchen bin ich im Forum von pi4j auf ein Beitrag gestoßen, wo jemand das selbe Problem hat. Beitrag im pi4j Forum
    Dort wurde empfohlen, als "quick and dirty" Methode, der Klasse einfach eine public Variable anzufügen. Was ich ja bereits gemacht habe. Da wird auch darauf hingewisen, dass im Fall von lange laufenden Schleifen, es zu Empfangsprobleme auf der Schnittstelle kommen kann. Ich habe allerdings nur eine Schleife die sekündlich durchläuft und das serial.readData einfach nur aufruft.

    Edit: Oder liegt das daran, dass ich den Sekundentakt mittels Thread.sleep(1000); erzeuge? Weil das heißt ja, dass er einfach mal 1000ms nichts tun soll. Mist, ich glaube den Fehler habe ich gerade selber gefunden :s.

    Als super Lösung wird darauf hingewisen, dass man einen eigen Thread für den Empfang bauen soll und den dann syncronisieren muss. Und hier bin ich total überfragt, weil ich das noch nie gemacht habe. Ich habe mal ein Thread Beispiel gebastelt wo zwei Threads einfach Variablen hoch zählen. Aber das mit dem Syncronisieren raff ich irgendwie noch nicht.

    Aber mal als Frage, hat jemand ein Beispiel, wie man das Problem lösen kann und würde das mal posten. Dann habsch mal ein funktionierendes Beispiel wie es geht :)

    Danke,
    Arno

  • [font="Tahoma, Verdana, Arial, sans-serif"]> Edit: Oder liegt das daran, dass ich den Sekundentakt mittels Thread.sleep(1000); erzeuge?[/font]
    [font="Tahoma, Verdana, Arial, sans-serif"]Genau das ist das Problem. Der Main-Thread holt keine Events mehr aus der Event-Queue.[/font]

    [font="Tahoma, Verdana, Arial, sans-serif"]> Als super Lösung wird darauf hingewisen, dass man einen eigen Thread für den Empfang bauen[/font]
    [font="Tahoma, Verdana, Arial, sans-serif"]> soll und den dann syncronisieren muss.[/font]
    [font="Tahoma, Verdana, Arial, sans-serif"]Stimmt, ABER Threads sind nichts fuer Anfaenger !![/font]

    [font="Tahoma, Verdana, Arial, sans-serif"]Die sind zwar in Java leicht zu machen, aber die Synchronisation braucht einiges Hintergrundwissen.[/font]
    [font="Tahoma, Verdana, Arial, sans-serif"]Threads NUR WENN NOETIG ![/font]

    [font="Tahoma, Verdana, Arial, sans-serif"](Ich weiss, gleich geht ein Storm los, dass fast alle von Euch die Threads voll im Griff[/font]
    [font="Tahoma, Verdana, Arial, sans-serif"]haben und nur absolut Thread-sicheren Code schreiben. Vergesst es: ich weiss was[/font]
    [font="Tahoma, Verdana, Arial, sans-serif"]ich schreibe)[/font]

    [font="Tahoma, Verdana, Arial, sans-serif"]Ein Timer ist viel einfacher in den Griff zu kriegen. Wenn ich mich richtig erinnere, gibt[/font]
    [font="Tahoma, Verdana, Arial, sans-serif"]es in Java gleich mehrere Timer. Eine Suche nach Java und Timer sollte einiges zu[/font]
    [font="Tahoma, Verdana, Arial, sans-serif"]Tage foerdern.[/font]

  • Versuch es mal wie folgt:
    Eine globale Variable ist sicher OK, ich würde einen Vector nehmen (der synchronisiert seine Zugriffe):
    Vector datenVecotor = new Vecotor();

    Die Zuweisung dann wie folgt:
    String readData = event.getData();
    if (readData != null) datenVector.add(readData);

    Ich unterstelle mal, dass getData() auch einen String liefert. Und hoffe, dass der Vector eine add-Methode hat (schreibe das nur mal so ohne auszuprobieren).

    Idealerweise hast du einen Thread, der auf genau so ein Ereignis wartet. Alternativ eine Endlosschleife, etwa so:

    while(true)
    {
    Thread.sleep(1000); // Eine Sekunde warten, Try/Catch unterschlage ich mal)
    if (datenVector.isEmpty() == false)
    {
    // hier über den Vector iterieren, die Werte lesen und aus dem Vector löschen
    // und irgend etwas damit machen
    }
    }

    Hoffe, der Ansatz hilft etwas.

  • Hallo Leute,

    habe jetzt eine Version zusammen gebastelt, die erstmal funktioniert :D
    Danke auch an die PN die ich mit einem Beispielprogramm bekommen habe. Das und viel lesen in Büchern hats am Ende doch gebracht :D

    Ich weiß jetzt nicht ob das hier die beste Lösung ist, aber ich stell den trotzdem mal rein. Vielleicht haben auch noch andere Leute ein Problem damit :)
    Für Verbesserungsvorschläge bin ich natürlich dankbar :D

    Mein "Machwerk": }


    und hier der TimerTask:

    Auf alle Fälle kann ich jetzt, aktuell zum testen, aller 250ms einen String per RS232 empfangen und auf der Konsole anzeigen.

    :danke_ATDE::bravo2::thumbs1::D
    Arno

  • Schön dass es funktioniert und für deine Aufgabenstellung vielleicht auch OK.

    In einem Java-Forum würde das nicht durchgehen - ich versuche mal zu erklären warum:
    - der Timer wird ständig auf Verdacht aufgerufen, das kostet sehr viele Resourcen
    - Wenn die Routine, die den String auswertet zu lange dauert, wirst du Probleme bekommen
    - es können auch Eingaben verloren gehen

    Besser ist es, das ganze in einem Thread zu machen. Der wird schlafen geschickt und geweckt, bis ein Ereignis kommt. Das handelt er ab (String-Verarbeitung) und legt sich wieder schlafen. Noch was gutes: auch eine Programm-Stop-Routine kann implementiert werden. Die stopt den Thread und schließt sauber die serielle Schnittstelle. Mal als Denkansatz zu sehen - falls eines der Probleme akut werden sollte.

    Und noch was: die Verarbeitung in der getSerialData-Methode zu machen, ist weniger gut - vor allem, wenn die Verarbeitung etwas Zeit in Anspruch nimmt.

  • Hallo Leute,

    Zitat


    Und noch was: die Verarbeitung in der getSerialData-Methode zu machen, ist weniger gut - vor allem, wenn die Verarbeitung etwas Zeit in Anspruch nimmt.

    Ja, so kenn ich es auch von den Mikroprozessoren und SPSen. Im Interrupt (Event) Case wird nur ein Flag gesetzt oder ein überschaubarer Teil Programm ausgeführt. Ebend wegen der Ausführungszeit.

    Bin gerade dabei mich mit Threads und syncronisierung zu beschäfftigen. Habe da ein Befehl "Lock" gefunden. Damit geht es scheinbar bei einfachen Programmen mit dem syncronisieren.

    Mit dem Timer auf verdacht geht so bei mir. Ich weiß wann ich Daten sende. Damit geht das. Aber wie ist das wenn ich im Thread.sleep bin und es kommt ein Event. Wacht der dann auf oder verpasse ich das das Ereigniss?


    Zitat


    In einem Java-Forum würde das nicht durchgehen


    Bin für jeden Hinweis dankbar :bravo2:.
    Bin gerade beim einarbeiten in Java und die ganze Sache mit Multithreading, syncronisieren und so ist mir zur Zeit noch nicht ganz geheuer :D. Aber es kommt langsam Licht ins Dunkel :thumbs1:

    Werde mein Lösung mal posten wenn ich es mal fertig habe :D

    :danke_ATDE:
    Arno

  • Warnung: Threads machen einige Dinge einfacher, aber man zahlt mit vielen Komplikationen !

    Threads starten ist einfach, einen Thread sauber zu terminieren dagegen nicht ...

    Und die ganzen Synchronisationsprobleme muss man erst begreifen und
    den Code GANZ GANZ sauber implementieren.

    Und kein Lock nehmen sondern einen synchronized-Block. Das
    ist deutlich einfacher, weil Java das Lock verwaltet.


    Uebrigens gibt es in diesem Code schon ZWEI Threads, der Timer
    laeft naemlich in einem eigenen Thread.

    Halt, stop, es sind DREI. Der Garbage-Collector ist ja auch noch da.

    (Oder vielleicht sogar noch ein vierter, je nachdem wie die Seriell-Klasse
    implementiert ist)

    Einen Callback kann man nicht mit einem Interrupt-Handler vergleichen,
    da das ganze von der Virtuellen Maschine verwaltet wird, hat man viel
    mehr Zeit.

Jetzt mitmachen!

Du hast noch kein Benutzerkonto auf unserer Seite? Registriere dich kostenlos und nimm an unserer Community teil!