串口未正确刷新

时间:2017-04-28 13:20:38

标签: linux python-3.x raspberry-pi pyserial

我有一个RPi (是的,我知道,也许有人认为这属于RPi网站,但我认为它与Linux有关,所以StackOverflow是正确的地方)我使用Python3和pySerial通过MAX485在一些Arduinos之间进行通信。这或多或少都有效,因为我发现我需要做一些奇怪的解决方法,以使一切正常运行"正确"。

如果我发送数据:

GPIO.output(23, 1) # Pulling transmit pin high to send
comport.write("Some data".encode()) # Writing data
comport.flush() # Flushing the buffer
GPIO.output(23, 0) # Pulling pin down to receive

Arduino接收数据并立即响应,但由于pySerial尚未准备就绪,因此它没有回复,我们丢失了数据包。

但是,如果我这样试试:

GPIO.output(23, 1)
comport.write("Some data".encode())
time.sleep(.001) # Add some delay of only 1ms
comport.flush()
GPIO.output(23, 0)

然后数据被发送并被接收。这引出了一个问题:flush命令是否正常工作?我试了一下:

GPIO.output(23, 1)
comport.write("Some data".encode())
time.sleep(.001) # Add some delay
# -- No flush --
GPIO.output(23, 0)

令人惊讶的是它也有效。似乎睡眠"取代" flush命令。

为什么pySerial的缓冲区没有刷新?我知道,这个可能是一种方法,但sleep只添加一个(通常)不必要的代码,导致整个代码等待(超过500行),这不是&#那太好了。

我已经在互联网上搜索过,有些人说它是USB TTL适配器,它不支持flush(这里不是这种情况,这个是在机上),其他人说可能是一个Linux内核错误,所以对我来说没有任何意义。

如果有人能够解释为什么冲洗命令不起作用以及如何使其工作(如果有其他方式),我和这个问题的每个未来访问者都会非常高兴。

2 个答案:

答案 0 :(得分:3)

您并不具体,但我认为假设您在半双工模式下使用MAX485是公平的。如果是这种情况,那么您尝试做的事情将无法可靠地运作。

有什么问题?

半双工通信使用same pair of wires向任一方向传输。但是一次只能传输一端。因此,这需要某种方式来协调当前正在传输的人。

enter image description here

我相信你对这个问题有一个很好的总结:

  

Arduino接收数据并立即响应,但由于pySerial尚未准备就绪,因此它没有回复,我们丢失了数据包。

然而,没有准备好PySerial,它是你的MAX485,以及GPIO-23的状态。

一切都在时间

这张照片来自Moxa关于Half Duplex 485的精彩技术说明,标题为The Secrets of RS-485 Half-duplex Communication

enter image description here

此图显示您需要在恰当的时刻更改GPIO-23(此图中的MASTER-RTS)的状态,否则您的通信将失败。技术说明值得全面阅读,我相信很好地描述了您所面临的挑战。

如何解决?

答案是,取决于。您的问题可能是过早或过晚切换GPIO-23。如果可能的话,最简单但性能最差的方法是让你的Arduino等待一段时间才能响应。这将允许您sleep()一点确保您的数据包已完成传输,然后在Arduino开始响应之前切换GPIO-23的状态。

如果此解决方案不可行或不可取,那么您需要研究其他驱动GPIO-23的方法。在SW中还有很多其他方法可以做到这一点,有些方法比其他方法更好。但请注意,只使用python代码切换GPIO-23线路,这绝不会100%可靠。如果需要高可靠性,几乎肯定需要某种类型的硬件辅助。

最后要注意的是,除非需要RS-485,否则您可以考虑全双工,使用RS-422,甚至RS-232。

答案 1 :(得分:1)

对于pyserial,您可以设置 write_timeout timeout (用于读取)参数,如果未设置为零则会导致写入和读取操作将阻塞。

因此,如果未设置 write_timeout 参数,则写入操作的默认行为将被阻止,直到将数据发送到硬件。您不需要刷新数据,此功能无关。

现在它取决于您的配置如何以及您用于通信的内核驱动程序。

如果您使用的是RPi的嵌入式UART端口,那么阻塞的写操作应该等到所有数据都被推出。否则,这可能是一个配置错误的内核驱动程序或错误。

如果您正在使用像FTDI芯片那样的USB转UART转换器,那么在数据传输到芯片后,阻塞的wirte操作将返回。这意味着当写入函数返回时,此ic可能无法完全传输数据。

如何处理这个问题(你需要一台示波器): 1.检查断言tx引脚和开始传输之间的延迟。 2.检查解除tx引脚和传输结束之间的延迟。

对于小数据包,可能有助于提高波特率。

此外,您应该考虑使用硬件驱动的tx启用电路。 可以将多个FTDI芯片配置为这样(适当的引脚必须连接到tx使能)。