问题
How can I make my program interrupt an already running for loop when it receives the "K" character from a serial port ?
The code is :
import serial
from time import sleep
ser = serial.Serial(port='/dev/ttyUSB0',baudrate=9600,parity=serial.PARITY_NONE,stopbits=serial.STOPBITS_ONE,bytesize=serial.EIGHTBITS,timeout=0)
while 1:
for line in ser.read(1):
input+=chr(line)
if input == 'S':
for x in range (1 , 10): # this is the loop i want to break
print(x)
sleep(1)
if input == 'K':
print('K received -> BREAK')
break
print("Finished")
That way the program prints 'K received -> BREAK' after the for loop finished.
回答1:
You can't, since it is not already running.
Your program won't read another char from the input until the for x in range (1, 10)
loop has finished executing.
Imagine the input is 'SK'
. Your program will read the 'S'
character and execute the loop. In each iteration, sleep
stops the whole thread, not just the for loop. So your program will stop 9 times for at least one second each time before processing the next character, 'K'
, when it will break from the for line in ser.read(1)
loop (Also, note that this loop will always run for one iteration only, because ser.read(1)
only reads one byte).
If I understand correctly, you want to run a possibly long task after receiving a certain character from the serial input, and stop the running task if you receive another character. In order to do this, you should run your task in a separate thread.
You'd probably want to encapsulate your task in a class that manages the thread, but the simplest way to do this that I can think of is writing a function for your task and executing it in a Thread. You can use a threading.Event
to tell the task to stop when you receive the stop character in your main thread.
import serial
import threading
from time import sleep
ser = serial.Serial(port='/dev/ttyUSB0',baudrate=9600,parity=serial.PARITY_NONE,stopbits=serial.STOPBITS_ONE,bytesize=serial.EIGHTBITS,timeout=0)
thread = None
stop_task = threading.Event()
def do_task():
for i in xrange(10):
if stop_task.is_set():
break
print(i)
sleep(1)
while True:
byte = ser.read(1): # No need for a loop here, read(1) returns a length 1 string
character = chr(byte) # I'm not familiar with the serial module, but I think this isn't needed
if character == 'S':
# We check that we are not executing the task already, and if so we handle it accordingly
if thread:
print('Error: a task is already running!')
continue
# Start the task in a thread
stop_task.clear()
thread = threading.Thread(target=do_task)
thread.start()
elif character == 'K':
print('K received -> BREAK FROM TASK')
if thread:
stop_task.set()
thread = None
Keep in mind that this will only work for one task at a time only and that in general you should make sure that any thread you start finishes (in this example it is pretty clear they will finish eventually after setting the event, but more complex executions may get the thread stuck in an infinite loop).
It's a small example, but I hope it helps you get in the right direction.
来源:https://stackoverflow.com/questions/24618802/interrupting-a-for-loop-while-receiving-data-from-a-serial-port