4

我有以下代码:

QSerialPort arduPort("COM5");
arduPort.setBaudRate(QSerialPort::Baud9600);
arduPort.setDataBits(QSerialPort::Data8);
arduPort.setParity(QSerialPort::NoParity);
arduPort.setStopBits(QSerialPort::OneStop);
arduPort.setFlowControl(QSerialPort::NoFlowControl);
arduPort.open(QSerialPort::ReadWrite);
cout<<arduPort.isReadable()<<endl;
cout<<arduPort.isWritable()<<endl;
arduPort.write("a");
QByteArray s=arduPort.readAll();

cout<<QString(s).toStdString()<<endl;

Arduino中的下一个代码:

int inByte = 0;

void setup()
{
    Serial.begin(9600);
    while(!Serial){;}
    int i=0;
}

void loop()
{
     if(Serial.read()=='a')
         Serial.write('b');  
}

首先,我向 Arduino 发送一个“a”,而 ARduino 必须以“b”响应。但是当我阅读 Arduino 的端口时,我只收到 ''。

任何人都知道为什么我收到''而不是'b'?谢谢你的时间。

4

3 回答 3

4

更新:请参阅此答案的底部以获取答案。TL;DR:您在打开端口设置了波特率(可能还有其他所有设置) 。

我相信这是 QSerialPort 的 Windows 实现中的一个错误。我还不能缩小原因,但我有以下症状:

  1. 使用 ASCII 演示加载 Arduino(在我的情况下为 Uno;Leonardo 的行为可能非常不同)。拔下并重新插入 Arduino。请注意,TX 灯不亮。

  2. 使用 Putty 或 Arduino 串行端口监视器连接到它。这会重置 Arduino,然后打印 ASCII 表。TX 灯按预期持续亮起。

  3. 拔下/重新插入 Arduino,这次使用 QSerialPort 程序连接到它。这一次,尽管端口打开正常,但 TX 灯永远不会亮起,readyRead()也永远不会被触发。另请注意,Arduino 未重置,因为默认情况下 QSerialPort 不会更改 DTR。如果你这样做了,QSerialPort::setDataTerminalReady(false);然后暂停 10 毫秒,然后设置它true它将按预期重置 Arduino,但它仍然不传输。

  4. 请注意,如果您有一个连续传输数据的 Arduino 程序(ASCII 示例停止),如果您使用 putty 打开端口使其开始传输,然后在不拔掉电缆的情况下使用 QSerialPort 打开它,它将起作用!但是,一旦您拔下/插入电缆,它就会再次停止工作。

这让我怀疑腻子正在设置一些 arduino 所需的串行端口选项,并在您重新插入电缆时重置。QSerialPort 显然不会改变这个值。

据我所知,这是 Putty 使用的设置:

dcb.fBinary = TRUE;
dcb.fDtrControl = DTR_CONTROL_ENABLE;
dcb.fDsrSensitivity = FALSE;
dcb.fTXContinueOnXoff = FALSE;
dcb.fOutX = FALSE;
dcb.fInX = FALSE;
dcb.fErrorChar = FALSE;
dcb.fNull = FALSE;
dcb.fRtsControl = RTS_CONTROL_ENABLE;
dcb.fAbortOnError = FALSE;
dcb.fOutxCtsFlow = FALSE;
dcb.fOutxDsrFlow = FALSE;
dcb.Parity = NOPARITY;
dcb.StopBits = ONESTOPBIT;
dcb.BaudRate = ...;
dcb.ByteSize = ...;

通过QSerialPort

dcb.fBinary = TRUE;
dcb.fDtrControl = unchanged!
dcb.fDsrSensitivity = unchanged!
dcb.fTXContinueOnXoff = unchanged!
dcb.fOutX = FALSE;
dcb.fInX = FALSE;
dcb.fErrorChar = FALSE;
dcb.fNull = FALSE;
dcb.fRtsControl = RTS_CONTROL_DISABLE;
dcb.fAbortOnError = FALSE;
dcb.fOutxCtsFlow = FALSE;
dcb.fOutxDsrFlow = unchanged!
dcb.Parity = NOPARITY;
dcb.StopBits = ONESTOPBIT;
dcb.BaudRate = ...;
dcb.ByteSize = ...;

所以我认为它一定是那些使 Arduino 认为它没有连接的不变值之一。从我怀疑的DCB 文档fTxContinueOnXoff中。

好的,我将编写一个小程序来读取这些设置并查看发生了什么变化。

更新 1

好的,我编写了我的程序并做出了以下发现。运行 putty 和我的 Qt 程序后的区别是:

  • 波特率:这不是 QT 设置的!!!!!!!!!事实证明,您只能在打开端口设置波特率。. 否则,当您第一次插入电缆时,它会保留为先前的值 0。
  • fDtrControl:Putty 设置为 1,Qt 设置为 0。
  • fOutX 和 fInX:两者都被 Putty 设置为 1,被 Qt 设置为 0。

在打开后移动我所有的set...()函数调用后,它工作得很好。我不必摆弄 DtrControl 或 Out/InX。(虽然我也手动将 DTR 设置为高。)

更新 2

在设置所有参数时,我认为将错误策略设置为“跳过”是个好主意。不要这样做!忽略它!否则,它会搞砸一切,并为您的所有通信增加奇怪的延迟。

于 2013-10-01T09:31:19.363 回答
4

在 Qt 5.2 之前,在打开之前设置端口是不太可能的。原因是原始设计对于该类来说太低级了,而该类是面向对象的。想了很久要不要改,最后还是决定改了。

我刚刚提交了一个更改,现在正在接受代码审查,这将使您的原始概念也可以工作。

在这里您可以找到详细信息:

可以在打开之前设置端口值

可以在此处阅读更改的摘要:

可以在打开之前设置端口值

此补丁还更改了 open 方法的行为。我们不再使用端口检测了。这是一个破碎的概念,而且几乎不可能有人依赖它。如果有人这样做,他们无论如何都会遇到麻烦,不必要地收到嘈杂的警告等等。

另一个选项也被认为可以选择将此行为保留为默认行为,但这会使 API 过于复杂而没有太多收益。

默认端口设置现在也是正常的 9600,8,N,1,并且没有流量控制。另请注意,如果任何设置失败,串口会在 open 方法中自动关闭。

请更新您的 Qt 版本(至少到 Qt 5.2),或者您可以自己向后移植更改。然后,可以编写此代码,实际上甚至建议:

QSerialPort arduPort("COM5");
arduPort.setBaudRate(QSerialPort::Baud9600);
arduPort.setDataBits(QSerialPort::Data8);
arduPort.setParity(QSerialPort::NoParity);
arduPort.setStopBits(QSerialPort::OneStop);
arduPort.setFlowControl(QSerialPort::NoFlowControl);
arduPort.open(QSerialPort::ReadWrite);
于 2014-03-03T07:39:29.133 回答
1

波特率:这不是 QT 设置的!!!!!!!!!事实证明,您只能在打开端口后设置波特率。否则,当您第一次插入电缆时,它会保留之前的值,即 0。

是的,它是真实的。但它已被修复并将在 Qt 5.3 中可用

fDtrControl:Putty 设置为 1,Qt 设置为 0。

不,Qt 在打开时不要触摸 DTR 信号。该信号只有在设置为 DTR_CONTROL_HANDSHAKE 时才会被清除。因为 QtSerialPort 不支持 DTR/DSR 流控制。因此,在任何情况下,您都可以通过 QSerialPort::setDataTerminalReady(bool) 来控制 DTR。

PS:我的意思是当前的 Qt 5.3 版本

fOutX 和 fInX:两者都被 Putty 设置为 1,被 Qt 设置为 0。

该标志仅在您使用 QSerialPort::Software 流控制 (Xon/Xoff) 时使用。但是您使用的是 QSerialPort::NoFlowControl (从您的代码片段中可以看出),所以,好吧。因此,请检查您是否也将 Putty 与“无”流控制一起使用。

在设置所有参数时,我认为将错误策略设置为“跳过”是个好主意。

请仅使用 QSerialPort::Ignore 策略(默认)。因为其他策略已被弃用(所有策略)并且将来会被删除。

升级版:

dcb.fRtsControl = RTS_CONTROL_ENABLE;

啊,您的 Arduino 似乎希望 RTS 信号默认启用。在这种情况下,您应该使用 QSerialPort::setRequestToSend(bool)。但只有在 QSerialPort::NoFlowControl 模式下才有可能。

即 RTS 在打开端口后始终处于 RTS_CONTROL_DISABLE 或 RTS_CONTROL_HANDSHAKE 中(取决于您的 FlowControl 设置, QSerialPort::setFlowControl() )。

于 2014-04-21T14:19:27.413 回答