serielle Schnittstelle / wechsel von Python 2 zu 3 geht nicht

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
kussji
User
Beiträge: 78
Registriert: Mittwoch 16. Mai 2018, 09:58

Hallo finden meinen Fehler nicht. Auch werde ich im Netz nicht wirklich fündig.

Ich lese eine serielle Schnittstelle mit Python 2.7.15 aus. Funktioniert prima 8)
Nun will ich den selben Code in Python 3.6.5 laufen lassen. Ohne Erfolg! :roll: (Python unter Windows)
Die Zeile "data = serport.read(Length+4)" am Ende wird anscheindend nie durchlaufen.

Habe pyserial mit pip3 installiert. Die Schnittstelle an und für sich läuft. Aber mit dem spezifischen Code geht es nicht.
Ich denke es liegt irgendwie an der Variable "Frameheader" unicode / formatierung oder sowas...
Wenn ich auskommentierte "Zeile # print(byte_in)" "ausführe", werden die seriellen Daten in der Konsole gezeigt.

Danke schon mal...

Code: Alles auswählen

Header = b'\xb5\x62'
Class = b'\x01'
ID = b'\x14'
Frameheader = Header + Class + ID
Length = 36
#open data port
serport = serial.Serial('COM4', 9600)

#search special message from data port
while True:
    while True:
        for ch in Frameheader:
            byte_in = serport.read(1)
            # print(byte_in)
            if byte_in != ch:
                break
        else:
            # signature found
            break
    # read data
    data = serport.read(Length+4) #Payload-Length + 4
Sirius3
User
Beiträge: 18267
Registriert: Sonntag 21. Oktober 2012, 17:20

Der unterschied ist, dass Python2 beim Iterieren über Bytestrings Strings der Länge 1 liefert, Python3 dagegen ints, Dein read aber immer Bytestrings der Länge 1 liefert.

Ganz optimal ist der Code noch nicht. Konstanten werden KOMPLETT_GROSS geschrieben. Wenn B5 62 B5 kommt, dann wird das zweite B5 verworfen, obwohl es der Anfang des Headers sein könnte. Am besten benutzt Du eine Deque:

Code: Alles auswählen

from collections import deque
HEADER = b'\xb5\x62'
CLASS = b'\x01'
ID = b'\x14'
FRAME_HEADER = deque(HEADER + CLASS + ID)
FRAME_LENGTH = 36

serport = serial.Serial('COM4', 9600)

while True:
    header = deque(maxlen=len(FRAME_HEADER))
    while header != FRAME_HEADER:
        header.extend(serport.read(1))
    data = serport.read(FRAME_LENGTH + 4
Das Funktioniert dann auch unter beiden Pythonversionen.
kussji
User
Beiträge: 78
Registriert: Mittwoch 16. Mai 2018, 09:58

Hallo Sirius3
Vielen Dank für die Hilfe. Habe es grade mal schnell getestet - sieht gut aus. (zumindes in Python 2.7 - in Python 3.6 happerts dann am CRC-check)
Was ich nicht ganz verstanden habe, auch mit "deque" hab ich das Problem noch, dass allenfalls der Header nicht korrekt erkannt wird oder ist das Problem damit "erschlagen" muss mal noch das deque studieren.

Habe nicht den ganzen Code gepostet...
ich habe auch einen CRC-Check drin. Der entschärft ja das Problem mit "falschen" Header aber wenn es konstant diese B5 62 B5 gäbe würde ja das auch nichts nützen.

Nun vielleicht kannst Du mir noch einen weiteren tollen Tip geben, zum nicht funktionierenden CRC-Code in Python3.6 (google sonst später selber nochmal danach :-)
Das passt nicht: ck_a = ck_a + ord(i)
Fehlermeldung: ord() expected string of length 1, but int found

Danke!

Code: Alles auswählen

#calculate checksum of frame
def checksum(msg):
    ck_a = 0
    ck_b = 0
    for i in msg:
        ck_a = ck_a + ord(i)
        ck_b = ck_b + ck_a
    ck_a = ck_a % 256
    ck_b = ck_b % 256
    return ck_a, ck_b
Sirius3
User
Beiträge: 18267
Registriert: Sonntag 21. Oktober 2012, 17:20

Der Grund des Fehlers ist der selbe, wie schon oben beschrieben. Einfach das ord weglassen.
kussji
User
Beiträge: 78
Registriert: Mittwoch 16. Mai 2018, 09:58

... so einfach kann das sein :)
Danke!
kussji
User
Beiträge: 78
Registriert: Mittwoch 16. Mai 2018, 09:58

... hm weiss nicht ob ich das jetzt hier posten soll oder einen neuen thread? ... versuchs mal hier.

habe schöne Tutorials zu Python Grundlagen sowie auch zu tkinter aber die Kombination davon ist ehrer rar.

Wie kann ich jetzt meine Daten, welche in einer Endlosschleife eingelesen werden geschickt in einer GUI anzeigen? Am Ende wird die GUI ziemlich umfangreich sein. Anzeige, Datenbankzugriffe, Einstellungen etc.

Ist da mit "thread" zu arbeiten der richtige Weg? Einer z.B. für Daten einlesen ein anderer für GUI-Anzeigen/Bedienung
Danke
Sirius3
User
Beiträge: 18267
Registriert: Sonntag 21. Oktober 2012, 17:20

Da das Abfragen von Koordinaten ja seine Zeit braucht, und man nicht währendessen die GUI stehen soll, beleibt eigentlich nur die Verwendung von Nebenläufigkeit (Threads). In der GUI muß man dann regelmäßig nach neuen Daten schauen. Kommunikation findet, wie meist, am einfachsten über Queues statt.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Statt threads nutze ich createfilhandler. Damit bekommst du einen Rueckruf im GUI-Thread wenn Daten an der Seriellen Schnittstelle anliegen.
Antworten