Python 重置打开的串行端口

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/36869394/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 18:28:01  来源:igfitidea点击:

Reset an open serial port

pythonserial-portpyserial

提问by Pablo Flores

I am reading data from a serial port, sent by an arduino.

我正在从 arduino 发送的串行端口读取数据。

I have two files, which I use separately to write some code and try differents things. In one of them, I read the data and I draw it using a matplotlib figure. After I finish using it, it remains connected to my computer and sending data. So, what i need to do is to "reset" the port. This is, close the opened port and open it again, and stop it from sending data so I can use the arduino to try some modifications in the code of this file.

我有两个文件,我分别使用它们来编写一些代码并尝试不同的东西。在其中之一中,我读取数据并使用 matplotlib 图绘制它。在我用完它后,它仍然连接到我的电脑并发送数据。所以,我需要做的是“重置”端口。这就是,关闭打开的端口并再次打开它,并阻止它发送数据,以便我可以使用 arduino 尝试对该文件的代码进行一些修改。

So to accomplish this, i mean, to reset the port, i created another file and wrote this code:

因此,为了实现这一点,我的意思是,要重置端口,我创建了另一个文件并编写了以下代码:

import serial

print "Opening port"

try:
  serial_port = serial.Serial("com4", 9600)
  print "Port is open"

except serial.SerialException:
  serial.Serial("com4", 9600).close()
  print "Port is closed"
  serial_port = serial.Serial("com4",9600)
  print "Port is open again"

print "Ready to use"

But this code does not seems to work.The port is still connected and sending data. So, it means that I can not close the port with my code,and then reopen it again.

但是这段代码似乎不起作用。端口仍然连接并发送数据。所以,这意味着我不能用我的代码关闭端口,然后再重新打开它。

What am i doing wrong? How can I stop the arduino from sending data? Or how can I reset thw arduino, maybe?

我究竟做错了什么?如何阻止arduino发送数据?或者我怎样才能重置 thw arduino,也许?

Hope you can help me.

希望您能够帮助我。

----- EDIT -----

- - - 编辑 - - -

I accomplish to identify the real problem that i am having, and it is not what i thought. The problem was not that the port was open despite that i use the closefunction that Pyserial have. The real thing is that the port is closing as I want, but the device (the arduino) is still sending data. So, i changed the code to reproduce the situation.

我完成了确定我遇到的真正问题,而不是我想的那样。问题不在于端口是开放的,尽管我使用了closePyserial的功能。实际情况是端口正在按照我的意愿关闭,但设备(arduino)仍在发送数据。因此,我更改了代码以重现这种情况。

This is the code:

这是代码:

print "Abriendo puerto"

ser = serial

try:
  ser = serial.Serial("com4", 9600, timeout = 1)
  serial_port = "Open"
  print "The port %s is available" %ser

except serial.serialutil.SerialException:
  print "The port is at use"

  ser.close()
  ser.open()

while ser.read():
  print "Sending data"

ser.setBreak(True)
time.sleep(0.2)

ser.sendBreak(duration = 0.02)
time.sleep(0.2)

ser.close()
time.sleep(0.2)
print "The port is closed"

exit()

With this code, what i do is:

使用此代码,我要做的是:

1) I open the serial port

1)我打开串口

2) If the device is sending data, I print "Sending data"

2)如果设备正在发送数据,我打印“发送数据”

3) After 1 sec, I try to close the port and stop the device from sending data

3)1秒后,我尝试关闭端口并停止设备发送数据

I tried these last two thing with the closefunction to close the port, and reading the docs I tried with setBreakand sendBreakas you can see in the code above (i left them on purpose). But the device is still sending the data, which means that the code does not work.

我使用close关闭端口的功能尝试了最后两件事,并阅读了我尝试使用的文档setBreaksendBreak正如您在上面的代码中看到的那样(我故意留下它们)。但是设备仍在发送数据,这意味着代码不起作用。

So, is there a way to tell the arduino "stop sending data", or can i reset the device?

那么,有没有办法告诉arduino“停止发送数据”,或者我可以重置设备吗?

回答by Eric Nelson

I do a very similar thing, two ways with success.

我做了一个非常相似的事情,成功的两种方式。

The first way is to let the Arduino send data continuously. The problem here is when your python code wakes up and starts to read from the serial port, the Arduino might be anywhere in its procedures. The simple solution is to modify the Arduino code to send some kind of "restarting" line. All your python code needs to do in this case is wait for "restart", then read real data until it again sees "restart". I had noisy lines so my code read (and parsed) through multiple cycles to make sure it got good data.

第一种方法是让Arduino不断发送数据。这里的问题是当您的 Python 代码唤醒并开始从串行端口读取时,Arduino 可能位于其程序中的任何位置。简单的解决方案是修改 Arduino 代码以发送某种“重新启动”行。在这种情况下,您的所有 python 代码需要做的是等待“重启”,然后读取真实数据,直到再次看到“重启”。我有嘈杂的行,所以我的代码通过多个周期读取(和解析)以确保它获得良好的数据。

resetCount = 0;
while resetCount < 3:
    line = s.readline().rstrip("\r\n")
    if string.find(line, "restart") != -1 :
        resetCount += 1
    elif resetCount > 0 :
        fields = string.split(line, " ")
        dict[fields[0]] = fields

The second way is to implement a command-response protocol with the Arduino, wherein the Arduino sends data only when requested. In this case your python code sends a command to the Arduino ("RT" in the example below) and then reads data from the Arduino until it sees a "completed" line or it times out.

第二种方式是使用 Arduino 实现命令-响应协议,其中 Arduino 仅在请求时发送数据。在这种情况下,您的 Python 代码会向 Arduino(下例中的“RT”)发送一个命令,然后从 Arduino 读取数据,直到看到“已完成”行或超时。

        dict = {}
        regex = re.compile('28-[0-9A-Fa-f]{12}') # 28-000005eaa80e

        s = serial.Serial('/dev/ttyS0', 9600, timeout=5)
        s.write("RT\n");

        while True:
            line = s.readline().rstrip("\r\n")
            print line
            if string.find(line, "completed") != -1:
                break;

            fields = string.split(line)
            if (regex.match(fields[0]) != None and len(fields) == 4) :
                dict[fields[0]] = fields
        s.close()

回答by Peter Harrison

It is possible that when you close the port, data is still coming from the arduino and being buffered by the operating system. There is a short delay between your script calling close() and the device driver actually shutting stuff down.

当您关闭端口时,数据可能仍然来自 arduino 并被操作系统缓冲。在您的脚本调用 close() 和设备驱动程序实际关闭设备之间存在短暂的延迟。

An immediate re-open may allow the driver to carry on without resetting its buffer. This is the device driver buffer, not the one seen by the Python serial port instance.

立即重新打开可以允许驱动程序在不重置其缓冲区的情况下继续。这是设备驱动缓冲区,不是 Python 串口实例看到的缓冲区。

If you wait for at least a couple of seconds after the call to close() before you try to call open() then the behaviour should be as you hope.

如果在尝试调用 open() 之前调用 close() 后至少等待几秒钟,则行为应该如您所愿。

I have just spent most of the day working out that this is what had been preventing my code from working properly.

我刚刚花了一天的大部分时间来研究这就是阻止我的代码正常工作的原因。

回答by Perry

I think you have to do a serial_port.open() immediately after creation to actually open the port.

我认为您必须在创建后立即执行 serial_port.open() 才能实际打开端口。

It also looks like it just opens the port and exits if successful. Maybe I'm missing something here. I've never used pySerial, I'm just going by the docs.

它看起来也只是打开端口并在成功后退出。也许我在这里遗漏了一些东西。我从未使用过 pySerial,我只是按照文档进行操作。

回答by maxlazar

Try using the handle to close the port instead of invoking the constructor again. If you the port is open and you call serial.Serial("com4", 9600) it will attempt to re-open the port again and fail.

尝试使用句柄关闭端口而不是再次调用构造函数。如果您的端口是打开的并且您调用 serial.Serial("com4", 9600) 它将尝试再次重新打开端口并失败。

If serial_port was assigned successfully then serial_port.close() should close it.

如果 serial_port 分配成功,serial_port.close() 应该关闭它。