为啥 QtSerialPort 在运行超过一次或两次后不会读取?

Posted

技术标签:

【中文标题】为啥 QtSerialPort 在运行超过一次或两次后不会读取?【英文标题】:Why would QtSerialPort not read after running more than once or twice?为什么 QtSerialPort 在运行超过一次或两次后不会读取? 【发布时间】:2021-03-24 21:07:43 【问题描述】:

我只是想在一个值表示开始后从 QtSerialPort 连接读取值到 arduino。我可以在 python 代码中有一个最大计数,但这并不会改变它在多次运行 python 脚本后没有从 arduino 读取 println 的结果。起初它会打印出“开始”、“阅读”和“V”,如果我很快再次运行它,可能会再次打印出来。但在那之后,它在打印出“开始”后停止阅读。这是python代码。

from PyQt5 import QtCore, QtSerialPort
import sys 

app = QtCore.QCoreApplication([]) 

serial_port = QtSerialPort.QSerialPort('COM3') 

serial_port.open(QtCore.QIODevice.ReadWrite) 

def handle_ready_read(): 
    print('to read')
    while serial_port.canReadLine():
        serialrd = serial_port.readLine().data().decode().strip()
        print(serialrd)
        serial_port.close()
        app.quit() 

serial_port.readyRead.connect(handle_ready_read) 

serial_port.write(bytes([100])) 
print('start')
sys.exit(app.exec_())

这是arduino代码。

int measured;
int counter = 0;
int maxnum = 10;

void setup()

Serial.begin(9600);


void loop()

  if(Serial.available() > 0)
  
    while(counter < maxnum)
    

        Serial.println("V");
        counter++;
        delay(100);

    
  


任何可以解释为什么它不会再次阅读的想法都会很有用。我每次都必须拔下并重新插入 arduino 才能读取它,但最好避免这样做。我还注意到我无法在 pyserial 连接之后运行 PyQt5 串行端口连接,首先断开 arduino,但我可以在 PyQt5 串行端口连接之后运行 pyserial,尽管我不知道该问题是否与某种相关。

编辑:我在handle_ready_read中添加了'to read'打印语句,第一次运行时有时会打印两次,所以虽然有要读取的内容,但readline并不总是可以读取,所以我添加了到最后去handle_ready_read吧,

    while serial_port.bytesAvailable(): 
        dataByte = serial_port.readLineData(1)
        print(dataByte)
        serial_port.close()
        app.quit()

因此有时会在读取时打印出b'V',而不仅仅是V。但一两次尝试后仍然无法读取。

编辑 2:我添加了一个计时器和函数来检查字节是否被写入,

attempts = []
def check_bytes_written():    
    print('bytes to write' , serial_port.bytesToWrite())
    attempts.append(1)
    if len(attempts) > 10:
        serial_port.close()
        timer.stop()
        app.quit()

timer = QtCore.QTimer()
timer.setInterval(50) 
timer.timeout.connect(check_bytes_written)
timer.start()

这不会在第一次或第二次尝试时打印出任何内容,然后在以后的尝试中说“要写入 0 的字节”,即使端口和应用程序已结束,仍然没有打印出任何形式的“V”,除非我仍然断开 arduino 并将其重新插入(至少现在不需要每次都重新启动内核)。我还在 arduino 中添加了代码,以检查写入的值是否可用于更改输出引脚的电压,它可以工作并且每次运行 python 脚本时都会更改输出电压,是否读取了“V” .所以我稍微改变了问题标题和之前的文字,因为它并没有真正崩溃或冻结,它只是没有阅读 arduino 正在打印的内容。

编辑 3:我将if(Serial.available() &gt; 0) int counter = 0; 放在 arduino 代码中,而不是在开始时初始化计数器,python 代码将在重新运行脚本时从 arduino 读取(尽管 V 周围有一堆空格,或者只是从 readlineData 部分打印 b'\x00',但这可能是另一个问题,可以通过在 readyRead 之前放置 serial_port.clear() 来清除它,但是仍然会打印 V 或 b'V')。所以看起来python脚本没有重新启动arduino代码,也许这是qserialport如何关闭或打开的问题(如DTR或RTS),不像pyserial那样?更多讨论here。

编辑 4:如果我添加(在 arduino 代码的开头初始化计数器时,如最初所示,撤消最后一次编辑)

serial_port.setDataTerminalReady(1)
serial_port.setDataTerminalReady(0)
serial_port.setDataTerminalReady(1)

serial_port.open 语句并运行它之后,它仍然不会从串行读取中打印(没有断开arduino 并首先重新连接它),但是如果我评论DTR 设置,那么V 是再次运行时按预期打印,无需断开连接,但随后又回到不打印V。仅使用 serial_port.setDataTerminalReady(1) 也会产生相同的效果,每隔一段时间将其评论输入/输出。

编辑 5:我发现(一旦它至少正常运行一次,首先拔掉插头或使用编辑 4 中的方法),如果我放了

serial_port.setDataTerminalReady(0)
serial_port.setDataTerminalReady(1)
serial_port.setDataTerminalReady(0)

就在serial_port.close() 之前,它可以再次运行多次并打印出“V”。我猜它正在将 DTR 重置为 0。如果有解释为什么需要发生这种情况,那就太好了。

【问题讨论】:

【参考方案1】:

你的函数逻辑是否正确缩进?

在我看来,你读了一行就立即关闭串行端口并退出你的应用程序。

也许你打算:

def handle_ready_read(): 
    while serial_port.canReadLine():
        serialrd = serial_port.readLine().data().decode().strip()
        print(serialrd)
    # Close serial port and quit app when no more data is available
    serial_port.close()
    app.quit() 

【讨论】:

这给出了相同的结果,它仍然卡住了。在任何一种情况下,它都只读取一行。我知道 arduino 的 println 比读取的要多,但它适用于 pyserial。 如果我读到了arduino发送的最大行数,然后退出,它仍然卡住,这主要是为了举一个更简单的例子。 您可以尝试打印serial_port.baudRate() 吗?我想知道 Qt 是否无法正确设置它 默认是 9600,所以设置它不会改变任何东西。它按原样工作一两次。 pyserial 可能就是这种情况,但 Qt 文档建议 QSerialPort 尝试查找端口配置本身。所以也许它可能弄错了。

以上是关于为啥 QtSerialPort 在运行超过一次或两次后不会读取?的主要内容,如果未能解决你的问题,请参考以下文章

ip命令

代码结构

Java - 如何一次或从一个文件夹中依次运行几个 shell/bat 文件

计算机网络中,tcp连接中快速重传为啥要三个重复ack,而不是两个或一个??

在串行端口(QtSerialPort)读取传入字节的连续流

TeeChart ActiveX 7 问题