向设备发送串行消息,直到它在线

Posted

技术标签:

【中文标题】向设备发送串行消息,直到它在线【英文标题】:Send serial message to device until it is online 【发布时间】:2017-12-04 23:12:19 【问题描述】:

我正在尝试通过串行接口更新控制器的固件。为此,我必须向控制器发送一条重启消息(那里没问题),然后在它启动的那一刻发送另一条消息(字符'w'),以便它可以在写入模式下启动。这可以通过 minicom 实用程序轻松完成,方法是在设备重新启动时连续按 w。

我想改用 python 代码来实现这个功能,但我不知道如何发送消息,直到设备启动而不抛出异常(因为设备未连接)。

这是我尝试过的,但它不起作用(使用 pyserial):

def send_w(serial_port, baud_rate):
    msgw = "w_"
    ans = ""
    ser = serial.Serial(port=serial_port, baudrate=baud_rate,timeout = 10)
    ser.write(msgw)
    ans = ser.read(24)
    ser.close()
    print(ans)
    return ans

def set_firmware_version(serial_port, baud_rate):
    s = ""
    try:
        with serial.Serial(serial_port,baud_rate,timeout=1) as ser:
            msgr = "%reset "+sk+"_"
            ser.write(msgr)
            ser.close()
            print("reset")
    except (IOError) as e:
        print("Error in: set_firmware_version")
        print(e)
        return s
    time.sleep(1)
    send_w(serial_port, baud_rate)

set_firmware_version(sp,br)

这会产生以下错误:

serial.serialutil.SerialException: device reports readiness to read but returned no data (device disconnected or multiple access on port?)

我也尝试在一个短超时的循环中发送消息,但遇到了同样的问题。如果找不到设备,有什么方法可以连续发送消息并忽略异常?

任何帮助将不胜感激。

完整追溯:

Traceback (most recent call last):
  File "mc_config.py", line 69, in <module>
    set_firmware_version(sp,br)
  File "mc_config.py", line 64, in set_firmware_version
    send_w(serial_port, baud_rate)
  File "mc_config.py", line 46, in send_w
    ans = ser.read(24)
  File "/home/avidbots/.local/lib/python2.7/site-packages/serial/serialposix.py", line 501, in read
    'device reports readiness to read but returned no data '
serial.serialutil.SerialException: device reports readiness to read but returned no data (device disconnected or multiple access on port?)

(我使用的是 ubuntu 16.04 和 python 3)

【问题讨论】:

【参考方案1】:

如果您将异常代码放入try,然后使用except serial.serialutil.SerialException ... 块捕获异常会怎样?

显然,提交w 的时间窗口很长(否则“按 w”方法通常不会起作用。)那么,您的要求将是仅重试绝对必要的代码部分发送w,这样您就可以足够快地发送它以“捕获”处于启动状态的系统。由于回溯显示异常发生在 send_w 中,因此您可以添加 try/except 块和 while 循环围绕现在 set_firmware_version 末尾的一行。

不仅仅是这样:

send_w(serial_port, baud_rate)

这样的事情可能会解决问题:

while True:
  try:
    send_w(serial_port, baud_rate)
    break
  except serial.serialutil.SerialException:
    pass # retry

您可能需要更改导入以公开该异常,仅供参考。而且您可能需要考虑是否捕获了太多可能的异常——异常也可能代表其他不应重试的错误。您可能还需要在那里添加一小段睡眠时间 - 这本质上是一个繁忙的等待循环 (https://en.wikipedia.org/wiki/Busy_waiting)。

【讨论】:

谢谢,非常相似的工作。我在调用函数之前删除了睡眠,将 send_w 的超时时间缩短到 0.1,并在循环而不是 break 语句上设置了一个结束条件。通过异常是关键!

以上是关于向设备发送串行消息,直到它在线的主要内容,如果未能解决你的问题,请参考以下文章

从串行端口发送十六进制数据的问题

串行通信写入

如何从 tkinter 滑块/刻度重复输出,以便我可以通过串行向另一台设备发送恒定的数字流?

如何强制串行端口写入方法在发送数据之前等待线路清除?

在Qt中关闭串口之前发送串口消息

Linux上的串口和USB设备有什么区别?