线缓冲串行输入 [英] Line buffered serial input

查看:102
本文介绍了线缓冲串行输入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个串口设备,我正在尝试读取输入。我发了一个字符串ID \r,它返回ID XX \r(其中\r是ASCII回车符,十六进制0x0d)。

I have a serial device that I'm trying to read input from. I sent it a string "ID\r", and it returns "ID XX\r" (where \r is an ASCII carriage return, hex 0x0d).

由于不再支持serial.readline上的eol选项,我使用TextIOWrapper从串口读取并一次返回一行。

Since the eol option on serial.readline is no longer supported, I'm using TextIOWrapper to read from the serial port and return a line at a time.

My问题是,它不会在看到回车符时立即返回我的字符串,而是等到我打开串口时设置的超时时间的两倍。我希望它在读取整行后立即返回字符串,因为我可能有数百个命令发送到设备,我不想每次等待超时。如果我将超时设置为0,那么我根本就没有输出(可能是因为我的脚本在设备有机会输出任何内容之前停止等待),如果我将超时设置为None,脚本将永远阻塞。

My problem is that instead of returning my string as soon as it sees the carriage return, it's waiting until the twice the timeout I set when I opened the serial port. I'd like it to return the string immediately as soon as it reads an entire line since I may have hundreds of these commands to send to the device and I don't want to wait for the timeout each time. If I set timeout to 0, then I get no output at all (presumably because my script stops waiting before the device has a chance to output anything), and if I set the timeout to None, the script blocks forever.

这是一个简单的测试脚本:

Here's a simple test script:

import serial
import io
import time

ser = serial.Serial("/dev/ttyUSB0", baudrate=9600,
                    bytesize=8, parity='N', stopbits=1,
                    xonxoff=0, rtscts=1, timeout=5)

sio = io.TextIOWrapper(io.BufferedRWPair(ser, ser),
                       newline=None)


sio.write(unicode("ID\r"))
sio.flush()

print "reading..."

x = sio.readline()

print len(x)
print x

脚本总是需要10秒钟才能显示读取,直到它打印出从串口读取的ID XX字符串。

The script always takes 10 seconds from the time it says "reading" until it prints the "ID XX" string that it read from the serial port.

我确定那个神奇的人e正在输出回车,因为我用strace来观察读数:

I'm certain that the device is outputting the carriage return, as I've used strace to watch the reads:

select(4, [3], [], [], {5, 0})          = 1 (in [3], left {4, 991704})
read(3, "I", 8192)                      = 1
select(4, [3], [], [], {5, 0})          = 1 (in [3], left {4, 999267})
read(3, "D", 8191)                      = 1
select(4, [3], [], [], {5, 0})          = 1 (in [3], left {4, 999420})
read(3, " ", 8190)                      = 1
select(4, [3], [], [], {5, 0})          = 1 (in [3], left {4, 999321})
read(3, "X", 8189)                      = 1
select(4, [3], [], [], {5, 0})          = 1 (in [3], left {4, 999355})
read(3, "X", 8188)                      = 1
select(4, [3], [], [], {5, 0})          = 1 (in [3], left {4, 999171})
read(3, "\r", 8187)                     = 1
select(4, [3], [], [], {5, 0})          = 0 (Timeout)
select(4, [3], [], [], {5, 0})          = 0 (Timeout)

您可以看到2个select()超时,它们提供10秒延迟,但您也可以清楚地看到正在读取回车符。我已经尝试将newline参数设置为'None'和''(它应该自动允许\ r,\ n和\\\\ n),以及'\ r',但结果相同每次。

You can see the 2 select() timeouts that give the 10 second delay, but you can also clearly see the carriage return being read. I've tried setting the newline parameter to 'None' and '' (which should automatically allow \r, \n, and \r\n), and to '\r', but with the same result each time.

我也尝试将BufferedRWPair()调用中的buffer_size设置为'1'以防止缓冲输入,但这没有任何区别。

I've also tried setting the buffer_size in the BufferedRWPair() call to '1' to keep it from buffering input, but that made no difference.

我知道我做错了什么?

如果我不能让这个工作,我的下一步将使用serial.read()一次读取一个字符并进行自己的行缓冲,但我想先尝试用textiowrapper正确的方式。

If I can't get this working, my next step will be to use serial.read() to read a character at a time and do my own line buffering, but I wanted to try to do it the "right" way with textiowrapper first.

推荐答案

今天浪费了几个小时。原来, io.BufferedReader 读取,直到它填充了缓冲区,然后将缓冲区传递给 io.TextIOWrapper 。默认缓冲区大小为8192,因此根据您的设备,这可能需要一段时间。

Wasted a few hours on this today. It turned out that io.BufferedReader reads until it has filled its buffer and then passes the buffer to io.TextIOWrapper. The default buffer size is 8192, so depending on your device this might take a while.

正确的示例代码应为:

# buffer size is 1 byte, so directly passed to TextIOWrapper
sio = io.TextIOWrapper(io.BufferedRWPair(ser, ser, 1), encoding='ascii')
print sio.readline()[:-1]

这篇关于线缓冲串行输入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆