python - proyectos - PySerial sin bloqueo de lectura
leer datos de arduino con python (3)
Ponlo en un hilo aparte, por ejemplo:
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()
Estoy leyendo datos en serie como este:
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()
El problema es que impide que se ejecute cualquier otra cosa, incluido el framework web de bottle py. Agregar sleep()
no ayudará.
Cambiar "while True" "a" while ser.readline (): "no imprime" test ", lo cual es extraño ya que funcionó en Python 2.7. ¿Alguna idea de qué podría estar mal?
Idealmente, debería poder leer datos en serie solo cuando estén disponibles. Los datos se envían cada 1.000 ms.
Usar un hilo separado es totalmente innecesario. Simplemente haga esto para su bucle infinito while (probado en Python 3.2.3):
import serial
import time # Optional (if using time.sleep() below)
while (True):
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 esta manera solo leerás e imprimirás si hay algo allí. Usted dijo: "Idealmente, debería poder leer datos en serie solo cuando estén disponibles". Esto es exactamente lo que hace el código anterior. Si no hay nada disponible para leer, salta al resto de su código en el bucle while. Totalmente no bloqueante.
(Esta respuesta originalmente publicada y depurada aquí: Python 3 no bloquean la lectura con pySerial (No se puede hacer que la propiedad "in_waiting" de pySerial funcione) )
documentación de pySerial: http://pyserial.readthedocs.io/en/latest/pyserial_api.html
ACTUALIZAR:
- 27 de octubre de 2018: agregue el modo de suspensión para permitir que se ejecuten otras hebras
- Documentación: https://docs.python.org/3/library/time.html#time.sleep
- Gracias a @ RufusV2 por mencionar este punto en los comentarios.
Nota sobre multihilo:
Aunque la lectura de datos en serie, como se muestra arriba, no requiere el uso de múltiples subprocesos, la lectura de la entrada del teclado de manera no bloqueante. Por lo tanto, para lograr una lectura de entrada de teclado sin bloqueo, he escrito esta respuesta: .com/questions/5404068/how-to-read-keyboard-input/… .
Utilice un evento controlado por temporizador para probar y leer el puerto serie. Ejemplo no probado:
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