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');  
}

最初に 'a' を Arduino に送信すると、ARDuino は 'b' で応答する必要があります。しかし、Arduinoのポートを読み取ると、「」しか受信しません。

「b」ではなく「」を受け取る理由を知っている人はいますか? 御時間ありがとうございます。

4

3 に答える 3

4

更新: 回答については、この回答の下部を参照してください。TL;DR:ポートを開いた、ボーレート (およびおそらく他のすべての設定)を設定しました。

これは QSerialPort の Windows 実装のバグだと思います。原因はまだ特定できていませんが、以下の症状があります。

  1. Arduino (私の場合は Uno。Leonardo は非常に異なる動作をする可能性があります) に ASCII デモをロードします。Arduino のプラグを抜き差しします。TX ライトが点灯しないことに注意してください。

  2. Putty または Arduino シリアル ポート モニターを使用して接続します。これにより Arduino がリセットされ、ASCII テーブルが出力されます。TX ライトは、予想どおり継続的に点灯しています。

  3. Arduino を抜き差しし、今度は QSerialPort プログラムで接続します。今回は、ポートが正常に開かれているにもかかわらず、TX ライトが点灯したり、readyRead()トリガーされたりすることはありません。また、デフォルトでは QSerialPort は DTR を変更しないため、Arduino はリセットされないことに注意してください。QSerialPort::setDataTerminalReady(false);その後、10ms 間一時停止してから設定するとtrue、 Arduino は期待どおりリセットされますが、それでも送信されません。

  4. データを継続的に送信する Arduino プログラムがある場合 (ASCII の例では停止)、パテでポートを開いて送信を開始しケーブルを抜かずに QSerialPort で開くと動作することに注意してください。ただし、ケーブルを抜き差しするとすぐに、再び機能しなくなります。

これにより、パテがarduinoに必要なシリアルポートオプションを設定し、ケーブルを再接続するとリセットされるのではないかと思われます。QSerialPort は明らかにこの値を変更しません。

私が知る限り、パテが使用する設定は次のとおりです。

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に接続されていないと思わせる変更されていない値の1つである必要があると思います。DCBのドキュメントから、私はfTxContinueOnXoff.

わかりました、これらの設定を読み取り、何が変化するかを確認するための小さなプログラムを作成します。

更新 1

さて、私は自分のプログラムを書き、次の発見をしました。パテと私の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 メソッドの動作も変更します。ポート検出はもう使用しません。それは壊れた概念であり、誰もそれに依存したことはほとんどありません. 誰かがそれを行っていたとしても、とにかく問題が発生し、不必要に騒々しい警告が表示されます。

もう 1 つのオプションも、この動作をオプションでデフォルトとして保持することを検討していましたが、それでは 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 に答える