【问题标题】:Problems with serial communication and queues串行通信和队列问题
【发布时间】:2014-08-21 09:35:18
【问题描述】:

我在创建多进程串行记录器时遇到了一些问题。 计划:有一个单独的进程从串口读取,将数据放入队列。主进程在一段时间后读取整个队列并处理数据。

但我不确定这是否是正确的方法,因为有时数据的顺序不正确。它适用于慢速通信。

我必须锁定什么吗?!有没有更聪明的方法来做到这一点?

import time
import serial
from multiprocessing import Process, Queue

def myProcess(q):
    with serial.Serial("COM2", 115200, 8, "E", 1, timeout=None) as ser:
        while True:
            q.put("%02X" % ser.read(1)[0])



if __name__=='__main__':
    try:
        q = Queue()
        p = Process(target=myProcess, args=(q,))
        p.daemon = True
        p.start()
        data = []
        while True:
            print(q.qsize()) #!debug
            while not q.empty(): #get all data from queue
                data.append(q.get())
            #proc_data(data) #data processing
            time.sleep(1)    #emulate data processing
            del data[:]      #clear buffer
    except KeyboardInterrupt:
        print("clean-up") #!debug
        p.join()

更新: 我尝试了另一个基于线程的版本(参见下面的代码),但效果/问题相同。结转工作正常,但结转和新数据“之间”的一个字节总是消失 -> 当 main 读取队列时,脚本会错过这个字节?!

import time, serial, threading, queue

def read_port(q):
    with serial.Serial("COM2", 19200, 8, "E", 1, timeout=None) as ser:
        while t.is_alive():
            q.put("%02X" % ser.read(1)[0])

def proc_data(data, crc):
    #processing data here
    carry = data[len(data)/2:] #DEBUG: emulate result (return last half of data)
    return carry

if __name__=='__main__':
    try:
        q = queue.Queue()
        t = threading.Thread(target=read_port, args=(q,))
        t.daemon = True
        t.start()

        data = []
        while True:
            try:
                while True:
                    data.append(q.get_nowait()) #get all data from queue
            except queue.Empty:
                pass
            print(data) #DEBUG: show carry-over + new data
            data = proc_data(data) #process data and store carry-over
            print(data) #DEBUG: show new carry-over
            time.sleep(1) #DEBUG: emulate processing time

    except KeyboardInterrupt:
        print("clean-up")
        t.join(0)

【问题讨论】:

    标签: python multithreading serial-port queue multiprocessing


    【解决方案1】:

    考虑下面的代码。

    1) 两个进程是兄弟;父级只是设置它们然后等待 control-C 中断一切

    2) 一个 proc 将原始字节放入共享队列

    3) 第一个数据字节的其他 proc 块。当它获得第一个字节时,它会抓取其余数据,以十六进制输出,然后继续。

    4) 父进程只是设置其他进程然后使用signal.pause() 等待中断

    请注意,使用multiprocessingqsize()(可能还有empty())函数是不可靠的——因此上面的代码将可靠地获取您的数据。

    来源

    import signal, time
    import serial
    from multiprocessing import Process, Queue
    
    def read_port(q):
        with serial.Serial("COM2", 115200, 8, "E", 1, timeout=None) as ser:
            while True:
                q.put( ser.read(1)[0] )
    
    def show_data(q):
        while True:
            # block for first byte of data
            data = [ q.get() ]
            # consume more data if available
            try:
                while True:
                    data.append( q.get_nowait() )
            except Queue.Empty:
                pass
            print 'got:', ":".join("{:02x}".format(ord(c)) for c in data)
    
    if __name__=='__main__':
        try:
            q = Queue()
            Process(target=read_port, args=(q,)).start()
            Process(target=show_data, args=(q,)).start()
    
            signal.pause()          # wait for interrupt
    
        except KeyboardInterrupt:
            print("clean-up") #!debug
    

    【讨论】:

    • 您好,感谢您的评论。我让它在 Windows 上运行,但最后我得到了同样的效果。我进一步研究了这个问题;查看我更新的问题。
    • @Julian 所以有时候输入数据是乱序的?
    • “乱序”是什么意思?该脚本检查传入数据的有效性(在上面的代码 sn-p 中省略)。无效部分单独显示,我可以看到缺少一个字节。当其他进程/线程正在读取队列时,它正在丢失(或未从串行线路读取)。当我调高波特率时,可能会丢失更多字节。如何保证从串行线路读取每个字节?当其他进程/线程正在读取队列时,我尝试通过不将输入数据直接放入队列来缓冲输入数据。但它也不起作用。
    猜你喜欢
    • 2012-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-01
    • 2017-11-15
    相关资源
    最近更新 更多