Schleife durchbrechen

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
erdmulch
User
Beiträge: 230
Registriert: Samstag 17. Juli 2010, 19:50

Hallo zusammen,

ich will Daten aus meiner Seriellen Schnittstelle auslesen was auch ganz gut funktioniert.
Die Daten werden in die Variable "line" geschrieben.
die Daten werden kontinuierlich angefordert. Nun wollte ich die Daten Splitten, kann mir jemand sagen wie man die Daten nun aus der Schleife bekommt damit ich eine Neue Funktion schreiben kann zum splitten?

vielen Dank im voraus

Code: Alles auswählen

#!/usr/bin/env python
#-*- coding: utf-8 -*-

from datetime import datetime
import os
import serial
import time

def save():
    ser = serial.Serial('/dev/rfcomm0')       
    try:
        while True:
            line = ser.readline()
            print line
    finally:
        ser.close()
save()

lunar

@erdmulch "break". Steht übrigens bestimmt auch im Tutorial…

PS: Man bricht Schleifen „ab“, nicht „durch”…
BlackJack

@erdmulch: Ich glaube Du willst die Schleife nicht abbrechen, sondern eher eine Funktion in der Schleife aufrufen. Oder Du suchst die ``yield``-Anweisung, womit sich die Schleife unterbrechen lässt bis der nächste Wert angefordert wird.

Die ``while``-Schleife und das `readline()` sind überflüssig weil man direkt über die Zeilen in einer ``for``-Schleife iterieren kann. Zusammen mit `contextlib.closing()` bekommt man die Funktion wie sie jetzt ist zu einem Dreizeiler zusammengestrichen:

Code: Alles auswählen

from contextlib import closing
from serial import Serial


def save(port='/dev/rfcomm0'):
    with closing(Serial(port)) as lines:
        for line in lines:
            print line
Der Name passt nicht zur Funktion.
erdmulch
User
Beiträge: 230
Registriert: Samstag 17. Juli 2010, 19:50

Hallo nochmals,

ich habe es nun nach dem Beispiel von BlackJack gemacht.
allerdings hab ich das gleiche Problem. das Programm läuft irgendwie in einer Endlos schleife.

nun wollte ich das ganze in einem Thread laufen lassen. Aber wie es aussieht kann nicht einmal in Thread das programm für 10sec unterbrechen und dann wieder neustarten der erste Thread läuft einfach durch.

oder mach ich was grundlegendes falsch?

Code: Alles auswählen

from contextlib import closing
from serial import Serial


def save(port='/dev/rfcomm0'):
    with closing(Serial(port)) as lines:
        for line in lines:
            print line

#Hauptprogramm
thread.start_new_thread(save(),)
time.sleep(10)
thread.start_new_thread(save(),)
time.sleep(10)

Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

@erdmulch: Threads sind ja dafür da, dass sie neben dem Hauptprogramm weiterlaufen,
warum sollte sich der Thread dafür interessieren, dass das Hauptprogramm 10s lang wartet?
Und warum startest Du einen zweiten Thread, der auch von der gleichen Seriellen Schnittstelle
liest?
Soll die Schleife beendet werden, sollte schon irgendwo ein break auftauchen.

Übrigens: thread solltest Du nicht benutzen, sondern statt dessen threading.
BlackJack

@erdmulch: Die Schleife da sagt „lies alle Zeilen die über die serielle Schnittstelle rein kommen”. Das ist letztendlich eine Endlosschleife solange die Gegenseite die Verbindung nicht schliesst.

Neben den Anmerkungen von Sirius3 machst Du auch in der Tat etwas grundlegend falsch, denn Du startest nie einen Thread. Dazu hättest Du die *Funktion* übergeben müssen. Du rufst sie aber auf und übergibst ihren Rückgabewert — allerdings wird da nie einer zurück gegeben, weil die Funktion wie weiter oben angemerkt, „endlos” läuft. Und falls die Gegenseite die Kommunikation abbricht, würde die Funktion `None` zurückgeben, was nichts ist was man aufrufen kann, also kann damit auch kein Thread gestartet werden.
erdmulch
User
Beiträge: 230
Registriert: Samstag 17. Juli 2010, 19:50

mit dem Thread habt ihr recht, das habe ich nun getestet und funktioniert auch.
Aber mein Problem ist leider noch nicht behoben.
von der Seriellen Schnittstelle kommen Wertte die durch Semikolon getrennt sind.
Ich würde nun gerne die Einzelnen werte in eine Datenbank scpeichern, da es sich um Float und um int sowie charr handelt.

mein gedanke war nun wie im Code beschrieben mit Split die einzelnen Teile herauszusplitten:

Code: Alles auswählen

def save(port='/dev/rfcomm0'):
    with closing(Serial(port)) as lines:
        for line in lines:
            print line
            teilstring1 = line.split(";")[0]
            teilstring2 = line.split(";")[1]
            teilstring3 = line.split(";")[2]
            teilstring4 = line.split(";")[3]
dann erscheint aber folgende Meldung:
IndexError: list index out of range

jetzt habe ich mir gedacht, damit es vielleicht mit der Seriellen Schnittstelle zu tun hat, dass diese vielleicht auch einen leeren String sendet.

also wollte ich eine if Anweisung machen:
if line == None:
print "mache nichts"
else:
print "Code wird ausgeführt"

leider springt er Nie in "mache nichts" darum gehe ich davon aus dass der String nie leer ist.

muss ich sonst noch was beachten wenn es um die Verarbeitung von seriellen Daten geht?
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

None ist nicht gleich leerem String "", ist nicht gleich leerer Zeile "\n".
Du solltest auch nicht 4mal split aufrufen, sondern nur einmal und dann prüfen, ob
der String in so viele Teile gesplittet wurde, wie Du erwartest.
erdmulch
User
Beiträge: 230
Registriert: Samstag 17. Juli 2010, 19:50

wurde es denn eine Möglichkeit geben, das Programm solange in einer schleife laufen lassen, bis nicht mehr "index out of range" kommt?
ich hab nämlich mein Programm nun mehrmals nacheinander gestartet und es funktioniert hin und wieder. Ich denke je nachdem wie die Daten aus der Seriellen Schnittstelle kommen.
Oder kann mir vielleicht jemand sagen wie man nach einer leeren Zeile sucht?
BlackJack

@erdmulch: Eine (wirklich) leere Zeichenkette enthält keine Zeichen, hat die also die Länge 0, und ist als Wahrheitswert gesehen „Falsch”. Das sollte einem eigentlich jedes Grundlagentutorial vermitteln. Eine leere *Zeile* besteht in der Regel aus einem Zeilenende-Zeichen. Es gibt auf Zeichenketten eine Methode die sogenannte „whitespace”-Zeichen an beiden Enden der Zeichenkette entfernt. Wenn die Zeichenkette also nur solche Zeichen enthält, dann gibt diese Methode eine (wirklich) leere Zeichenkette zurück. Was „whitespace”-Zeichen sind und wie die erwähnte Methode heisst, lasse ich jetzt mal als Aufgabe im Raum stehen.

Auf einen `IndexError` kannst Du wie auf jede andere Ausnahme auch reagieren. Oder wie von Sirius3 vorgeschlagen *vorher* prüfen ob genug Teile beim Aufteilen der Zeichenkette entstanden sind.

Wobei ich jetzt den Verdacht habe, dass das besser gehen sollte als zu „raten”. Aufgrund der bisherigen Beiträge vermute ich mal, da ist irgend ein (Mess)gerät (Wetterstation?) an der seriellen Schnittstelle angeschlossen? Solche Geräte sendennicht irgendwie zufällig formatierte Daten sondern kommunizieren mit einem spezifizierten Protokoll. Und *das* sollte man auch geziehlt verarbeiten. Denn vielleicht kommen in dem Protokoll auch noch andere Zeilen mit Semikolons vor und Werten die *nicht* in die Datenbank wandern sollen.
Antworten