web-dev-qa-db-fra.com

Boucle de lecture non bloquante PySerial

Je lis des données en série comme ceci:

connected = False
port = 'COM4'
baud = 9600

ser = serial.Serial(port, baud, timeout=0)

while not connected:
    #serin = ser.read()
    connected = True

    while True:
        print("test")
        reading = ser.readline().decode()

Le problème est que cela empêche toute exécution, y compris le framework web bottle py. Ajouter sleep() ne vous aidera pas.

Changer "While True" "en" While ser.readline (): "n'imprime pas" test ", ce qui est étrange, car cela fonctionnait dans Python 2.7. Des idées sur ce qui pourrait ne pas être correct?

Idéalement, je ne devrais être capable de lire des données série que si elles sont disponibles. Les données sont envoyées toutes les 1 000 ms.

24
DominicM

Mettez-le dans un fil séparé, par exemple:

import threading
import serial

connected = False
port = 'COM4'
baud = 9600

serial_port = serial.Serial(port, baud, timeout=0)

def handle_data(data):
    print(data)

def read_from_port(ser):
    while not connected:
        #serin = ser.read()
        connected = True

        while True:
           print("test")
           reading = ser.readline().decode()
           handle_data(reading)

thread = threading.Thread(target=read_from_port, args=(serial_port,))
thread.start()

http://docs.python.org/3/library/threading

38
Fredrik Håård

L'utilisation d'un thread séparé est totalement inutile. Faites simplement ceci pour votre boucle while infinie à la place (testé en Python 3.2.3):

import serial
import time # Optional (if using time.sleep() below)

while (True):
    # NB: for PySerial v3.0 or later, use property `in_waiting` instead of function `inWaiting()` below!
    if (ser.inWaiting()>0): #if incoming bytes are waiting to be read from the serial input buffer
        data_str = ser.read(ser.inWaiting()).decode('ascii') #read the bytes and convert from binary array to ASCII
        print(data_str, end='') #print the incoming string without putting a new-line ('\n') automatically after every print()
    #Put the rest of your code you want here
    time.sleep(0.01) # Optional: sleep 10 ms (0.01 sec) once per loop to let other threads on your PC run during this time. 

De cette façon, vous ne lisez et n'imprimez que s'il y a quelque chose. Vous avez dit: "Idéalement, je devrais pouvoir lire les données série uniquement lorsqu'elles sont disponibles." C'est exactement ce que le code ci-dessus fait. Si rien n’est disponible pour la lecture, il passe au reste de votre code dans la boucle while. Totalement non bloquant.

(Cette réponse a été posté et débogué ici: Lecture non bloquante de Python 3 avec pySerial (Impossible d'obtenir la propriété "in_waiting" de pySerial) )

documentation pySerial: http://pyserial.readthedocs.io/en/latest/pyserial_api.html

METTRE À JOUR: 

Note sur le multi-threading:

Même si la lecture de données série, comme indiqué ci-dessus, not ne nécessite pas l'utilisation de plusieurs threads, la lecture au clavier d'une manière non bloquante ne. Par conséquent, pour obtenir une lecture d’entrée au clavier non bloquante, j’ai écrit cette réponse: Comment lire une entrée au clavier? .

29
Gabriel Staples

Utilisez un événement piloté par une horloge pour tester et lire le port série . Exemple non testé:

import threading
class serialreading():
    def __init__(self):
        self.active = True
        self.test() 
    def test(self):
        n_in =comport.in_waiting()
        if n_in> 0:
            self.data = self.data + comport.read(size=n_in)
    if len(self.data) > 0: 
        print(self.data)
        self.data=""
    if self.active:
        threading.Timer(1, test).start()  # start new timer of 1 second
    def stop(self):
        self.active = False
0
William Kuipers