JavaFX->ArduinoUNO->LCD

Hallo liebes Forum,

ich versuche momentan einen String über die serielle Schnittstelle vom JavaFX-Programm an den Arduino Uno zu schicken, um ihn dann auf einem 16x2 LCD anzuzeigen. Leider flackert nach dem betätigen des Sendebuttons die LCD nur kurz auf und zeigt den gleichen Text, der beim Setup voreingestellt wurde.

Über Hilfe würde ich mich sehr freuen.

JavaFX:

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.TextField;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import jssc.SerialPort;
import jssc.SerialPortException;
import jssc.SerialPortList;

import java.util.logging.Level;
import java.util.logging.Logger;

public class JavaFX_jSSC extends Application {

    ObservableList<String> portList;

    private void detectPort(){

        portList = FXCollections.observableArrayList();

        String[] serialPortNames = SerialPortList.getPortNames();
        for(String name: serialPortNames){
            System.out.println(name);
            portList.add(name);
        }
    }

    @Override
    public void start(Stage primaryStage) {
        detectPort();

        final ComboBox comboBoxPorts = new ComboBox(portList);
        final TextField textFieldOut = new TextField();
        Button btnSend = new Button("Send");

        btnSend.setOnAction( s -> {
            if(comboBoxPorts.getValue() != null &&
                    !comboBoxPorts.getValue().toString().isEmpty()){

                String stringOut = textFieldOut.getText();

                try {
                    SerialPort serialPort =
                            new SerialPort(comboBoxPorts.getValue().toString());

                    serialPort.openPort();
                    serialPort.setParams(
                            SerialPort.BAUDRATE_9600,
                            SerialPort.DATABITS_8,
                            SerialPort.STOPBITS_1,
                            SerialPort.PARITY_NONE);
                    serialPort.writeBytes(stringOut.getBytes());
                    serialPort.closePort();

                } catch (SerialPortException | InterruptedException ex) {
                    Logger.getLogger(
                            JavaFX_jSSC.class.getName()).log(Level.SEVERE, null, ex);
                }

            }else{
                System.out.println("No SerialPort selected!");
            }
        });

        VBox vBox = new VBox();
        vBox.getChildren().addAll(
                comboBoxPorts,
                textFieldOut,
                btnSend);

        StackPane root = new StackPane();
        root.getChildren().add(vBox);

        Scene scene = new Scene(root, 300, 250);

        primaryStage.setTitle("J-A-Kommu");
        primaryStage.setScene(scene);
        primaryStage.show();
    }


    public static void main(String[] args) {
        launch(args);
    }
}

Arduino:

//LiquidCrystal-Bibliothek einrichten
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

String charsIn = "";

void setup() {
  Serial.begin(9600);
  
  lcd.begin(16, 2);
  lcd.print("Hallo,");
  lcd.setCursor(0, 1);
  lcd.print("ich warte...");
}

void loop() {
  while(Serial.available()){
    char charRead = Serial.read();
    Serial.print(charRead);
    charsIn.concat(charRead);
    delay(3);
  }

  if(charsIn != ""){
    lcd.clear();
    delay(500);
    lcd.setCursor(0, 0);
    lcd.print(charsIn);
    charsIn = "";
  }
}

Meine Vermutung ist, durch Senden deines Strings über die serielle an den Uno wird dieser resettet und startet danach erneut das Setup. Das sieht ganz normal aus.

Leider flackert nach dem betätigen des Sendebuttons die LCD nur kurz auf

Du sammelst erstmal Zeichen von der Seriellen, nach einem "Timeout" gibst du diese aus.

Wenn jetzt der Timeout zuschlägt, wenn noch nicht alle Zeichen da sind, flackert es.
Dein Timeout kann auch zuschlagen, wenn der Sender nicht schnell genug ist.

Ich würde mit Steuerzeichen arbeiten:

  • Lösche LCD
  • Setze Cursor in die nächste Zeile
    Im Bereich < 0x20 wirst du sicher welche dafür nehmen können.

und zeigt den gleichen Text, der beim Setup voreingestellt wurde.

KA was da passiert. Sollte höchstens leer sein.

@TO: Schau mal, ob Dein JAVA ein DTR sendet. Das führt zum Reset.

Gruß Tommy

Hallo,

warum testest Du das nicht zunächt mal ohne JavaFx und benutzt den Monitor zur Eingabe der Zeichen. Dann weist Du wo du suchen musst.

Heinz

Soooo habe jetzt mein JavaFX Programm umgeschrieben. Ich benutze zwar jetzt die jSerialComm Library ist aber quasi das selbe in grün. Ich habe die Funktionen aufgeteilt. Ein "Connect" Button öffnet bei erstmaligen betätigen den seriellen Port und schließt ihn bei nochmaligen betätigen. Der "Send" Button schickt den String an den LCD. Vorher gab es nur den Sende Button der alle drei Funktionen nacheinander durchgeführt hat und dabei gab es diese Restartprobleme beim Arduino.

Wo ist da der Unterschied? Der serielle Port wird ja immer noch geöffnet und geschlossen.

JavaFX:

import com.fazecast.jSerialComm.SerialPort;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

import java.io.PrintWriter;


public class JavaFX_jSSC extends Application {

    static SerialPort chosenPort;

    ObservableList<String> portList;

    private void detectPort(){

        portList = FXCollections.observableArrayList();

        SerialPort[] portNames = SerialPort.getCommPorts();
        for(int i = 0; i < portNames.length; i++)
            portList.add(portNames[i].getSystemPortName());
    }

    @Override
    public void start(Stage primaryStage) {


        detectPort();

        final ComboBox comboBoxPorts = new ComboBox(portList);
        final TextField textFieldOut = new TextField();
        Button btnSend = new Button("Send");
        Button btnConnect = new Button("Connect");

        btnSend.setDisable(true);

        btnConnect.setOnAction( c -> {
            if (btnConnect.getText().equals("Connect")){
                //Versuch eine Verbindung zum seriellen Port herzustellen
                chosenPort = SerialPort.getCommPort(comboBoxPorts.getValue().toString());
                chosenPort.setComPortTimeouts(SerialPort.TIMEOUT_SCANNER, 0, 0);
                if (chosenPort.openPort()){
                    btnConnect.setText("Disconnect");
                    comboBoxPorts.setDisable(true);
                    btnSend.setDisable(false);
                }
            }else{
                chosenPort.closePort();
                comboBoxPorts.setDisable(false);
                btnConnect.setText("Connect");
                btnSend.setDisable(true);
            }
        });

        btnSend.setOnAction( s -> {

            try {Thread.sleep(100); } catch(Exception e) {}

            PrintWriter output = new PrintWriter(chosenPort.getOutputStream());
            output.print(textFieldOut.getText());
            output.flush(); //Sendet die Daten

        });

        VBox vBox = new VBox();
        HBox hBox = new HBox(10);
        hBox.getChildren().addAll(comboBoxPorts, btnConnect);
        vBox.getChildren().addAll(
                hBox,
                textFieldOut,
                btnSend);

        StackPane root = new StackPane();
        root.getChildren().add(vBox);

        Scene scene = new Scene(root, 300, 250);

        primaryStage.setTitle("J-A-Kommu");
        primaryStage.setScene(scene);
        primaryStage.show();
    }


    public static void main(String[] args) {
        launch(args);
    }
}

Du solltest das nochmal klar stellen:

  • Hat sich was verändert?
  • Passiert der Arduino-Reset beim Connect(openPort) oder bei jedem Send?
  • Oder ist es gar kein Reset sondern irgend ein anderer Dreck?

Wenn es ein Arduino-Reset ist und mit dem openPort zu tun hat, liegt es daran, dass dies das DTR - Signal verändert.

Das kann man zur Not elektrisch am Arduino unterbinden, wenn es das überhaupt ist, und es sonst keine andere Möglichkeit (auf der PC-Seite) gibt.
Wie du das mit deiner java - Library beeinflussen kannst, ist dann allerdings hier eher off-topic, denn dein javafx und fazecast.jSerialComm - Programm interessiert hier im Arduino-Forum höchstens am Rande.

michael_x:
Du solltest das nochmal klar stellen:

  • Hat sich was verändert?
  • Passiert der Arduino-Reset beim Connect(openPort) oder bei jedem Send?
  • Oder ist es gar kein Reset sondern irgend ein anderer Dreck?

Wenn es ein Arduino-Reset ist und mit dem openPort zu tun hat, liegt es daran, dass dies das DTR - Signal verändert.

Das kann man zur Not elektrisch am Arduino unterbinden, wenn es das überhaupt ist, und es sonst keine andere Möglichkeit (auf der PC-Seite) gibt.
Wie du das mit deiner java - Library beeinflussen kannst, ist dann allerdings hier eher off-topic, denn dein javafx und fazecast.jSerialComm - Programm interessiert hier im Arduino-Forum höchstens am Rande.

Ja es hat sich in sofern verändert, dass kein Arduino-Reset passiert. Wie ich in meinen vorherigen Kommentaren beschrieben habe, wurde der Arduino-Reset anscheinend durch das port.close() von JavaFX ausgelöst.

Als ich das alte JavaFX Programm im Debug-Modus laufen ließ und kurz vor dem port.close() stoppte funktionierte das ganze einwandfrei.

Code der durch betätigen des SendeButtons durchgeführt wurde:

                    serialPort.openPort();
                    serialPort.setParams(
                            SerialPort.BAUDRATE_9600,
                            SerialPort.DATABITS_8,
                            SerialPort.STOPBITS_1,
                            SerialPort.PARITY_NONE);
                    serialPort.writeBytes(stringOut.getBytes());
                    serialPort.closePort();

Deswegen hatte ich die Vermutung, dass der Reset am Arduino (wenn es ein Reset war) vielleicht an einem zu frühen schließen des Ports während des Sendens lag.

Ob es an einer Veränderung des DTR-Signals lag, weiß ich leider nicht, denn dafür kenne ich mich zu wenig mit der seriellen Kommunikation aus.

Meine Lösung war es, wie bereits erwähnt, die Sendemethode und die Methode zum Öffnen und Schließen des Port in zwei Buttons zu trennen, so dass die port.close() Methode im JavaFX-Code nicht direkt nach der send-Anweisung kam.

Ich hoffe ich habe meine Gedankengänge deutlich dargestellt.

Meine Lösung war es, wie bereits erwähnt, die Sendemethode und die Methode zum Öffnen und Schließen des Port in zwei Buttons zu trennen, so dass die port.close() Methode im JavaFX-Code nicht direkt nach der send-Anweisung kam.

Das halte ich auch für besser: openPort und setParams sollte man nur einmal machen, und also auch closePort nicht nach jedem Senden.

Da Java an sich gern plattformunabhängig ist, war Serial immer etwas knifflig und braucht passende Native Libraries. Die jSerialComm scheint sinnvoll zu sein, danke für den Tip.

fazecast.github.io/jSerialComm:

  • automatically uses correct native library based on current architecture
  • Configurable flow control parameters for the serial port (CTS, RTS/CTS, DSR, DTR/DSR, XOn/XOff)