0

I'm having trouble reading the response from a RS232 OBD2 interface via pySerial. The code successfully enters the data, as I can see from a direct parallel terminal screen, but fails to read and print the response, regardless of the response.

Right now the code is not capable of printing the response in neither versions of Python. The code looks something like this :

from serial import * # I also tried using /from serial import Serial
import time
ser = Serial("/dev/rfcomm1", 38400, timeout=1)
#print ('Starting up, formatting responses')
#ser.write("ATZ\r"),
#ser.write("ATSP0\r"),
#ser.write("ATS1\r"),
#ser.write("ATL1\r"),
#ser.write("ATH1\r"),
#ser.write("ATF1\r")
#time.sleep(1)
#print ('We have lift-off !')
if ser.inWaiting() > 0:
    ser.flushInput()
#ser.timeout = 1.
time.sleep(1)
#print (raw_data)
ser.write("AT RV\r") #The response should be something like 13.5V, but nothing
ser.timeout = 1.
msg = ser.read(size=1024)
print msg
ser.close()

I left only the AT RV command because while I'm working on it I sent the text formatting commands to ease the job. Right now when I send it it just gives me a blank line (although the terminal which is running on the same machine displays the desired output)

There are no errors in the code, and the commands go through and are responded to by the interface, and I can see that in another live term, but nothing appears when running the Python code. What should I do ?

4

2 回答 2

4

你应该在写作之后阅读,而不是之前。

# before writing anything, ensure there is nothing in the buffer
if ser.inWaiting() > 0:
    ser.flushInput()

# set the timeout to something reasonable, e.g., 1 s
ser.timeout = 1.

# send the commands:
ser.write("ATZ\r")
# ...

# read the response, guess a length that is more than the message
msg = ser.read(1024)
print msg

# send more commands
# read more responses
# ...

这里的重点是无法知道何时收到响应。此代码在发送每个命令后等待一秒钟,除非在此期间到达的字节数超过 1024。还有更聪明的算法,但让我们先试试这个。

如果你想用串行线做一些更复杂的事情,看看pexpect模块。


调试python串口问题的一些想法

串行通信问题有时很难解决。pySerial是一个可靠的库,但是由于不同的平台有不同类型的串行API,所以有很多细节。由于 USB 转换器为游戏带来了额外的层,因此移除物理串行端口并没有变得更容易。蓝牙转换器更糟糕。

调试物理层的最佳方法是使用一些监视器硬件,将两个串行端口接入串行线路。这种嗅探器有助于将问题隔离到连接的任一端。不幸的是,这种嗅探器在需要时很少出现。

下一个最好的办法是短接串行线的 RD 和 TD(RXD,TXD)引脚。这样所有数据都会被回显。如果接收到发送的数据,则物理连接良好。需要注意的一件事是握手。如果您不知道自己在做什么,请禁用所有流控制(xon/xoff、rts/cts、dtr/dsr。如果另有指示,pySerial 会禁用所有这些。

在上述问题的情况下,物理连接是可以的,因为另一个软件证明数据是由另一个设备发送和理解的。(看到发送了一些东西并不能证明什么,因为该信息没有经过物理层,但是看到另一个设备产生的东西被接收到证明物理连接是好的。)

现在我们知道数据进入了操作系统,但是 pySerial 看不到它。或者我们的代码仍然有点糟糕(不,它不应该,但是......)

让我们怀疑自己的代码并尝试其他人的代码。这可以从命令提示符运行:

python -m serial.tools.miniterm /dev/rfcomm1 38400

现在我们有了一个终端,可以用来手动发送/接收对方的数据。如果该行为可以重复(发送成功,数据已接收到系统,但未显示在终端上),那么问题可能不在我们的代码中。

然后下一步是尝试:

sudo python -m serial.tools.miniterm /dev/rfcomm1 38400

原则上,访问权限问题会导致我们可以接收但不能发送的情况。但是测试这一点并没有坏处,因为奇怪的权利会导致奇怪的问题。

pySerial有一个方便的功能readline,应该从串行线一次读取一行。这通常是想要的。但是,在这种特定情况下,这些行似乎以\r而不是结束\n。代码中的其他地方可能会重复相同的内容,因此需要特别注意特殊数据。(从这个意义上说,简单的“超时读取”是安全的,但速度很慢。)这在pySerial 2.6:在 readline() 中指定行尾进行了讨论

同样的问题困扰着所有终端程序。对于 pySerial miniterm,请参阅其文档(命令行选项--cr)。

如果有超时,它们可以而且应该更长以用于调试目的。一秒超时可以更改为十秒超时,以确保其他设备有足够的时间来回答。

于 2014-06-22T23:45:45.480 回答
0

我遇到了完全相同的问题,通过 Python 2 IDLE 在 IDLE 屏幕上没有显示任何结果,但结果被重定向到终端上的 picocom 活动。我需要捕获结果,因为我的目标是读取传入的 SMS。以下代码解决了我的问题,我还不知道原因,正在分析中。

import time
import serial

modem1 = serial.Serial("/dev/ttyUSB3",baudrate=115200,timeout=0,rtscts=0,xonxoff=0)
def sendat1(cmd):
    if cmd == 'res' : modem1.write('Z'); return
    if cmd == 'out' : modem1.write(chr(26)); return
    modem1.write('AT+'+cmd+'\r')
    time.sleep(3)
    obu = str(modem1.inWaiting())
    msg = modem1.read(32798)
    print(obu+':\n'+msg)
    return

try:
    if modem1.inWaiting()>0: modem1.flushInput()
    sendat1('res')
    sendat1('CMGF=1')
    sendat1('CMGL')
    sendat1('out')
finally:
    modem1.close()
于 2016-03-12T05:26:32.383 回答