Qtの基礎 - シリアル通信

提供:MochiuWiki : SUSE, EC, PCB
2024年2月28日 (水) 19:41時点におけるWiki (トーク | 投稿記録)による版 (→‎データの送信)
ナビゲーションに移動 検索に移動

概要

QtSerialPortライブラリは、 Qtライブラリのアドオンモジュールであり、ハードウェアシリアルポートとバーチャルシリアルポートの両方に単一のインターフェースを提供する。

シリアルインターフェースは、そのシンプルさと信頼性から、組み込みシステムやロボット開発等の業界ではよく使用されている。

QtSerialPortライブラリを使用することにより、開発者はシリアルインターフェイスへのアクセスが必要なQtアプリケーションの実装に必要な時間を大幅に短縮することができる。


データの送信

Qtのシリアルポートモジュールをプロジェクトファイルに追加する。

 # QMake
 
 QT += core serialport


 # CMake
 
 find_package(Qt6 REQUIRED COMPONENTS SerialPort)
 target_link_libraries(mytarget PRIVATE Qt6::SerialPort)


以下の例では、ボーレートは9600[bps]、データビットは8[ビット]、パリティなし、ストップビットは1[ビット]の8N1で、シリアル通信を行っている。

 #include <QCoreApplication>
 #include <QSerialPort>
 #include <QSerialPortInfo>
 #include <QDebug>
 
 int main(int argc, char *argv[])
 {
    QCoreApplication a(argc, argv);
 
    QSerialPort serial;
    serial.setPortName("/dev/ttyUSB0");                // シリアルポート名 (環境に合わせて変更すること)
    serial.setBaudRate(QSerialPort::Baud9600);         // ボーレート 9600[bps]
    serial.setDataBits(QSerialPort::Data8);            // データビット 8[ビット]
    serial.setParity(QSerialPort::NoParity);           // パリティなし
    serial.setStopBits(QSerialPort::OneStop);          // ストップビット 1[ビット]
    serial.setFlowControl(QSerialPort::NoFlowControl); // フロー制御なし
 
    if (!serial.open(QIODevice::ReadWrite)) {
       qDebug() << "Could not open serial port : " << serial.errorString();
       return -1;
    }
 
    // データの送信
    QByteArray dataToSend = "Hello, Serial Port!";
    serial.write(dataToSend);
 
    serial.close();
  
    return a.exec();
 }



データの受信

同期式

以下の例では、同期的にデータを受信している。
実用的な設計を行う場合は、信頼性と応答性を高めるために、シグナルおよびスロットを使用した非同期でデータを受信する方法が推奨される。

 #include <QCoreApplication>
 #include <QSerialPort>
 #include <QSerialPortInfo>
 #include <QDebug>
 
 int main(int argc, char *argv[])
 {
    QCoreApplication a(argc, argv);
 
    QSerialPort serial;
    serial.setPortName("/dev/ttyUSB0");                // シリアルポート名 (環境に合わせて変更すること)
    serial.setBaudRate(QSerialPort::Baud9600);         // ボーレート 9600[bps]
    serial.setDataBits(QSerialPort::Data8);            // データビット 8[ビット]
    serial.setParity(QSerialPort::NoParity);           // パリティなし
    serial.setStopBits(QSerialPort::OneStop);          // ストップビット 1[ビット]
    serial.setFlowControl(QSerialPort::NoFlowControl); // フロー制御なし
 
    if (!serial.open(QIODevice::ReadWrite)) {
       qDebug() << "Could not open serial port : " << serial.errorString();
       return -1;
    }
 
    // データの受信 (同期式)
    // 非同期でデータを受信する方法を推奨する
    // 1[Sec]待機
    if (serial.waitForReadyRead(1000)) {
       QByteArray responseData = serial.readAll();
       while (serial.waitForReadyRead(10))
          responseData += serial.readAll();
 
       qDebug() << "Recieved data : " << responseData;
    }
    else {
       qDebug() << "Failed to recieve data";
    }
 
    serial.close();
  
    return a.exec();
 }


非同期

非同期でデータを受信する場合、QSerialPortクラスのシグナルとスロットのメカニズムを使用する。
これにより、データが受信された時に自動的に通知されて、アプリケーションのメインループをブロックすることなくデータを受信することができる。

まず、QObjectクラスを継承したクラスを定義する。
シリアルポートからのデータの受信を管理するためのスロットを用意する。
以下の例では、シリアルポートがデータを受信したことを検出するために、readyReadシグナルを使用している。

 // Sample.hファイル
 
 #include <QCoreApplication>
 #include <QSerialPort>
 #include <QDebug>
 
 class SerialPortReader : public QObject
 {
    Q_OBJECT
 public:
    SerialPortReader(QSerialPort *serialPort, QObject *parent = nullptr) : QObject(parent), m_serialPort(serialPort)
    {
       connect(m_serialPort, &QSerialPort::readyRead, this, &SerialPortReader::handleReadyRead);
    }
 
 private slots:
    void handleReadyRead()
    {
       const QByteArray data = m_serialPort->readAll();
       qDebug() << "Recieved data : " << data;
    }
 
 private:
    QSerialPort *m_serialPort;
 };


 // Sample.cppファイル
 
 #include <QCoreApplication>
 #include <QSerialPort>
 #include <QDebug>
 
 int main(int argc, char *argv[])
 {
    QCoreApplication app(argc, argv);
 
    QSerialPort serial;
    serial.setPortName("/dev/ttyUSB0");                // シリアルポート名 (環境に合わせて変更すること)
    serial.setBaudRate(QSerialPort::Baud9600);         // ボーレート 9600[bps]
    serial.setDataBits(QSerialPort::Data8);            // データビット 8[ビット]
    serial.setParity(QSerialPort::NoParity);           // パリティなし
    serial.setStopBits(QSerialPort::OneStop);          // ストップビット 1[ビット]
    serial.setFlowControl(QSerialPort::NoFlowControl); // フロー制御なし
 
    if (!serial.open(QIODevice::ReadWrite)) {
       qDebug() << "Could not open serial port : " << serial.errorString();
       return -1;
    }
 
    SerialPortReader reader(&serial);
 
    return app.exec();
 }