这将是我的第一篇文章,我将尽力使其清晰简洁。我已经查看了此论坛上的其他一些帖子,但未能找到满意的答案。
我的问题涉及使用JavaFX和jSSC(java简单串行连接)库。我设计了一个非常简单的GUI应用程序,它将托管四个不同的图表。其中两个图表将显示过去一小时温度和太阳能传感器的读数,而另外两个图表显示长时间内的数据--14小时。最后我想让它更灵活,并将应用程序设置为" sleep"当读数大致为零(夜晚)时。
如何实时流式传输数据?
在线引用多个来源后,从#34; JavaFX 8简介中引用。通过示例",我已经能够构建大部分串行连接类。我在处理数据读数时遇到问题,因此可以在图表上显示。
public class SerialComm implements SerialPortEventListener {
Date time = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("mm");
boolean connected;
StringBuilder sb;
private SerialPort serialPort;
final StringProperty line = new SimpleStringProperty("");
//Not sure this is necessary
private static final String [] PORT_NAMES = {
"/dev/tty.usbmodem1411", // Mac OS X
"COM11", // Windows
};
//Baud rate of communication transfer with serial device
public static final int DATA_RATE = 9600;
//Create a connection with the serial device
public boolean connect() {
String [] ports = SerialPortList.getPortNames();
//First, Find an instance of serial port as set in PORT_NAMES.
for (String port : ports) {
System.out.print("Ports: " + port);
serialPort = new SerialPort(port);
}
if (serialPort == null) {
System.out.println("Could not find device.");
return false;
}
//Operation to perform is port is found
try {
// open serial port
if(serialPort.openPort()) {
System.out.println("Connected");
// set port parameters
serialPort.setParams(DATA_RATE,
SerialPort.DATABITS_8,
SerialPort.STOPBITS_1,
SerialPort.PARITY_NONE);
serialPort.setEventsMask(SerialPort.MASK_RXCHAR);
serialPort.addEventListener(event -> {
if(event.isRXCHAR()) {
try {
sb.append(serialPort.readString(event.getEventValue()));
String str = sb.toString();
if(str.endsWith("\r\n")) {
line.set(Long.toString(time.getTime()).concat(":").concat(
str.substring(0, str.indexOf("\r\n"))));
System.out.println("line" + line);
sb = new StringBuilder();
}
} catch (SerialPortException ex) {
Logger.getLogger(SerialComm.class.getName()).log(Level.SEVERE, null, ex); }
}
});
}
} catch (Exception e) {
System.out.println("ErrOr");
e.printStackTrace();
System.err.println(e.toString());
}
return serialPort != null;
}
@Override
public void serialEvent(SerialPortEvent spe) {
throw new UnsupportedOperationException("Not supported yet.");
}
public StringProperty getLine() {
return line;
}
}
在try块中,我理解端口参数,但eventListener是我遇到困难的地方。 stringbuilder的重要性在于从设备读取新数据时附加数据。 我如何计算两个传感器读数?我会通过创建单独的数据速率来区分每个传感器的传入数据吗?
我希望这很清楚,而且我提供的信息不多,但不是太多。谢谢你的帮助。
------------------------------- UPDATE --------------- -----------
自你回复Jose后,我开始添加我的代码。在JavaFX类中添加监听器,我遇到了一些问题。我一直得到一个NullPointerException,我相信String []数据没有被SerialCommunication类的任何数据初始化。
serialPort.addEventListener(event -> {
if(event.isRXCHAR()) {
try {
sb.append(serialPort.readString(event.getEventValue()));
String str = sb.toString();
if(str.endsWith("\r\n")) {
line.set(Long.toString(time.getTime()).concat(":").concat(
str.substring(0, str.indexOf("\r\n"))));
System.out.println("line" + line);
sb = new StringBuilder();
}
} catch (SerialPortException ex) {
Logger.getLogger(SerialComm.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
}
} catch (Exception e) {
System.err.println(e.toString());
}
我正在为正在阅读的数据添加时间。正如Jose在下面提到的,我在arduino代码中为数据变量添加了标签,我使用的是:Serial.print(" Solar:"); Serial.println(solarData);
JavaFx侦听器的粗略代码:
serialPort.getLine().addListener((ov, t, t1) -> {
Platform.runLater(()-> {
String [] data = t1.split(":");
try {
//data[0] is the timestamp
//data[1] will contain the label printed by arduino "Solar: data"
switch (data[1]) {
case "Solar":
data[0].replace("Solar:" , "");
solarSeries.getData().add(new XYChart.Data(data[0], data[1]));
break;
case "Temperature":
temperatureSeries.getData().add(new XYChart.Data(data[0], data[1]));
break;
}
这个代码是否有NullPointerException导致String []数据数组未初始化的原因?
异常错误
端口:/dev/tty.usbmodem1411已连接 线程中的异常" EventThread /dev/tty.usbmodem1411"显示java.lang.NullPointerException 在SerialComm.lambda $ connect $ 0(SerialComm.java:61) 在SerialComm $$ Lambda $ 1 / 1661773475.serialEvent(未知来源) 在jssc.SerialPort $ LinuxEventThread.run(SerialPort.java:1299)
答案 0 :(得分:2)
jssc库中定义的SerialPortEventListener
允许侦听串口事件。其中一个事件是RXCHAR
事件,当Arduino板发送一些数据并且某些字节在输入缓冲区上时发生。
event.getEventValue()
返回带有字节数的int
,serialPort.readString(event.getEventValue())
从这些字节中获取String
格式。
请注意,此方法不会返回整行,因此您需要侦听回车符和换行符。找到"\r\n"
后,您可以获取该行,并为下一个重置StringBuilder
:
sb.append(serialPort.readString(event.getEventValue()));
String str=sb.toString();
if(str.endsWith("\r\n")){
line.set(str.substring(0,str.indexOf("\r\n")));
sb=new StringBuilder();
}
其中line
是可观察的String
:
final StringProperty line=new SimpleStringProperty("");
在Arduino方面,如果你想以不同的速率从不同的传感器发送值,我建议你在Arduino草图上为每个传感器定义一些识别字符串,并为每个值打印其传感器的id。
例如,这些将是您将通过串行事件侦听器获得的读数:
ID1,val1
ID1,val2
ID2,val3
ID1,val4
ID3,val5
...
最后,在JavaFX线程上,为line
中的更改定义一个侦听器,并处理String
以获取传感器和值。像这样:
serial.getLine().addListener(
(ObservableValue<? extends String> observable, String oldValue, String newValue) -> {
Platform.runLater(()->{
String[] data=newValue.split("\\,");
if(data[0].equals("ID1"){
// add to chart from sensor 1, value data[1];
} else if(data[0].equals("ID2"){
// add to chart from sensor 2, value data[1];
} else if(data[0].equals("ID3"){
// add to chart from sensor 3, value data[1];
}
});
});
请注意,您需要添加Platform.runLater()
,因为从串行端口获取数据并更新line
的线程不在JavaFX线程上。
答案 1 :(得分:0)
根据我的经验,在Arduino方面,添加逗号或其他内容以在打印时分隔不同的值,当您在Java中收到该字符串时,只需用逗号分隔该字符串。
String[] stringSeparate = str.split(",");