Interrupting a for loop while receiving data from a serial port

倖福魔咒の 提交于 2020-01-03 06:27:11

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!