Serielle Schnittstelle auslesen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Kirikkayis
User
Beiträge: 85
Registriert: Freitag 18. Januar 2019, 08:02

Hay :D

ich versuche gerade eine Serielle Schnittstelle auszulesen.
Folgendes habe ich programmiert bis jetzt:

Code: Alles auswählen

import serial


s = serial.Serial()

# Kommunikationsparameter
s.port = 'COM4'
s.baudrate = 115200
s.bytesize = 8
s.stopbits = serial.STOPBITS_ONE
s.parity = serial.PARITY_NONE
s.rts = True
s.dtr = True

s.timeout = None

print(s.timeout)
print(s.parity)

# Oeffne Kommunikation 
s.open()

# gib den Namen des Ports aus 
print(s.name)

# checkt ob Kommunikation offen ist 
print(s.is_open) 

test = []

if(s.isOpen()):
    xy = ("SET\n\r").encode('utf-8')
    s.write(xy)
    while(1):
        serial_line = s.readline().decode("utf-8")
        print(serial_line)
        test.append(serial_line)
  
    file = open("CAB690.txt", "w")
    file.write(str(test))
    file.close()
    s.close()
else:
    print("Cannot open serial port")
Ich erhalte die Daten EINWANDFREI und genau wie ich sie haben möchte.
Problem:
Ich bleibe in der "while(1)" - Schleife stecken ... und komme nicht dazu die Daten in meine file zu schreiben.
Gibt es irgendein Befehl um am ende der "while-Schleife" abzubrechen?
Also z.B. wenn ich keine Daten mehr erhalte soll er raus aus der while-Schleife
Benutzeravatar
__blackjack__
User
Beiträge: 14045
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Kirikkayis: Du müsstest halt irgend etwas senden was hier als Ende der Daten erkannt werden kann.

Die „unpythonischen“ Schreibweisen von `Serial` sollte man nicht mehr verwenden. Statt `isOpen()` hast Du doch sogar bereits `is_open` im Code stehen. Wobei dieser Test sinnfrei ist, denn wenn die `open()`-Methode fehlschlägt, dann wird eine Ausnahme ausgelöst. Warum verwendest Du die Methode überhaupt und erstellst das `Serial`-Objekt nicht gleich mit den Argumenten, statt die alle danach einzeln zu setzen?

Das `Serial`-Objekt ist sowohl ein Kontextmanager, kann also wie Dateien mit ``with`` verwendet werden, also auch iterierbar über die Zeilen. Die ``while``-Schleife sollte also eine ``for``-Schleife sein. Und auch die Datei sollte man mit ``with`` verwenden.

Es ist nicht sinnvoll die Zeichenkettendarstellung von Listen in eine Datei zu schreiben. Das ist kein Standardformat und kann Probleme beim wieder einlesen machen. Hier würde sich vielleicht JSON anbieten, oder man schreibt die empfangenen Zeilen einfach als Zeilen in die Datei. Bei Textdateien sollte man zudem eine Kodierung angeben. Oder Du dekodierst die Zeilen nicht und öffnest die Datei im Binärmodus und schreibst die Daten rein.

Die Kodierung von 'SET\n\r' als UTF-8 ist etwas umständlich – man könnte da doch gleich ein `bytes`-Literal hinschreiben. Und das auch nicht an so einen unsinnigen Namen binden sondern gleich als Argument hinschreiben. Ist die Reihenfolge '\n\r' tatsächlich so gewollt?

Alternativ könnte man das `Serial`-Objekt auch in einen `io.BufferedRWPair` und dann ein `io.TextIOWrapper` verpacken und damit sowohl (de)kodierung und Zeilenendenumwandlung erschlagen.
„A life is like a garden. Perfect moments can be had, but not preserved, except in memory. LLAP” — Leonard Nimoy's last tweet.
Kirikkayis
User
Beiträge: 85
Registriert: Freitag 18. Januar 2019, 08:02

Danke für die ganzen Vorschläge,

für mich wichtig ist wirklich das ich aus der while-schleife raus komme.
Was soll ich dann in meiner for-schleife schreiben? bzw. nach was soll die schleife laufen?
Ich muss die Daten in eine txt-Datei schreiben.

Also eigentlich muss ich folgendes machen:
- die Schnittstelle auslesen
- Ergebnis in eine Textdatei schreiben (decodiert)
- und wenn 1-2 Sekunden keine Daten erhalten werden abbrechen

Ich hab es schon mit meinem Timeout probiert und diesen auf 1s gesetzt … ich bleibe trzm in der while-schleifen stecken ...
Kirikkayis
User
Beiträge: 85
Registriert: Freitag 18. Januar 2019, 08:02

Sieht nun wie folgt aus:

Code: Alles auswählen

…
…
…

xy = ("SET\n\r").encode('utf-8')
s.write(xy)
while(1):
   serial_line = s.readline().decode("utf-8")
   test.append(serial_line)
   with open('testdatei.txt', 'a') as f:
        f.write(serial_line)
Die Daten werden nun in die Datei vollständig geschrieben.
Problem immer noch:

ich bleibe in while(1) stecken und habe somit eine Endlosschleife .... (leider)
Benutzeravatar
__blackjack__
User
Beiträge: 14045
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Kirikkayis: Du musst halt prüfen ob `serial_line` eine komplette Zeile enthält und falls nicht, dann abbrechen.

Gibt es wirklich keine andere Art das Ende festzustellen? Auf einen Prompt oder so etwas warten?

Ich würde da nicht immer wieder die Datei öffnen in der Schleife, sondern das einmal *vor* der Schleife machen.
„A life is like a garden. Perfect moments can be had, but not preserved, except in memory. LLAP” — Leonard Nimoy's last tweet.
Kirikkayis
User
Beiträge: 85
Registriert: Freitag 18. Januar 2019, 08:02

@__blackjack__ Danke für dein Hinweis :S

Das ist natürlich richtig Doof wie ich es gemacht habe. War auf die schnelle kurz runter programmiert.
Die Datei wird nun einmal vor der while-Schleife geöffnet und am Ende dann geschlossen (vorausgesetzt ich komme aus der while-Schleife heraus :D :D :D :D )

Nun, die Antwort auf diese Frage würde ich auch nur zu gern Erfahren
Gibt es wirklich keine andere Art das Ende festzustellen? Auf einen Prompt oder so etwas warten?
Das Skript wird später über einen Button meiner C++ GUI getriggert, bedeutet das Skript muss selber herausfinden das es keine Daten mehr erhält und aus der while-Schleife herausspringen (also das Ende feststellen)
Leider habe ich hierzu immer noch keine Lösung ...

Zu deinem Lösungsvorschlag: "... ob 'serial_line' eine komplette Zeile enthält und falls nicht, dann abbrechen."
Wie genau soll ich das anstellen?
Hab leider kein Plan :S
Danke nochmal für deine Mühe
Benutzeravatar
__blackjack__
User
Beiträge: 14045
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Kirikkayis: Schau Dir die Daten doch einfach an die da kommen. Was eine komplette Zeile ausmacht. Wenn das nicht mehr da ist, dann bist Du fertig.
„A life is like a garden. Perfect moments can be had, but not preserved, except in memory. LLAP” — Leonard Nimoy's last tweet.
Antworten