在串口接收数据时中断for循环

0 投票
1 回答
5542 浏览
提问于 2025-04-18 12:24

我想知道怎么让我的程序在从串口接收到“K”这个字符时,能够中断正在运行的for循环。

代码如下:

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")

这样的话,程序会在for循环结束后打印出'K received -> BREAK'。

1 个回答

0

你不能这样做,因为程序还没有在运行。

你的程序在执行完for x in range (1, 10)这个循环之前,不会再从输入中读取其他字符。

想象一下输入是'SK'。你的程序会先读取'S'这个字符,然后执行循环。在每次循环中,sleep会让整个线程暂停,而不仅仅是暂停这个循环。所以你的程序会停下9次,每次至少停一秒,才会处理下一个字符'K',这时它会跳出for line in ser.read(1)这个循环(另外要注意,这个循环只会执行一次,因为ser.read(1)只读取一个字节)。

如果我理解得没错,你是想在从串口输入接收到某个字符后,运行一个可能比较长的任务,并且如果接收到另一个字符,就停止这个正在运行的任务。

为了做到这一点,你应该把任务放在一个单独的线程中运行。

你可能想把任务封装在一个管理线程的类里,但我能想到的最简单的方法是为你的任务写一个函数,然后在一个线程中执行它。你可以使用threading.Event来告诉任务在主线程接收到停止字符时停止。

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

请记住,这样做一次只能处理一个任务,而且一般来说,你应该确保你启动的任何线程都能完成(在这个例子中,很明显它们最终会在设置事件后完成,但更复杂的执行可能会让线程陷入无限循环)。

这是一个小例子,但我希望它能帮助你朝着正确的方向前进。

撰写回答