Temperaturmesswerte über RS232 einlesen

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.
Regret
User
Beiträge: 17
Registriert: Freitag 20. Mai 2016, 10:58

Hi Leute,

ich arbeite gerade an einem Teststand als Bachelorarbeit. Zur Zeit wird beim Kalibrieren die Referenztemperatur vom Display des geeichten Messgeräts abgelesen. Da das Gerät auch eine RS232 Schnittstelle hat, wollte ich mir es etwas einfacher machen. Also hab ich folgendes versucht:

Code: Alles auswählen

import time
import serial

port = serial.Serial("/dev/ttyS0", 115200, timeout=0.2)

RefTemp = open("RefTemp.dat", "w") 	
RefTemp.close()						

while True:
	RefTemp = open("RefTemp.dat", "w")
	newline = port.readline()
	RefTemp.write(str("newline;time.ctime();\n"))
	RefTemp.close()
	print newline
Nachdem der Port geöffnet ist, soll eine .dat Datei mit dem Namen "RefTemp" erstellt werden. Das funktioniert soweit auch, aber:
Weder im Terminal, noch in der Textdatei stehen dann die vom Gerät über die RS232 übertragenen Daten. Wenn ich den Port jedoch mit "Screen" auslese, gibt er mir die gewünschten Werte aus. Also am Port selbst kann es nicht liegen. Ich bin absoluter Python-Neuling, mach ich was oben falsch?

Viele Grüße :)

EDIT: newline = newline[13:20] hab ich noch in die while-Schleife hinzugefügt, da das Format des RS232 Signals so ist:

01:29:59 00: +022.050 °C P304 ist und ich nur die Zeichen 13-20 (+022.050) brauche.
Zuletzt geändert von Anonymous am Montag 23. Mai 2016, 15:45, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
BlackJack

@Regret: Du erwartest offenbar das auf magische Weise nicht der Inhalt der literalen Zeichenkette geschrieben wird, sondern das Python da irgendwie rät das es da etwas durch etwas anderes ersetzen soll. Wenn Du die Zeichenkette 'newline;time.ctime();\n' in die Datei schreibst, dann wird eben genau diese Zeichenkette in die Datei geschrieben. Wenn Du aus dem Wert der an den Namen `newline` gebunden ist und der aktuellen Zeit als Zeichenkette eine neue Zeichenkette zusammensetzen möchtest, dann musst Du *das* machen. Zum Beispiel mit der `format()`-Methode auf Zeichenketten.
Regret
User
Beiträge: 17
Registriert: Freitag 20. Mai 2016, 10:58

Naja eigentlich wollte ich das nur mal ausprobieren. Ich war mir da schon unsicher ob das klappt, aber soweit kams ja leider garnicht.

Natürlich hast du aber Recht. Das werd ich morgen direkt ändern.

Wenn ich jetzt aber wie folgt erst einmal das aufschreiben der Werte sein lasse, funktioniert es leider auch nicht.

Code: Alles auswählen

    import time
    import serial
     
    port = serial.Serial("/dev/ttyS0", 115200, timeout=0.2)
              

    while True:
        newline = port.readline()
        print newline
Nach meinem Verständnis öffnet ich ja mit pyserial den Port und lese mit port.readline() in der Schleife immer eine Zeile aus die ich direkt ausgebe oder? Also im Endeffekt mach ich ja das gleiche wie mit "Screen". Ich versteh nur nicht, wieso ich in Screen tatsächlich dann was ausgegeben bekomme und bei dem Python Skript nicht
BlackJack

@Regret: Was heisst ”funktioniert nicht”? Und wie macht man so etwas mit ``screen``?
Regret
User
Beiträge: 17
Registriert: Freitag 20. Mai 2016, 10:58

Naja mit

Code: Alles auswählen

screen /dev/ttyS0 115200
werden eben ähnlich wie wenn man PuttY auf die serielle Schnittstelle anwendet die Signale im Terminal ausgegeben. In meinem Fall weiß ich daher ja, dass mein Signal als "01:29:59 00: +022.050 °C P304" ausgegeben wird. Die Frage ist eben nur wieso ich im Terminal die Ausgabe sehe wenn ich Screen nutze, bei Python hingegen aber nur leere Zeilen ausgegeben werden.

Mit funktioniert nicht meinte ich diese Zeile: RefTemp.write(str("newline;time.ctime();\n"))
Ich wollte die eigentlich mal testen, aber leider kam ich ja auf Grund fehlender Ausgabe noch nicht dazu. Aber wenn du sagst, dass es sowieso nicht so funktioniert, werd ich das morgen nochmal überarbeiten.
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Kann es sein dass kein \n sondern ein \r ausgegeben wird?
harryberlin
User
Beiträge: 227
Registriert: Donnerstag 17. Dezember 2015, 12:17

Code: Alles auswählen

RefTemp.write('%s;%s;\n' % (newline, time.ctime()))
ungetestet
was soll dieses ständige open/close der datei in der schleife?
empty Sig
Regret
User
Beiträge: 17
Registriert: Freitag 20. Mai 2016, 10:58

@harryberlin: Naja ich hatte eben gestern gelesen, dass ich nach dem Bearbeiten das Dokument wieder schließen muss. Also wär es sinnvoller das Dokument vor der Schleife zu öffnen und geöffnet zu lassen? Aber vielen Dank schonmal für die Hilfe. Sobald ich das Problem mit dem Signaleingang gelöst habe, werd ich das anpassen.

@DasIch: Ich dachte bisher \n seht für eine "newline" im Dokument. Was wäre dann \r? Ich wollte damit bezwecken, dass der Messwert, etc. in eine Zeile geschrieben wird und dann in die neue Zeile gesprungen wird. Eigentlich hätte ich es einfach ausprobiert um zu sehen ob es wirklich tut was ich möchte, aber der Output der RS232 wird ja schon garnicht angezeigt.
Regret
User
Beiträge: 17
Registriert: Freitag 20. Mai 2016, 10:58

Nachtrag: Bild

Damit ihr wisst was ich mit "Screen" meine. Ich hab wie oben erwähnt den Befehl genutzt um Screen mit der Seriellen Schnittstelle zu connecten und jedes mal wenn ich dann "s" drücke erscheint die Ausgabezeile wie auf dem Bild zu sehen, also Zeitstempel des Gerätes und Messtemperatur.
Sirius3
User
Beiträge: 18335
Registriert: Sonntag 21. Oktober 2012, 17:20

@Regret: es geht um den Input. Wie liefert Dein Gerät die Daten. Mit '\r' oder mit '\n' abgeschlossen. Beides ist möglich, aber nur '\n' funktioniert mit readline. Um zu testen, ob überhaupt etwas von der Schnittstelle kommt, solltest Du mal mit `port.read()` einzelne Bytes lesen und ausgeben.

Wenn Du die Datei parallel von einem anderen Programm lesen möchtest, ist es schon ratsam, die Datei immer wieder zu schließen, damit auch alle Daten geschrieben werden.
Regret
User
Beiträge: 17
Registriert: Freitag 20. Mai 2016, 10:58

Hallo Sirius3,

danke für deine Antwort.

Ich hab gerade mal folgendes probiert:

Code: Alles auswählen

import time
import serial

port = serial.Serial("/dev/ttyS0", 115200, timeout=1)

while 1:
	x = port.read()
	print x
Leider besteht das Problem weiterhin, im Terminal spring ich zwar von Zeile zu Zeile als ob er was ausgibt, aber die Zeilen sind leer.

Bild
BlackJack

@Regret: Es kommt halt auf die Definition von „nach dem Bearbeiten“ an. Falls zwischen den Schreibvorgängen nicht längere Zeiträume liegen, würde man die Datei wohl eher erst nach der Schleife schliessen. Und dann am besten durch die ``with``-Anweisung oder in einem ``finally``-Block, weil bei dieser Schleife ja nicht ganz auszuschliessen ist, dass sie durch eine Ausnahme abgebrochen wird (E/A-Fehler, Zeitüberschreitung, Benutzer drück STRG+C, …). Wobei Du das schon richtig gemacht hast falls Du *wirklich* immer nur *eine* Zeile in der Datei stehen haben möchtest. Falls alle gelesenen Zeilen in der Datei landen sollten, dann ist der Dateimodus an der Stelle falsch, denn 'w' löscht eventuell schon vorhandenen Inhalt beim Öffnen der Datei.

'\r' ist ein Wagenrücklauf. Und das *Du* '\n' in die Datei schreibst ist schon okay, es ging eher darum was als Zeilenende über die serielle Schnittstelle kommt. `readline()` wartet nämlich auf '\n'. Wenn das nicht kommt, kann man lange warten. Da ein `Serial`-Objekt von `io.RawIOBase`, sollte man da mit einem `BufferedReader` und einem `TextIOWrapper` etwas ausrichten können. (An der Stelle fängt es an ein wenig „javaesque“ zu werden. :-()

Wo hast Du in Deinem Programm denn das 's' eingebaut? Wenn man das zur Gegenseite senden muss, dann musst Du das natürlich auch in Deinem Programm machen.
Regret
User
Beiträge: 17
Registriert: Freitag 20. Mai 2016, 10:58

Hallo BlackJack,

also im Prinzip wollte ich eine Textdabei die am Schluss mal pro Sekunde eine Textzeile hinzufügen soll. Bei der Kalibrierung der Temperaturfühler nimmt das Programm pro Sekunde einen Messwert auf, genau das wollte ich dann eben mit dem geeichten Temperaturfühler mit der Referenztemperatur auch machen um einen vergleichbaren Zeitstempel bzw. Abstand zwischen den Messwerten zu erreichen.

Das s hab ich garnicht in das Programm eingebaut, ich hab nur zufällig rausgefunden das ich im Terminal die Zeile ausgegeben bekomme wenn ich s drücke während "Screen" auf die Serielle Schnittstelle zugreift. Die Frage ist eben ob das an Screen oder dem Messgerät liegt. Also ob Screen eben nur die Zeile ausgibt mit s oder das Messgerät einfach nur auf "s" die Zeile antwortet.

Nochmal zu Python: Ich dachte ich könnte mit "w" einfach in die nächste Zeile schreiben. Also das mein Textdokument etwa so aussieht:

22,359 10:07:21 24052016
22,358 10:07:22 24052016
22,359 10:07:23 24052016
22,359 10:07:24 24052016
22,359 10:07:25 24052016
22,358 10:07:26 24052016
22,359 10:07:27 24052016
.
.
.

Aber so programmiertechnisch würde ich das denke ich schon hinbekommen, wenn es dann mal funktioniert den Messwert überhaupt irgendwie in das Textdokument zu schreiben. Aber anscheinend ist das Problem ja schon, dass ich es nicht hinkriege die Zeile des Messgeräts mit Python überhaupt einzulesen um dann quasi Formatierung, Zeitstempel, etc. anzupassen. Ich weiß eigentlich nur wie das Signal aussieht, weil ich eben mit Screen die Serielle Stelle separat zu Python ausgelesen habe.
Sirius3
User
Beiträge: 18335
Registriert: Sonntag 21. Oktober 2012, 17:20

Solangsam wird das Bild klarer. Wenn Du die Datei immer weiter füllen willst, dann solltest Du sie nur einmal vor der Schleife öffnen und dann nur immer eine neue Zeile schreiben. Wenn das Messgerät ein 's\n' oder 's\r\n' erwartet, dann solltest Du das auch senden.
BlackJack

Ungetestet und davon ausgehend das die Zeilenenden mit einem '\n' kodiert werden:

Code: Alles auswählen

#!/usr/bin/env python
# coding: utf8
from __future__ import absolute_import, division, print_function
import time
from serial import Serial


def main():
    try:
        with Serial('/dev/ttyS0', 115200, timeout=0.2) as connection:
            with open('RefTemp.dat', 'w') as out_file:
                while True:
                    connection.write('s\n')
                    connection.flush()
                    line = next(connection)
                    if not line.endswith('\n'):
                        raise ValueError('Oooh, we are in trouble Scotty.')
                    out_file.write('{0};{1};\n'.format(line.rstrip(), time.ctime()))
                    time.sleep(1)
    except KeyboardInterrupt:
        pass  # Allow the user to stop the program with CTRL+C.


if __name__ == '__main__':
    main()
Regret
User
Beiträge: 17
Registriert: Freitag 20. Mai 2016, 10:58

@Sirius3: So also langsam wird das Bild für mich selbst auch ein bisschen klarer. Ich wusste nicht, dass das Messgerät den Messwert nicht nur auf "Anfrage" sendet. Also generell kannte und kenne ich mich leider noch nicht mit seriellen Schnittstellen aus.

@BlackJack: Ich hab den Code probiert. Leider hat das auch nicht geklappt. Nach starten des Skripts wurde die Datei zwar erstellt aber sie war leer und auch im Terminal wurd nix angezeigt.

ABER:

Ich hab aus deinem Script jetzt einfach mal den Befehl übernommen das an die Schnittstelle "s" geschickt wird mit der Zeile

Code: Alles auswählen

port.write('s\n')
und siehe da: Ich seh zumindest mal im Terminal genau das was ich wollte: Bild

Ich werd jetzt noch versuchen das ganze in die Textdatei einzupflegen und mich in dem Fall das es funktioniert oder eben nicht nochmal hier melden :) Schonmal danke soweit an alle!

EDIT:

Jetzt klappt es schonmal mit den Einträgen in die Textdatei. Leider noch ein bisschen wirr:

;Tue May 24 17:44:56 2016;
;Tue May 24 17:44:56 2016;
+022.807;Tue May 24 17:44:56 2016;
;Tue May 24 17:44:57 2016;
;Tue May 24 17:44:57 2016;
;Tue May 24 17:44:57 2016;
+022.806;Tue May 24 17:44:57 2016;
;Tue May 24 17:44:57 2016;
;Tue May 24 17:44:57 2016;
+022.806;Tue May 24 17:44:57 2016;
;Tue May 24 17:44:57 2016;
;Tue May 24 17:44:57 2016;
+022.806;Tue May 24 17:44:57 2016;

Code: Alles auswählen

import time
import serial

port = serial.Serial("/dev/ttyS0", 115200, timeout=1) #oeffnet den serial port S0

RefTemp = open("RefTemp.dat", "w") 	#erstellt eine .dat-Datei im Modus "write"
RefTemp.close()						#schliesst die .dat-Datei

try:
	RefTemp = open("RefTemp.dat", "w")
	while True:
		port.write('s\n')
		newline = port.readline()
		newline = newline[13:21]
		RefTemp.write('%s;%s;\n' % (newline, time.ctime()))
		print newline
		
except KeyboardInterrupt:
	pass
	RefTemp.close()
	
Grund dafür ist wohl die Zeile:

Code: Alles auswählen

RefTemp.write('%s;%s;\n' % (newline, time.ctime()))
Aber wenn ich eins der %s; lösche oder das , time.ctime() dann funktioniert das Skript nicht mehr.

Edit vom Edit?:

Wenn ich

Code: Alles auswählen

RefTemp.write('{0};{1};\n'.format(newline.rstrip(), time.ctime()))
nutze bekomm ich das gleiche Textdokument ausgegeben.
Benutzeravatar
kbr
User
Beiträge: 1510
Registriert: Mittwoch 15. Oktober 2008, 09:27

Regret hat geschrieben:Grund dafür ist wohl die Zeile:
RefTemp.write('%s;%s;\n' % (newline, time.ctime()))
Das ist gewiss nicht der Grund. Eher wohl das fehlende "time.sleep()", das Du nicht eingebaut hast. Womöglich braucht das Messgerät etwas Zeit, bis die nächsten Daten verfügbar sind.
Regret
User
Beiträge: 17
Registriert: Freitag 20. Mai 2016, 10:58

@ kbr: das ist natürlich ein guter Einwand. Ich werd es morgen wenn ich wieder bei der Arbeit bin mal mit einem time.sleep() probieren.

EDIT: Wie ist das denn eigentlich? Wenn ich beispielsweise eine sleeptime von 1sek angebe. Hab ich dann die Zeit die der Rechner braucht um die Schleife abzuarbeiten + 1Sekunde oder immer genau eine Sekunde zwischen den Messwertaufzeichnungen? Also ich mein die Zeit zum Durchlaufen der Schleife ist wohl im ersten Blick vernachlässigbar, aber wenn ich jetzt beispielsweise über eine Stunde aufnehme würde sich ja der Zeitstempel zwischen dem ersten und dem letzten Messwert um die Rechenzeit * 3600 verschieben oder?
BlackJack

@Regret: Zu dem `sleep()` kommt natürlich noch die Rechenzeit die der Rest der Schleife verbraucht dazu. Und dazu kommt auch noch das `sleep()` nicht genau ist, das kann mehr oder auch weniger Zeit verschlafen als man angibt. Es wird bei einer Stunde Laufzeit also sich aufaddierende Ungenauigkeiten geben. Selbst wenn Du berechnest wie viel Zeit gewartet werden muss bis zur nächsten Sekunde, wird das nicht genau sein. Zum einen weil Python als Bytecode interpretierende Hochsprache da rein spielt, zum anderen weil ein normales Betriebssystem keine harten Zusagen machen kann wie ein Echtzeitbetriebssystem. Wenn das also ”wirklich” Abstände von einer Sekunde sein sollen müsstest Du den `sleep()`-Wert entsprechend berechnen. Oder etwas wie das `sched`-Modul aus der Standardbibliothek zur Hilfe nehmen.
Regret
User
Beiträge: 17
Registriert: Freitag 20. Mai 2016, 10:58

@Blackjack: Okay dann schau ich morgen mal wenn ich dazu komme, dass die Textdatei nach meinen Vorstellungen formatiert ist und fang einfach mal mit dem Kalibrieren an. Wenn ich wirklich merklich in der Zeitspanne abtriffte behalt ich mal das 'sched'-Modul im Hinterkopf. Schonmal vielen Dank!

PS: Danke an alle trotz der vielen Anfängerfragen. Da ich mir die Python Programmierung mehr oder weniger neben meiner eigentlichen Arbeit versuche anzueignen blieb leider nicht sehr viel Zeit um mich wirklich mal eine vernünftige Zeit dran zu setzen. Ihr habt mir sehr geholfen :)
Antworten