串行端口未正确刷新
Serial Port not being flushed properly
我有一个 RPi (是的,我知道,也许有人认为这属于 RPi 站点,但我认为它通常与 Linux 有关,所以 Whosebug 是正确的地方) 我正在使用 Python3 和 pySerial 通过 MAX485 在一些 Arduino 之间进行通信。这或多或少是有效的,因为我发现我需要做一些奇怪的解决方法才能让一切正常工作"properly"。
如果我发送数据:
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)
令人惊讶的是它也有效。看来sleep "replaces" flush
命令。
为什么 pySerial 的缓冲区没有刷新?我知道,这 可能 是一种方法,但是 sleep
只会添加一段(通常)不必要的代码,导致整个代码等待(超过 500 行)并且这不是很好。
我已经在网上搜索过了,有人说是USB TTL适配器不支持flush
ing(这里不是这样,这个是板载的),其他人说可能是一个 Linux 内核错误,所以对我来说没有任何意义。
如果有人能解释为什么 flush 命令不起作用以及如何让它起作用(如果有办法的话),我和这个问题的未来访问者可能会非常高兴。
对于 pyserial,您可以设置 write_timeout 和 timeout(用于读取)参数,这将导致如果不设置为零,写入和读取操作将阻塞。
因此,如果您没有设置 write_timeout 参数,您的写操作的默认行为是阻塞,直到您的数据被发送到硬件。您不需要刷新数据,此功能将无事可做。
现在这取决于您的配置以及您用于通信的内核驱动程序。
如果您使用的是 RPi 的嵌入式 UART 端口,那么阻塞的写入操作应该等到所有数据真正推出。否则这可能是内核驱动程序配置错误或错误。
如果您使用的是像 FTDI 芯片这样的 USB 转 UART 转换器,那么在数据传输到芯片后,wrte 操作将被阻止 return。这意味着当写函数 returns.
时,数据可能没有被这个 ic 完全传输
如何处理这个问题(你需要一个示波器):
1. 检查断言 tx 引脚和传输开始之间的延迟。
2. 检查解除 tx 引脚和传输结束之间的延迟。
对于小数据包,提高波特率可能会有所帮助。
此外,您应该考虑使用硬件驱动的 tx 启用电路。
几个 FTDI 芯片可以配置为这样的行为(必须将适当的引脚连接到 tx 启用)。
你没有具体说明,但我认为假设你在半双工模式下使用 MAX485 是公平的。如果是这种情况,那么您尝试做的事情将无法可靠地工作。
问题是什么?
半双工通信使用 same pair of wires 双向传输。但是一次只有一端可以传输。因此,这需要某种方式来协调当前传输的人员。
我相信你已经很好地总结了这里的问题:
the Arduino receives the data and responds imediately, but because pySerial is somehow not ready yet, it becomes nothing back and there we have a lost packet.
不过不是PySerial没准备好,是你的MAX485,还有GPIO-23的状态。
一切都在时机
这是从 Moxa on Half Duplex 485, titled The Secrets of RS-485 Half-duplex Communication
的一篇优秀技术笔记中抄录的图片
此图显示您需要适时更改 GPIO-23(此图中的 MASTER-RTS)的状态,否则您的通信将失败。该技术说明值得完整阅读,我相信它很好地描述了您面临的挑战。
我该如何解决?
答案是,这取决于。您的问题可能是太早或太晚切换 GPIO-23。如果可能,最简单但性能最低的方法是让您的 Arduino 在响应之前等待一段时间。这将允许您 sleep()
确认您的数据包已完成传输,然后在 Arduino 开始响应之前切换 GPIO-23 的状态。
如果此解决方案不可行或不可取,那么您将需要研究其他驱动 GPIO-23 的方法。在 SW 中还有很多其他方法可以做到这一点,有些方法会比其他方法更好。但请注意,仅使用 python 代码切换 GPIO-23 线永远不会 100% 可靠。如果需要高可靠性,几乎肯定需要某种硬件辅助。
最后一点,除非需要 RS-485,否则您可以考虑使用 RS-422 或什至 RS-232 的全双工。
我有一个 RPi (是的,我知道,也许有人认为这属于 RPi 站点,但我认为它通常与 Linux 有关,所以 Whosebug 是正确的地方) 我正在使用 Python3 和 pySerial 通过 MAX485 在一些 Arduino 之间进行通信。这或多或少是有效的,因为我发现我需要做一些奇怪的解决方法才能让一切正常工作"properly"。
如果我发送数据:
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)
令人惊讶的是它也有效。看来sleep "replaces" flush
命令。
为什么 pySerial 的缓冲区没有刷新?我知道,这 可能 是一种方法,但是 sleep
只会添加一段(通常)不必要的代码,导致整个代码等待(超过 500 行)并且这不是很好。
我已经在网上搜索过了,有人说是USB TTL适配器不支持flush
ing(这里不是这样,这个是板载的),其他人说可能是一个 Linux 内核错误,所以对我来说没有任何意义。
如果有人能解释为什么 flush 命令不起作用以及如何让它起作用(如果有办法的话),我和这个问题的未来访问者可能会非常高兴。
对于 pyserial,您可以设置 write_timeout 和 timeout(用于读取)参数,这将导致如果不设置为零,写入和读取操作将阻塞。
因此,如果您没有设置 write_timeout 参数,您的写操作的默认行为是阻塞,直到您的数据被发送到硬件。您不需要刷新数据,此功能将无事可做。
现在这取决于您的配置以及您用于通信的内核驱动程序。
如果您使用的是 RPi 的嵌入式 UART 端口,那么阻塞的写入操作应该等到所有数据真正推出。否则这可能是内核驱动程序配置错误或错误。
如果您使用的是像 FTDI 芯片这样的 USB 转 UART 转换器,那么在数据传输到芯片后,wrte 操作将被阻止 return。这意味着当写函数 returns.
时,数据可能没有被这个 ic 完全传输如何处理这个问题(你需要一个示波器): 1. 检查断言 tx 引脚和传输开始之间的延迟。 2. 检查解除 tx 引脚和传输结束之间的延迟。
对于小数据包,提高波特率可能会有所帮助。
此外,您应该考虑使用硬件驱动的 tx 启用电路。 几个 FTDI 芯片可以配置为这样的行为(必须将适当的引脚连接到 tx 启用)。
你没有具体说明,但我认为假设你在半双工模式下使用 MAX485 是公平的。如果是这种情况,那么您尝试做的事情将无法可靠地工作。
问题是什么?
半双工通信使用 same pair of wires 双向传输。但是一次只有一端可以传输。因此,这需要某种方式来协调当前传输的人员。
我相信你已经很好地总结了这里的问题:
the Arduino receives the data and responds imediately, but because pySerial is somehow not ready yet, it becomes nothing back and there we have a lost packet.
不过不是PySerial没准备好,是你的MAX485,还有GPIO-23的状态。
一切都在时机
这是从 Moxa on Half Duplex 485, titled The Secrets of RS-485 Half-duplex Communication
的一篇优秀技术笔记中抄录的图片此图显示您需要适时更改 GPIO-23(此图中的 MASTER-RTS)的状态,否则您的通信将失败。该技术说明值得完整阅读,我相信它很好地描述了您面临的挑战。
我该如何解决?
答案是,这取决于。您的问题可能是太早或太晚切换 GPIO-23。如果可能,最简单但性能最低的方法是让您的 Arduino 在响应之前等待一段时间。这将允许您 sleep()
确认您的数据包已完成传输,然后在 Arduino 开始响应之前切换 GPIO-23 的状态。
如果此解决方案不可行或不可取,那么您将需要研究其他驱动 GPIO-23 的方法。在 SW 中还有很多其他方法可以做到这一点,有些方法会比其他方法更好。但请注意,仅使用 python 代码切换 GPIO-23 线永远不会 100% 可靠。如果需要高可靠性,几乎肯定需要某种硬件辅助。
最后一点,除非需要 RS-485,否则您可以考虑使用 RS-422 或什至 RS-232 的全双工。