Qt QSerialPort シリアル通信

1. 例

ここに画像の説明を挿入

2. コンピュータのシリアルデバイスをポーリングする

    // 查询所有串口设备
    QList<QSerialPortInfo> serialList = QSerialPortInfo::availablePorts();

    QStringList serialPortNameList;
    foreach(const QSerialPortInfo &info,QSerialPortInfo::availablePorts())
    {
    
    
        serialPortNameList << info.portName();
        qDebug()<<"serialPortName: "<<info.portName();
    }
    // 展示在下拉列表中
    ui->comboBox->addItems(serialPortNameList);

QSerialPort を使用するには、pro に追加する必要があることに注意してください。QT += serialport

3. シリアルクラス

	m_serialPort = new QSerialPort(this);
    connect(m_serialPort, &QSerialPort::readyRead, this, &MainWindow::handleReadyRead);
    connect(m_serialPort, &QSerialPort::errorOccurred, this, &MainWindow::handleError);

readRead 事件:シリアルデータを非同期で受信中
errorOccurred 事件:異常

void MainWindow::handleReadyRead()
{
    
    
    m_recvData = m_serialPort->readAll();
    writeMsg("异步收到:" + QString::fromUtf8(m_recvData));

    emit serialDataReadFinished();  // 自定义的事件,为了配合通知异步等待完成
}

void MainWindow::handleError(QSerialPort::SerialPortError serialPortError)
{
    
    
    if (serialPortError == QSerialPort::ReadError)
    {
    
    
        QString error = QString("An I/O error occurred while reading "
                                        "the data from port %1, error: %2")
                            .arg(m_serialPort->portName())
                            .arg(m_serialPort->errorString());
        writeMsg(error);
    }
}

4. シリアルデータの送信

4.1 シリアルポートデータ送信後は待たずにhandleReadyReadシリアルポートから非同期でデータを受信する

void MainWindow::on_sendMsgButton_clicked()
{
    
    
    QString sendData = ui->textEdit->toPlainText();
    writeMsg("发送:" + sendData);

    m_serialPort->write(sendData.toUtf8(), sendData.toUtf8().size());
}

4.2 シリアル ポート データを送信した後、シリアル ポートがデータを同期して返すのを待ちます。

void MainWindow::on_sendMsgButton_clicked()
{
    
    
    QString sendData = ui->textEdit->toPlainText();
    writeMsg("发送:" + sendData);

    m_serialPort->write(sendData.toUtf8(), sendData.toUtf8().size());

	if(!m_serialPort->waitForReadyRead(5000))
	{
    
    
		writeMsg("等待回复超时");
		return;
	}
	
	QByteArray recvData = m_serialPort->readAll();
	writeMsg("同步收到:" + QString::fromUtf8(recvData));
}

QSerialPortただし、イベントをリッスンするとreadReadwaitForReadyReadシリアル ポートから返されるデータを待つことができず、常にタイムアウトになります。



場合によっては、シリアル ポートにメッセージを送信した後、シリアル ポートから返されたデータを時間内に受信する必要があり、また、メッセージが送信されていないときに、非同期監視を使用してシリアル ポートから報告されたデータをリアルタイムで受信する必要もあります。
したがって:
a. シリアル ポート データの同期読み取りを待機する必要がある; b.イベントを監視し、リアルタイムでデータを受信する
必要があるreadRead



解決策 1:

非同期待機メソッドを自分で記述して、非同期を同期にすることができます

bool MainWindow::waiteForReadyRead(int msec)
{
    
    
    QEventLoop eventloop;
    QObject::connect(this, &MainWindow::serialDataReadFinished, &eventloop, &QEventLoop::quit);

    bool isTimeout = false;
    QTimer::singleShot(msec, &eventloop, [&](){
    
    
        eventloop.quit();
        isTimeout = true;
    });

    eventloop.exec(QEventLoop::AllEvents);
    return !isTimeout;
}
  • serialDataReadFinishedこのイベントはカスタム イベントで、シリアル ポート データが handleReadyRead スロット関数で受信された後、このイベントは非同期待機の終了を通知するために送信されます。
  • QTimer::singleShotタイミングとしては、タイムアウト後に非同期待機も終了します。
  • 戻り値は、serialDataReadFinished受信イベントの終了待ちの非同期の場合は正常終了でtrueを返し、タイムアウト終了の場合は異常終了でfalseを返します。

したがって、シリアル ポート データを送信した後、結果を待つ必要がある場合は、次のように記述できます。

void MainWindow::on_sendMsgButton_2_clicked()
{
    
    
    QString sendData = ui->textEdit->toPlainText();
    writeMsg("发送:" + sendData);

    m_serialPort->write(sendData.toUtf8(), sendData.toUtf8().size());
    if(!waiteForReadyRead(5000))	// 自定义的异步等待函数
    {
    
    
        writeMsg("等待回复超时");
    }
    else
    {
    
    
        writeMsg("同步收到: " + m_recvData);
    }
}


解決策 2:

write切断イベントが切断される前にreadRead、シリアル ポート クラスに付属する waitForReadyRead を使用してシリアル ポート データを待ってから、シリアル ポート データを読み取ります。読み込み後は再度connectreadReadイベントを使用してください。

void MainWindow::on_sendMsgButton_2_clicked()
{
    
    
    QString sendData = ui->textEdit->toPlainText();
    writeMsg("发送:" + sendData);
	
	// 断开readyRead事件
	disconnect(m_serialPort, &QSerialPort::readyRead, this, &MainWindow::handleReadyRead);
	
    m_serialPort->write(sendData.toUtf8(), sendData.toUtf8().size());
    if(!m_serialPort->waitForReadyRead(5000))	// 串口类自带的等待函数
    {
    
    
        writeMsg("等待回复超时");
    }
    else
    {
    
    
    	m_recvData = m_serialPort->readAll();
        writeMsg("同步收到: " + m_recvData);
    }
    
    // 重新连接readyRead事件
	connect(m_serialPort, &QSerialPort::readyRead, this, &MainWindow::handleReadyRead);
}




上記の完全なコード: QSerialPortTest



5. テスト

仮想シリアル ポート ツールの仮想シリアル ポートをダウンロードし、仮想シリアル ポート ペアを作成します。たとえば、私が作成したシリアル ポート ペアは COM4 と COM5 です。
ここに画像の説明を挿入
シリアル ポート ペアを作成した後、システム デバイス マネージャーで次のように表示されます。

ここに画像の説明を挿入
テスト プログラムをコンパイルした後、COM4 用と COM5 用の 2 つのプロセスを開きます。
ここに画像の説明を挿入

おすすめ

転載: blog.csdn.net/Jay_Xio/article/details/127394729