Heim >Java >javaLernprogramm >Detaillierte Erläuterung der seriellen Java-Kommunikation
Vorwort
Wenn es um Open Source geht, gibt es wahrscheinlich nur wenige Menschen, die es nicht mit dem großen Zeigefinger loben würden. Studenten erlernen Wissen durch Open-Source-Code, Programmierer sammeln durch Open-Source-Klassenbibliotheken erfolgreiche Erfahrungen anderer und können die anstehenden Projekte termingerecht abschließen, und Händler verdienen Geld durch Open-Source-Software ... Kurz gesagt, alle sind glücklich. Der Hauptnachteil von Open-Source-Software oder Klassenbibliotheken besteht jedoch darin, dass es ihnen meist an detaillierter Dokumentation und Anwendungsbeispielen mangelt oder dass der Softwarecode nur für Sie bestimmt ist und Sie nur Geld für die Dokumentation, Beispiele und Nachbearbeitungsdienste verlangen . Kein Wunder, denn wie ein berühmter NBA-Spieler sagte: „Ich muss immer noch meine Familie ernähren, also verhandeln Sie nicht mit mir über einen Vertrag über weniger als 10 Millionen US-Dollar, sonst wäre ich lieber arbeitslos.“ Ja, Menschen, die Open Source unterstützen, müssen auch ihre Familien unterstützen, daher ist es nicht zu viel, etwas Geld zu verlangen. Wenn Sie Wissen erlernen möchten, ohne Geld auszugeben, können Sie nur das Internet nutzen. Ich möchte nur einen kleinen Beitrag zur Open-Source-Sache leisten. Es reicht aus, um auch nur ein kleines Problem für Ihr Projekt zu lösen.
Obwohl es sich bei den Dingen, die ich in dieser Serie vorstelle, nicht um Web-Frameworks oder Open-Source-Server handelt, glaube ich, dass Sie als Programmierer auf alle möglichen Probleme stoßen werden. Manchmal gilt: Je einfacher das Problem, desto schwieriger ist es; je kleiner der Ort, desto schwieriger ist es, jemanden zu finden, der es lösen kann. Solange Sie sich nicht den ganzen Tag nur mit „Architektur“, „Komponente“ und „Framework“ beschäftigen, werden Sie meines Erachtens auf jeden Fall anwenden, was ich gesagt habe.
1 Einführung in die serielle Kommunikation
1.1 Gängige Java-Serienpakete
1.2 Installation serieller Pakete (unter Windows)
2 Übersicht über die serielle API
2.1 javax.comm.CommPort
2.2 javax.comm.CommPortIdentifier
2.3 javax.comm.SerialPort
2 . 4 API-Instanz für serielle Ports
2.4.1 Alle verfügbaren seriellen Ports auf diesem Computer auflisten
2.4.2 Konfiguration der Parameter der seriellen Ports
2.4.3 Lesen und Schreiben von seriellen Ports Ports
3 gängige Modi der seriellen Kommunikation und ihre Probleme
3.1 Event-Listening-Modell
3.2 Threading-Modell für das Lesen von Daten über serielle Ports
3.3 Die dritte Methode
4 Fazit
1 Einführung in die serielle Kommunikation
Viele Anwendungen und Tests eingebetteter Systeme oder Sensornetzwerke erfordern PCs und eingebettete Geräte bzw Sensorknoten. Unter diesen sind die am häufigsten verwendeten Schnittstellen der serielle RS-232-Anschluss und der parallele Anschluss (angesichts der Komplexität der USB-Schnittstelle und der Tatsache, dass keine große Datenübertragungsmenge erforderlich ist, ist die USB-Schnittstelle immer noch zu extravagant). Zusätzlich zu SUN gibt es derzeit ein Paket, das USB unterstützt. Ich habe keine anderen Java-Bibliotheken gesehen, die USB direkt unterstützen. Die CommAPI von SUN bietet Unterstützung für häufig verwendete serielle RS232-Port- bzw. IEEE1284-Parallelport-Kommunikationen. RS-232-C (auch bekannt als EIA RS-232-C, im Folgenden als RS232 bezeichnet) wurde 1970 von der Electronic Industries Association (EIA) in Zusammenarbeit mit Bell Systems, Modemherstellern und Computerterminalherstellern für die serielle Kommunikation entwickelt. Standards. RS232 ist ein Vollduplex-Kommunikationsprotokoll, das gleichzeitig Daten empfangen und senden kann.
1.1 Gängige Java-Pakete für serielle Ports
Derzeit umfassen gängige Java-Pakete für serielle Ports die 1998 von SUN veröffentlichte serielle Kommunikations-API: comm2.0.jar (unter Windows), comm3.0. jar (Linux/Solaris); die serielle Kommunikations-API und eine Open-Source-Implementierung. Da die API von SUN häufig unter Windows verwendet wird und die Implementierung von IBM auf API-Ebene mit der von SUN übereinstimmt, ist die Open-Source-Implementierung nicht so sicher wie die Produkte der beiden großen Hersteller. Hier stellen wir nur die Verwendung der seriellen Port-API von SUN vor Windows-Plattform.
1.2 Installation des seriellen Port-Pakets (unter Windows)
Gehen Sie zur SUN-Website und laden Sie javacomm20-win32.zip herunter. Der Inhalt lautet wie folgt:
Wenn Sie das Serial-Port-Paket für die serielle Kommunikation verwenden möchten, müssen Sie gemäß den Anweisungen (Readme.html) zusätzlich zum Festlegen der Umgebungsvariablen auch win32com.dll in das Verzeichnis
Es ist erwähnenswert, dass bei der Verwendung der seriellen Port-API in Netzwerkanwendungen andere komplexere Probleme auftreten. Wenn Sie interessiert sind, können Sie den Beitrag „Über das Problem, dass Applet javacomm20 zum Lesen des seriellen Client-Ports auf der Webseite verwendet“ in der CSDN-Community lesen.
2 Übersicht über die serielle Port-API
2.1 javax.comm.CommPort
Dies ist eine abstrakte Klasse, die zur Beschreibung eines Ports verwendet wird, der vom zugrunde liegenden System unterstützt wird. Es enthält einige High-Level-IO-Steuerungsmethoden, die allen verschiedenen Kommunikationsports gemeinsam sind. SerialPort und ParallelPort sind beide Unterklassen. Erstere wird zur Steuerung des seriellen Ports und Letztere zur Steuerung des parallelen Ports verwendet. Beide verfügen über unterschiedliche Steuerungsmethoden für ihre zugrunde liegenden physischen Ports. Hier geht es uns nur um SerialPort.
2.2 javax.comm.CommPortIdentifier
Diese Klasse wird hauptsächlich zur Verwaltung und Einrichtung der seriellen Schnittstelle verwendet. Sie ist die Kernklasse für die Zugriffskontrolle der seriellen Schnittstelle. Dazu gehören hauptsächlich die folgenden Methoden
l Bestimmen Sie, ob ein Kommunikationsport verfügbar ist
l Öffnen Sie den Kommunikationsport für den E/A-Betrieb
l Bestimmen Sie den Besitz des Ports
l Verarbeiten von Konflikten um Portbesitz
l Verwalten von Ereignissen, die durch Änderungen des Portbesitzes verursacht werden
2.3 javax.comm.SerialPort
Diese Klasse wird verwendet, um einen RS- zu beschreiben. 232 Serieller Port Die zugrunde liegende Schnittstelle des seriellen Kommunikationsports, die den Mindestsatz an Funktionen definiert, die für die serielle Kommunikation erforderlich sind. Dadurch können Benutzer die serielle Schnittstelle direkt lesen, schreiben und einrichten.
2.4 Beispiel für eine serielle Schnittstelle
Ein langer Textabschnitt ist nicht so klar wie ein kleines Beispiel, das mit dem Paket für die serielle Schnittstelle geliefert wird – ein kurzes Absatz im SerialDemo-Code, um das Verständnis für die Verwendung der Kernklassen der seriellen Port-API zu vertiefen.
2.4.1 Alle verfügbaren seriellen Ports auf diesem Computer auflisten
void listPortChoices() {
CommPortIdentifier portId;
Enumeration en = CommPortIdentifier.getIdentifiers ( ) ;
// Durch die Ports iterieren.
while (en.hasMoreElements()) {
portId = (CommPortIdentifier) en.nextElement();
if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) {
}
portChoice.select(parameters.getPortName()); COM1 und COM3.
2.4.2 Konfiguration der Parameter der seriellen Schnittstelle
Die serielle Schnittstelle verfügt im Allgemeinen über die folgenden Parameter, die vor dem Öffnen der seriellen Schnittstelle konfiguriert werden können:
Einschließlich Baudrate, Eingabe-/Ausgabeflusskontrolle, Anzahl der Datenbits, Stoppbits und Parität. SerialPort sPort;try {
sPort.setSerialPortParams(BaudRate,Databits,Stopbits,Parity);
//Eingabe-/Ausgabekontrollfluss festlegen
sPort.setFlowControlMode(FlowControlIn | FlowControlOut);
} Catch (UnsupportedCommOperationException e) {}
2.4.3 Lesen und Schreiben der seriellen Schnittstelle
Serial port Vor dem Lesen und Schreiben müssen Sie zunächst einen seriellen Port öffnen:
CommPortIdentifier portId = CommPortIdentifier.getPortIdentifier(PortName);
try {
SerialPort sPort = (SerialPort ) portId.open(" Name des Besitzers des seriellen Ports", Timeout-Wartezeit);
} Catch (PortInUseException e) {//Diese Ausnahme auslösen, wenn der Port belegt ist
());
os.write(int data);
//Wird zum Lesen von Daten vom seriellen Port verwendet
InputStream is = new BufferedInputStream(sPort .getInputStream()) ;
int empfangenData = is.read();
liest den Typ int, Sie können ihn bei Bedarf in andere Typen konvertieren.
An dieser Stelle ist zu beachten, dass Sie bei der Konvertierung von Byte nach Int besondere Aufmerksamkeit schenken sollten, da die Java-Sprache keine vorzeichenlosen Typen hat, d. Denn wenn das höchste Bit des Bytes 1 ist, wird 1 bei der Konvertierung in den Typ int als Platzhalter verwendet. Auf diese Weise wird die ursprüngliche Bytetypnummer 10000000 zum Typ int und zu 1111111110000000. Dies ist ein sehr ernstes Problem und sollte vermieden werden.
3 gängige Arten der seriellen Kommunikation und ihre Probleme
Endlich habe ich über das Grundwissen gesprochen, das ich am meisten hasse – nun beginnen wir mit unserem Fokus – der Forschung zu seriellen Port-Anwendungen . Da das Schreiben von Daten an die serielle Schnittstelle sehr einfach ist, konzentrieren wir uns hier nur auf das Lesen von Daten von der seriellen Schnittstelle. Normalerweise gibt es zwei Modi für serielle Kommunikationsanwendungen. Der eine besteht darin, die SerialPortEventListener-Schnittstelle zu implementieren, um verschiedene Ereignisse der seriellen Schnittstelle zu überwachen und sie entsprechend zu verarbeiten. Der andere besteht darin, einen unabhängigen Empfangsthread einzurichten, der speziell für den Empfang von Daten verantwortlich ist. Da diese beiden Methoden in einigen Fällen schwerwiegende Probleme haben (was das Problem betrifft, lasse ich es vorerst offen), besteht meine Implementierung darin, dieses Problem mit der dritten Methode zu lösen.
3.1 Event-Listening-Modell
Lassen Sie uns nun einen Blick darauf werfen, wie das Event-Listening-Modell funktioniert
:
l Zuerst müssen Sie die Klasse steuern Ihr Port (z. B. SManager) Fügen Sie „implements SerialPortEventListener“ hinzu 🎜> in dem die Folgende Ereignisse werden beurteilt:
BI – Kommunikationsunterbrechung.
CD – Trägererkennung.
CTS – Frei zum Senden.
DATA_AVAILABLE – Daten angekommen.
DSR – Datengerät bereit.
FE – Frame-Fehler.
OE – Überlauffehler
OUTPUT_BUFFER_EMPTY – Ausgabepuffer geleert 🎜> PE – Paritätsfehler.
RI – Klingelanzeige.
Im Allgemeinen wird DATA_AVAILABLE am häufigsten verwendet – der serielle Port hat ein Datenankunftsereignis. Das heißt, wenn Daten an der seriellen Schnittstelle ankommen, können Sie die empfangenen Daten in serialEvent empfangen und verarbeiten. In meiner Praxis stieß ich jedoch auf ein sehr ernstes Problem.
Beschreiben Sie zunächst mein Experiment: Meine Anwendung muss die vom Sensorknoten vom seriellen Port zurückgesendeten Abfragedaten empfangen und die Ergebnisse in Form von Symbolen anzeigen. Die vom seriellen Port festgelegte Baudrate beträgt 115200. Kawaguchi gibt alle 128 Millisekunden einen Datensatz (ca. 30 Byte) zurück, und der Zeitraum (dh die Dauer) beträgt 31 Sekunden. Während der eigentlichen Messung sollten in einem Zyklus mehr als 4900 Bytes zurückgegeben werden. Allerdings kann ich mit dem Event-Listening-Modell höchstens weniger als 1500 Bytes empfangen wissen, was verloren gegangen ist. Es ist erwähnenswert, dass dies darauf zurückzuführen ist, dass ich den gesamten Verarbeitungscode in serialEvent() auskommentiert habe und nur den Druckcode übrig habe. Da ich die Schwere des Datenverlusts nicht ertragen konnte, entschied ich mich für andere Methoden.
3.2 Thread-Modell zum Lesen von Daten über die serielle Schnittstelle
Wie der Name schon sagt, schreibt dieses Modell den Vorgang des Datenempfangs in Form eines Threads:
public void startReadingDataThread( ) {
Thread readDataProcess = new Thread(new Runnable() {
public void run() {
while (newData != -1) {
versuchen Sie es mit {
newData = is.read();
system.out.println (newdata);
In meiner Anwendung packe ich die empfangenen Daten in einen Cache und starte dann einen weiteren Thread, um die Daten aus dem Cache abzurufen und zu verarbeiten. Die beiden Threads arbeiten im Producer-Consumer-Modus zusammen und der Datenfluss ist wie in der folgenden Abbildung dargestellt:Auf diese Weise habe ich das Datenproblem erfolgreich gelöst Verlust. Doch nicht lange nachdem ich zufrieden war, entdeckte ich ein ebenso ernstes Problem: Obwohl ich dieses Mal keine Daten mehr verlor, hörte die Energieeinsparung des Sensors nach einem Zyklus (31 Sekunden) auf, Daten zu übertragen, aber mein serieller Port-Thread funktionierte immer noch hart Um den Lesevorgang der seriellen Schnittstelle durchzuführen, können Sie auch auf der Konsole sehen, dass die empfangenen Daten weiterhin kontinuierlich gedruckt werden. Da die vom Sensorknoten gesendeten Daten zu schnell sind und mein empfangender Thread sie nicht verarbeiten kann, stellt sich heraus, dass InputStream zunächst die angekommenen, aber noch nicht verarbeiteten Bytes zwischenspeichert, was dazu führt, dass der Sensorknoten nicht mehr sendet data , aber die Konsole kann immer noch das seltsame Phänomen erkennen, dass Daten kontinuierlich gedruckt werden. Das einzig Gute ist, dass die endgültig empfangenen Daten tatsächlich etwa 4900 Byte groß sind und kein Verlust auftritt. Die Verarbeitung der letzten Daten dauerte jedoch fast anderthalb Minuten, was viel länger ist als der Betriebszyklus des Knotens. Diese Verzögerung ist eine Katastrophe für ein Echtzeit-Anzeigesystem!
Später dachte ich: Liegt es an der Synchronisation und Kommunikation zwischen den beiden Threads, dass der Datenempfang langsam ist? Daher habe ich den gesamten Verarbeitungscode im Code des empfangenden Threads entfernt und nur die Anweisung zum Drucken der empfangenen Daten übrig gelassen, und das Ergebnis blieb dasselbe. Es scheint, dass nicht die Kommunikation zwischen Threads die Datenempfangsgeschwindigkeit behindert, sondern das Thread-Modell, das die Datenempfangsverzögerung verursacht, wenn die Datenübertragungsrate des Absenders zu hoch ist. Hierbei ist zu beachten, dass die beiden erstgenannten Modelle auch dann nützlich sein sollten, wenn die Datenübertragungsrate nicht so hoch ist, Sonderfälle jedoch speziell behandelt werden sollten.
3.3 Die dritte Methode
Nachdem ich lange gelitten hatte (Boss drängte mich jeden Tag zu L), hörte ich zufällig, dass einige Teile von TinyOS (wieder Open Source) ähnlich sind Meine Anwendung hat einen ähnlichen seriellen Kommunikationsteil, daher habe ich den Java-Codeteil der Version 1.x heruntergeladen und auf die Verarbeitungsmethode verwiesen. Der Weg, das Problem zu lösen, ist eigentlich sehr einfach, nämlich von der Grundursache auszugehen. Liegt die Ursache nicht am empfangenden Thread? Nun, ich werde einfach den empfangenden Thread und den gemeinsam genutzten Cache als Vermittler abbrechen und die Lesemethode für die serielle Schnittstelle im Verarbeitungsthread direkt aufrufen, um das Problem zu lösen (was, warum nicht). auch den Verarbeitungsthread verwenden und abbrechen? ----Würde die Anwendungsschnittstelle nicht gesperrt, wenn Sie sie abbrechen? Also muss sie beibehalten werden) Das Programm sieht also so aus:
public byte[] getPack( ){
while (true) {
for(int i = 0; i < ; PacketLength; i++){
if (((((((((((((newData)! "🎜>
msgpack [i] = (byte) newdata;System.Println (msgpack [ i]);
}
}
Return msgpack;
}
Rufen Sie diese Methode auf um die erforderliche Datensequenz zurückzugeben und zu verarbeiten. Auf diese Weise kommt es nicht nur zu keinem Datenverlust, sondern auch zu keiner Verzögerung beim Datenempfang. Das Einzige, was hier zu beachten ist, ist, dass is.read() immer -1 zurückgibt, wenn der serielle Port keine Daten mehr sendet. Wenn -1 zu Beginn des Datenempfangs gefunden wird, ignorieren Sie ihn und fahren Sie mit dem Empfang fort Es werden tatsächliche Daten zu den Daten empfangen.
4 Fazit
Ausführlichere Artikel zur seriellen Java-Kommunikation finden Sie auf der chinesischen PHP-Website!