我有以下代码:
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'?谢谢你的时间。
答案 0 :(得分:4)
更新:请参阅本答案的底部以获得答案。 TL; DR:您已经打开后设置了波特率(可能是所有其他设置)港口。
我认为这是QSerialPort的Windows实现中的一个错误。我还没有能够缩小原因,但我有以下症状:
使用ASCII演示加载Arduino(Uno在我的情况下; Leonardo可能表现得非常不同)。拔下并重新插上Arduino。请注意,TX灯不亮。
使用Putty或Arduino串口监视器连接到它。这将重置Arduino,然后打印ASCII表。 TX灯按预期连续亮起。
拔下/重新插入Arduino,这次使用QSerialPort程序连接到它。这次虽然打开了端口,但TX灯仍然没有亮起,readyRead()
永远不会被触发。另请注意,Arduino未重置,因为默认情况下QSerialPort不会更改DTR。如果您执行QSerialPort::setDataTerminalReady(false);
然后暂停10毫秒,则将其设置为true
将按预期重置Arduino,但仍然无法传输。
请注意,如果您有一个连续传输数据的Arduino程序(ASCII示例停止),如果您使用putty打开端口以便它开始传输并然后使用QSerialPort打开它拔掉电缆就可以了!但是,只要拔下/插上电缆,它就会再次停止工作。
这让我怀疑putty正在设置一些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 = ...;
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 documentation我怀疑fTxContinueOnXoff
。
好的我打算写一个小程序来阅读这些设置,看看有什么变化。
好的,我写了我的程序并做了以下发现。运行putty和我的Qt程序之后的差异是:
在打开后移动所有set...()
函数调用后,它完美运行。我没有必须摆弄DtrControl或Out / InX。 (虽然我也手动将DTR设置为高。)
在设置所有参数时,我认为将错误策略设置为“跳过”是个好主意。不要这样做!把它放在IGNORE上!否则它会搞乱一切,并为你的所有通信增加奇怪的延迟。
答案 1 :(得分:4)
在Qt 5.2之前,不可能在打开前设置端口。原因是原始设计对于类来说太低级了,而不是适当的面向对象。我一直在考虑是否要改变它,最后我真的决定这样做。
我刚刚提交了一项现在正在进行代码审核的更改,这也将使您的原始概念正常工作。
在这里您可以找到详细信息:
Make it possible to set the port values before opening
可以在此处阅读摘要以了解更改:
可以在打开前设置端口值
此修补程序还会更改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);
答案 2 :(得分:1)
BaudRate:这是因为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和&#34;无&#34;流量控制也是如此。
设置所有参数时,我认为这是一个好主意 将错误政策设置为&#39;跳过&#39;。
请仅使用QSerialPort :: Ignore策略(默认情况下)。因为其他政策已弃用(所有政策),将来也会被删除。
UPD:
dcb.fRtsControl = RTS_CONTROL_ENABLE;
啊,似乎你的Arduino期望默认情况下应启用RTS信号。在这种情况下,您应该使用QSerialPort :: setRequestToSend(bool)。但它只能在QSerialPort :: NoFlowControl模式下使用。
即。打开端口后,RTS始终位于RTS_CONTROL_DISABLE或RTS_CONTROL_HANDSHAKE中(取决于您的FlowControl设置,QSerialPort :: setFlowControl())。