Ich verwende ein Skript in Python, um Daten von einem PIC-Mikrocontroller über die serielle Schnittstelle mit 2 Mbit/s zu erfassen.
Der PIC arbeitet mit perfektem Timing bei 2 Mbit/s, auch der serielle FTDI-USB-Anschluss funktioniert mit 2 Mbit/s hervorragend (beide mit einem Oszilloskop überprüft).
Ich sende Nachrichten (Größe von ca. 15 Zeichen) ca. 100-150x pro Sekunde und die Anzahl erhöht sich (um zu überprüfen, ob ich Nachrichten verloren habe und so weiter)
Auf meinem Laptop läuft Xubuntu als virtuelle Maschine, ich kann die serielle Schnittstelle über PuTTY und über mein Skript (Python 2.7 und pySerial) lesen
Das Problem:
Hier ist der Code (ich habe den größten Teil des Codes weggelassen, aber die Schleife ist dieselbe):
ser = serial.Serial('/dev/ttyUSB0', 2000000, timeout=2, xonxoff=False, rtscts=False, dsrdtr=False) #Tried with and without the last 3 parameters, and also at 1Mbps, same happens.
ser.flushInput()
ser.flushOutput()
While True:
data_raw = ser.readline()
print(data_raw)
Weiß jemand, warum pySerial so viel Zeit braucht, um von der seriellen Schnittstelle bis zum Ende der Leitung zu lesen? Irgendeine Hilfe?
Ich möchte das in Echtzeit haben.
Vielen Dank
Sie können inWaiting()
verwenden, um die Anzahl der in der Eingabewarteschlange verfügbaren Bytes abzurufen.
Dann können Sie read()
verwenden, um die Bytes zu lesen.
While True:
bytesToRead = ser.inWaiting()
ser.read(bytesToRead)
Warum nicht readline()
in diesem Fall von Docs verwenden:
Read a line which is terminated with end-of-line (eol) character (\n by default) or until timeout.
Sie warten bei jeder Messung auf das Timeout, da es auf eol wartet. der serielle Eingang Q bleibt gleich, es ist nur eine Menge Zeit, um zum "Ende" des Puffers zu gelangen.
Sie müssen das Timeout auf "Keine" setzen, wenn Sie die serielle Schnittstelle öffnen:
ser = serial.Serial(**bco_port**, timeout=None, baudrate=115000, xonxoff=False, rtscts=False, dsrdtr=False)
Dies ist ein blockierender Befehl. Sie warten also, bis Sie Daten erhalten, die am Ende eine neue Zeile (\ n oder\r\n) enthalten: line = ser.readline ()
Sobald Sie die Daten haben, wird es so schnell wie möglich zurück.
Von das Handbuch :
Mögliche Werte für den Parameter Timeout:… x Timeout auf x Sekunden einstellen
und
readlines (sizehint = None, eol = '\ n') Lies eine Liste von Zeilen bis zum Timeout. sizehint wird ignoriert und ist nur aus Gründen der API-Kompatibilität mit integrierten Dateiobjekten vorhanden.
Beachten Sie, dass diese Funktion nur bei einer Zeitüberschreitung zurückgegeben wird.
Ihr readlines
wird also höchstens alle 2 Sekunden zurückkehren. Verwenden Sie read()
wie von Tim vorgeschlagen.
Eine sehr gute Lösung hierfür findet sich hier :
Hier ist eine Klasse, die als Wrapper für ein pyseriales Objekt dient. Sie können Zeilen ohne 100% CPU lesen. Es enthält keine Timeout-Logik. Wenn eine Zeitüberschreitung auftritt, gibt
self.s.read(i)
eine leere Zeichenfolge zurück, und Sie möchten möglicherweise eine Ausnahme auslösen, um die Zeitüberschreitung anzuzeigen.
Es soll laut Autor auch schnell sein:
Der folgende Code gibt mir 790 kB/Sek., Während das Ersetzen des Codes durch die Readline-Methode von Pyserial nur 170 kB/Sek. Ergibt.
class ReadLine:
def __init__(self, s):
self.buf = bytearray()
self.s = s
def readline(self):
i = self.buf.find(b"\n")
if i >= 0:
r = self.buf[:i+1]
self.buf = self.buf[i+1:]
return r
while True:
i = max(1, min(2048, self.s.in_waiting))
data = self.s.read(i)
i = data.find(b"\n")
if i >= 0:
r = self.buf + data[:i+1]
self.buf[0:] = data[i+1:]
return r
else:
self.buf.extend(data)
ser = serial.Serial('COM7', 9600)
rl = ReadLine(ser)
while True:
print(rl.readline())