# serielle Schnittstelle einlesen



## Gast (26. Feb 2008)

Hallo, ich möchte Werte über die serielle Schnittstelle einlesen, ich verwernde das SimpleRead programm von Sun.
Sobald ich jedoch die Werte einlesen möchte erscheinen komische Rechtecke und die Werte Stimmen überahupt nicht mit denen überein, die tatsächlich gesendet werden!

Danke für die mögliche Hilfe!!


```
import java.io.*;
import java.util.*;
import gnu.io.*;

public class RS232_lesen implements Runnable, SerialPortEventListener 
{
    //Definieren von Variablen
    static CommPortIdentifier portId;
    static Enumeration        portList;
    InputStream           inputStream;
    SerialPort            serialPort;
    Thread            readThread;

    //Beginn der Statischen Methode
    public static void main(String[] args) {
    boolean           portFound = false;
    String            defaultPort = "COM1"; //Auswahl welcher Port verwendet werden soll

    //Überprüfen ob Port vorhanden
    if (args.length > 0) {
        defaultPort = args[0];
    } 
   
    portList = CommPortIdentifier.getPortIdentifiers();

    while (portList.hasMoreElements()) {
        portId = (CommPortIdentifier) portList.nextElement();
        if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) { //Ob serieller Port vorhanden
        if (portId.getName().equals(defaultPort)) { //wenn vorhandener Port gleich dem definierten Port ist
            System.out.println("Found port: "+defaultPort);
            portFound = true;
            RS232_lesen reader = new RS232_lesen(); //Konstruktor neues SimpleRead
        } 
        } 
    } 
    if (!portFound) { //Wenn Port nicht gefunde
        System.out.println("Port " + defaultPort + " nicht gefunden");//Fehlermeldung wenn Port nicht gefunden
    } 
    
    } 

    //Lesen
    public RS232_lesen() {
    try {
        serialPort = (SerialPort) portId.open("RS232 lesen", 2000);//Port wird gelesen
    } catch (PortInUseException e) {}

    try {
        inputStream = serialPort.getInputStream(); //Inputstream wird gelesen
    } catch (IOException e) {}

    try {
        serialPort.addEventListener(this);
    } catch (TooManyListenersException e) {}

    serialPort.notifyOnDataAvailable(true);
    //Eigenschaften der Seriellen Schnittstelle
    try {
        serialPort.setSerialPortParams(9600, 
                       SerialPort.DATABITS_8, 
                       SerialPort.STOPBITS_1, 
                       SerialPort.PARITY_NONE);
    } catch (UnsupportedCommOperationException e) {}
    
    readThread = new Thread(this);

    readThread.start();
    }
   
    //ausführend des Programmes
    public void run() {
    try {
        Thread.sleep(200);
    } catch (InterruptedException e) {}
    } 

    public void serialEvent(SerialPortEvent event) {
    switch (event.getEventType()) { //Ermittelt den Typ dieses Events(lesen/schreiben)

    case SerialPortEvent.BI: //Break interrupt
    case SerialPortEvent.OE: //Overrun error
    case SerialPortEvent.FE: //Framing error
    case SerialPortEvent.PE: //Parity error
    case SerialPortEvent.CD: //Carrier detect
    case SerialPortEvent.CTS://Clear to send
    case SerialPortEvent.DSR://Data set ready
    case SerialPortEvent.RI://Ring indicator

    case SerialPortEvent.OUTPUT_BUFFER_EMPTY://Wenn keine Daten verfügbar sind
        break;

    case SerialPortEvent.DATA_AVAILABLE: //Wenn Daten verfügbar sind
            byte[] readBuffer = new byte[4]; //Daten werden in den Buffer geschrieben

        try {
        while (inputStream.available() > 0) { //Daten werden gelesen und anschließend in eine Variable gespeichert
            int numBytes = inputStream.read(readBuffer);
            //System.out.println("Winkel="+ numBytes);
        } 
        
        System.out.print(new String(readBuffer)); //Buffer wird ausgelsesn
        } catch (IOException e) {}

        break;
    }
    } 

}
```


----------



## Gast (26. Feb 2008)

Es werden Bytes gesendet, 
Schau dir mal die ASCII- Tabelle an, du musst die Daten nach deinem Entsprechen umwandeln,
daten.get...();


----------



## Gast (26. Feb 2008)

Danke für die Antowrt, aber ich versteh nicht ganz wie ich die Bytes in eine Dezimalzahl umwandeln soll!?
Die Werte die Gesendet werden haben immer folgende Form: -021 zum Beispiel

LG


----------



## quippy (26. Feb 2008)

Du liest 4 Bytes von der Seriellen Schnittstelle, also z.B. einen Long oder Integer, halt einen 32 Bit Wert.

Daraus machst Du (je nach little endian oder big endian) folgendermaßen einen Long:


```
long l1 = ((readBuffer[0]&0xFF)<<24) | ((readBuffer[1]&0xFF)<<16) | ((readBuffer[2]&0xFF)<<8) | (readBuffer[3]&0xFF);
long l2 = ((readBuffer[3]&0xFF)<<24) | ((readBuffer[2]&0xFF)<<16) | ((readBuffer[1]&0xFF)<<8) | (readBuffer[0]&0xFF);
```

Bitte beachte nun: wenn Du statt long einen int erzeugst, wird die Zahl ggf. negativ (Zweierkomplement), der long bildet die Zahl jetzt Vorzeichenlos ab. Du kannst mit der Prüfung


```
if ((l1 & 0x80000000)>0) l1 |= 0xFFFFFFFF00000000; // wird negativ
```

prüfen, ob die Zahl im Zweierkomplement negativ sein könnte, falls bedarf besteht.

Der Code

```
System.out.print(new String(readBuffer)); //Buffer wird ausgelsesn
```
versucht, die 4 Bytes jeweils als ASCII-Zeichen zu interpretieren und nach Standardcodepage (Windows: iso-8869-15) in Unicode wandeln. Das wird definitiv schief gehen!


----------



## Gast (4. Mrz 2008)

Danke für die schnelle Antwort!

Hab das jetzt ausprobiert:


```
case SerialPortEvent.DATA_AVAILABLE: //Wenn Daten verfügbar sind
            byte[] readBuffer = new byte[4]; //Daten werden in den Buffer geschrieben 
            
            try {
        while (inputStream.available() > 0) { //Daten werden gelesen und anschließend in eine Variable gespeichert
            int numBytes = inputStream.read(readBuffer);
            
            long winkel = ((readBuffer[0]&0xFF)<<24) | ((readBuffer[1]&0xFF)<<16) | ((readBuffer[2]&0xFF)<<8) | (readBuffer[3]&0xFF);
            System.out.println("Winkel="+ winkel);
            
        }
```

und das ergebnis ist aber folgendes:

Winkel=218759168
Winkel=825819136
Winkel=872415232
Winkel=536870912
Winkel=536870912

Verstehe jetzt nicht ganz, wie diese Werte zustande kommen, da diese überhaupt nichts mit den Werten zu tun haben, die eigentlich gesendet werden!!

Wäre nett, wenn sie mir vielleicht nocheinmal helfen könnten!

LG


----------



## quippy (4. Mrz 2008)

Aus dem Grund hatte ich beide Varianten angegeben. Es ist nämlich entscheidend, in welcher Reihenfolge die Bytes interpretiert werden müssen.

Das hängt mit der Darstellung "Little Endian" und "Big Endian" (Hier ein Link dazu) zusammen.

Bitte, gib mir doch mal den Wert, der 'rauskommen sollte und den Wert, der dann tatsächlich 'rauskommt. Damit kann ich mal sehen, wie man das vielleicht zusammenfummeln muss.

Der Erste Wert aus Deinem Beispiel z.B. sagt, daß im Array die Werte {0x0D, 0x0A, 0x00, 0x00} geliefert wurden. Nun habe ich die Mal verschiedentlich kombiniert:


```
byte [] readBuffer = new byte[] {0x0D, 0x0A, 0x00, 0x00};
// BigEndian
long w1 = (((readBuffer[0]&0xFF)<<24) | ((readBuffer[1]&0xFF)<<16) | ((readBuffer[2]&0xFF)<<8) | (readBuffer[3]&0xFF))&0xFFFFFFFFL;
// LittleEndian
long w2 = (((readBuffer[3]&0xFF)<<24) | ((readBuffer[2]&0xFF)<<16) | ((readBuffer[1]&0xFF)<<8) | (readBuffer[0]&0xFF))&0xFFFFFFFFL;
//MiddleEndian I
long w3 = (((readBuffer[2]&0xFF)<<24) | ((readBuffer[3]&0xFF)<<16) | ((readBuffer[0]&0xFF)<<8) | (readBuffer[1]&0xFF))&0xFFFFFFFFL;
//MiddleEndian II
long w4 = (((readBuffer[1]&0xFF)<<24) | ((readBuffer[0]&0xFF)<<16) | ((readBuffer[3]&0xFF)<<8) | (readBuffer[2]&0xFF))&0xFFFFFFFFL;
System.out.println(w1 + "\t(0x"+ Long.toHexString(w1) + ")");
System.out.println(w2 + "\t(0x"+ Long.toHexString(w2) + ")");
System.out.println(w3 + "\t(0x"+ Long.toHexString(w3) + ")");
System.out.println(w4 + "\t(0x"+ Long.toHexString(w4) + ")");
System.out.println(0xDA);
System.out.println(0xAD);
```

Resultat:

```
218759168	(0xd0a0000)
2573	(0xa0d)
3338	(0xd0a)
168624128	(0xa0d0000)
218
173
```

Vielleicht der Richtige Wert schon dabei?


----------



## quippy (4. Mrz 2008)

:meld: 

*So, und nun vergessen wir mal den Mist, und schaun' mal bei Google vorbei*:

Hier steht doch was interessantes:


```
public void serialEvent(SerialPortEvent event) {
        switch(event.getEventType()) {
        case SerialPortEvent.BI:
        case SerialPortEvent.OE:
        case SerialPortEvent.FE:
        case SerialPortEvent.PE:
        case SerialPortEvent.CD:
        case SerialPortEvent.CTS:
        case SerialPortEvent.DSR:
        case SerialPortEvent.RI:
        case SerialPortEvent.OUTPUT_BUFFER_EMPTY:
            break;
        case SerialPortEvent.DATA_AVAILABLE:
            StringBuilder readBuffer = new StringBuilder();
            int c;
            try {
                 while ((c=inputStream.read()) != 10){
                   if(c!=13)  readBuffer.append((char) c);
                 }
                 String scannedInput = readBuffer.toString();
                 TimeStamp = new java.util.Date().toString();
                 System.out.println(TimeStamp + ": scanned input received:" + scannedInput);
                 inputStream.close(); //TODO: DAS HIER ERSCHEINT MIR SUSPEKT!!!
            } catch (IOException e) {}

            break;
        }
    }
```

Probier das mal als Alternative - da kommen offensichtlich tatsächlich doch Characters über die Leitung. Allerdings muss man das CR+LF halt ignorieren bzw. dann stoppen.

Den String machst Du dann zu einer Zahl, indem Du z.B. mit Integer.parseInt(scannedInput) umwandelst...

Sorry, aber da war ich komplett auf dem falschen Dampfer!  

Noch was zu dem "StringBuilder.append" an der Stelle. Das gelesene Byze wird da zu einem "char" gecastet. Damit wird aus einem Byte ein Unicode-Zeichen - äh, oder anders gesagt, es wird ein Nullbyte vorangestellt. Für Zahlen und die meisten Buchstaben klappt das, bei Umlauten (äöü) wird das kritisch, da man dann eine Codepage für die Übersetzung mitgeben müsste. Das kann z.B. String (new String(byte[], enc)). Das bedingt allerdings, daß Du dann in einen byte-Buffer lesen musst, dessen damit fixe Größe unter Umständen ein Nachlesen erzwingt.

Also vielleicht ist dann sowas notwendig, allerdings nur, wenn Du das mit dem Coding wirklich brauchst!

```
case SerialPortEvent.DATA_AVAILABLE :
				StringBuilder stringBuffer=new StringBuilder();
				byte[] readBuffer=new byte[1024];
				int c;
				int i=0;
				try
				{
					while ((c=inputStream.read()) != 0x0A)
					{
						if (c != 0x0D)
						{
							readBuffer[i++]=(byte) c;
							if (i > 1023)
							{
								stringBuffer.append(new String(readBuffer, 0, i, "ISO-8859-15"));
								i=0;
							}
						}
					}
					if (i > 0) stringBuffer.append(new String(readBuffer, 0, i, "ISO-8859-15"));
					String scannedInput=readBuffer.toString();
				}
				catch (IOException e)
				{
				}

				break;
```


----------



## Gast (6. Mrz 2008)

Danke, mit dem oberen Code hat es jetzt funktioniert!

Falls noch Probleme auftreten, meld ich mich wieder!

Danke nocheinmal für die Hilfe!!!!

LG


----------



## Gast (11. Mrz 2008)

Also es gibt doch wieder ein Problem!
Ich muss den String jetzt in einen Integer Variable umwandeln, dies hätte ich mit folgenden Befehlen probiert:


```
String s1 = readBuffer.toString();  readBuffer in String schreiben

winkel=Integer.valueOf(s1).intValue();
```
oder

```
winkel=Integer.parseInt(scannedInput);
```

Das problem ist jetzt, wenn ich winkel ausgeben möchte, ist dieser leer!!
Weiteres muss ich bemerken, dass anscheinend der String nicht einmal umgewandelt wird!!

Danke für eine mögliche Hilfe!!


----------



## quippy (11. Mrz 2008)

Der zweite Ansatz ist korrekt.


```
try
		{
			String s1 = "10";
			int winkel = Integer.parseInt(s1);
			Integer winkelObjekt = new Integer(s1);
			System.out.println(s1 + "->" + winkel);
			
			//Integer winkelObjekt = new Integer(s1); // das geht auch...
		}
		catch (Exception ex)
		{
			ex.printStackTrace(System.err);
		}
```

produziert erfolgreich die Ausgabe "10->10"...

Damit sind zwei potentielle Ursachen möglich:
a) der String ist leer
b) im String ist nicht nur eine Zahl, sondern vielleicht auch nicht numerische Zeichen- die kann ParseInt nicht parsen.

Zielführung:
1.) Ausgabe der Strings "s1" im Programm
2.) Abfangen der NumderFormatException (oder aller ggf. geworfener Exceptions) entsprechend meines obigen Beispiels

Bedenke, daß Exceptions des Typs "RuntimeException" keinen try-catch erfordern - da NumberFormatException davon ableitet, ist eine try-catch-Benhandlung vom Compiler nicht gefordert. Der obige try-catch im Beispiel reagiert daher auf "Throwable", was sowohl "RuntimeExceptions" als auch "Exceptions" fängt.

Allgemein noch der Rat: wenn Du Dir unsicher bist, was eine Methode so tut, schreibe Dir ein kleines Testproggi, so wie ich da oben. Damit kannst Du die Reaktion einzelner Befehle überprüfen, wenn Du Dir nicht sicher bist, ob sie so tun, wie gewünscht.

PS: Mich macht Deine Aussage "winkel ist leer" etwas stutzig. Wenn der parseInt nichts tut, sollte "winkel" 0 sein, aber eben nicht leer!
Wenn Du ein Integer-Objekt erzeugen wolltest, dann ist "winkel" hinterher "null", meintest Du das damit?


----------



## Gast (11. Mrz 2008)

also so wie du das probiert hast, hab ich es auch schon gemacht und es funktionieren beide Befehel, jedoch nur wenn der String definiert ist

wie z.B:


```
String s1="10";
```

wenn ich aber dann diesen readBuffer auslesen möchte funktioniert das ganze dann auch schon nicht mehr!

Liegt das vlt. daran, dass der String nicht direkt von readBuffer umgewandelt werden kann oder so?

LG


----------



## quippy (11. Mrz 2008)

Dann probier es aus, setze einen Breakpoint, mache eine Ausgabe oder mach noch ein kleines Testproggi:


```
try
		{
			byte [] readBuffer = new byte[] {0x33, 0x30, 0x00, 0x00};
			String s1 = new String(readBuffer, 0, 2, "ISO-8859-1");
			int winkel = Integer.parseInt(s1);
			Integer winkelObjekt = new Integer(s1);
			System.out.println(s1 + "->" + winkel);
		}
		catch (Exception ex)
		{
			ex.printStackTrace(System.err);
		}
```

liefert 30->30

alternativ (je nach dem, was du implementiert hast)


```
try
		{
			StringBuilder readBuffer = new StringBuilder();
			readBuffer.append((char)0x33);
			readBuffer.append((char)0x30);
			String s1 = readBuffer.toString();
			int winkel = Integer.parseInt(s1);
			Integer winkelObjekt = new Integer(s1);
			System.out.println(s1 + "->" + winkel);
		}
		catch (Exception ex)
		{
			ex.printStackTrace(System.err);
		}
```

was das Gleiche Ergebnis hat!

Alternativ: bitte den kompletten Code mal geben (also der serialEvent-Methode)


----------



## Gast (11. Mrz 2008)

Ok, hab das ganze mal beim Debuggen ausprobiert und habe festgetellt, dass die variable winkel immer 0 bleibt bzw. nie zur Ausgabe darunter gesprungen wird, sonder es fängt sofort wieder von oben an!

Hier mal die serial-event Methode:

```
public void serialEvent(SerialPortEvent event) { 
        switch(event.getEventType()) { 
        case SerialPortEvent.OUTPUT_BUFFER_EMPTY: 
            break; 
        case SerialPortEvent.DATA_AVAILABLE: 
            StringBuilder readBuffer = new StringBuilder(); 
            int c; 
            int winkel=0;
            double winkel2=0;
            String Input="";
            try { 
                 while ((c=inputStream.read()) != 10){ 
                   if(c!=13)  readBuffer.append((char) c); 
                 }
                 
                 Input = readBuffer.toString(); 
                 System.out.println(""+ Input);
                 winkel=Integer.parseInt(Input);
                 System.out.println(Input +"="+ winkel);
} catch (IOException e) {} 

            break; 
          
        } 
    }
```


----------



## quippy (11. Mrz 2008)

Und wie sieht die Ausgabe von "Input" aus? Bzw. was sagt der Debugger, was da drinne ist?

Versuch's mal damit:


```
public void serialEvent(SerialPortEvent event)
	{
		switch (event.getEventType())
		{
			case SerialPortEvent.OUTPUT_BUFFER_EMPTY :
				break;
			case SerialPortEvent.DATA_AVAILABLE :
				StringBuilder readBuffer=new StringBuilder();
				int c;
				double winkel;
				try
				{
					while ((c=inputStream.read()) != 10)
					{
						if (c != 13) readBuffer.append((char) c);
					}

					String input=readBuffer.toString();
					System.out.println(input);
					try
					{
						winkel=Double.parseDouble(input);
					}
					catch (NumberFormatException ex)
					{
						ex.printStackTrace(System.err);
					}
					System.out.println(input + "=" + winkel);
				}
				catch (IOException e)
				{
					e.printStackTrace(System.err);
				}

				break;

		}
	}
```

By the way:

```
String Input="";
```
ist übrigens ein schlechter Stil, da damit eine Referenz auf einen leeren String erzeugt wird. Da bleibt Input besser null. Außerdem: variablennamen immer klein


----------

