1. Home
  2. Docs
  3. QT
  4. Genel
  5. QSerialPort ile Seri Port Okuma ve Yazma Arayüzü

QSerialPort ile Seri Port Okuma ve Yazma Arayüzü

Print

Gömülü sistemler dünyasında ESP32, STM32, Arduino veya Orange Pi gibi geliştirme kartlarıyla çalışırken, cihazdan toplanan sensör verilerini bilgisayarda gerçek zamanlı görselleştirmek veya cihaza komut göndermek en yaygın ihtiyaçtır. Bu köprüyü kurmanın en kararlı yolu Qt QSerialPort kullanımı ile masaüstü UART arayüzü geliştirmektir.

Qt, platform bağımsız (Windows, Linux, macOS) çalışan QSerialPort ve QSerialPortInfo sınıfları sayesinde işletim sistemi API’lerine (Win32 veya Linux POSIX termios) bulaşmadan kolayca seri port haberleşmesi yapmanızı sağlar.

Bu rehberde, portları otomatik keşfetmeyi, baudrate yapılandırmasını, asenkron veri okuma/yazma süreçlerini eksiksiz C++ kodlarıyla ele alıyoruz.


Proje Yapılandırması (CMake ve QMake)

QSerialPort sınıfını kullanabilmek için projenize SerialPort modülünü dahil etmeniz gerekir.

Modern CMake (CMakeLists.txt):

find_package(Qt6 COMPONENTS Core Gui Widgets SerialPort REQUIRED)
target_link_libraries(BenimUygulamam PRIVATE Qt6::Widgets Qt6::SerialPort)

Klasik QMake (.pro):

QT += core gui widgets serialport

1. Sistemdeki Mevcut Seri Portları Listelemek

Uygulamanız başladığında kullanıcının el ile port ismi (örn: COM3 veya /dev/ttyUSB0) yazması yerine, bağlı cihazları QSerialPortInfo ile dinamik olarak bir QComboBox içine doldurabilirsiniz:

#include <QSerialPortInfo>
#include <QComboBox>
#include <QDebug>

void portlariListele(QComboBox *comboBox) {
    comboBox->clear();
    const auto portlar = QSerialPortInfo::availablePorts();

    for (const QSerialPortInfo &port : portlar) {
        QString portBilgisi = QString("%1 (%2)")
                                  .arg(port.portName())
                                  .arg(port.description().isEmpty() ? "Bilinmeyen Cihaz" : port.description());
        comboBox->addItem(portBilgisi, port.systemLocation());
        qDebug() << "Tespit Edilen Port:" << port.portName() << "Uretici:" << port.manufacturer();
    }
}

2. Seri Portu Yapılandırmak ve Açmak

Cihazla doğru iletişim kurabilmek için baud hızı, veri bitleri, eşlik (parity) ve durma bitlerinin mikrodenetleyici tarafıyla (örneğin ESP32 veya Arduino) birebir eşleşmesi gerekir:

#include <QSerialPort>
#include <QDebug>

QSerialPort *serial = new QSerialPort(this);

bool portuAc(const QString &portAdi, qint32 baudRate = 115200) {
    serial->setPortName(portAdi); // Windows'ta "COM3", Linux'ta "/dev/ttyUSB0"
    serial->setBaudRate(baudRate);
    serial->setDataBits(QSerialPort::Data8);
    serial->setParity(QSerialPort::NoParity);
    serial->setStopBits(QSerialPort::OneStop);
    serial->setFlowControl(QSerialPort::NoFlowControl);

    if (serial->open(QIODevice::ReadWrite)) {
        qDebug() << "Seri port basariyla acildi:" << portAdi;
        return true;
    } else {
        qDebug() << "Port acilamadi! Hata:" << serial->errorString();
        return false;
    }
}

3. Asenkron Veri Okuma: readyRead Sinyali

Seri haberleşmede en büyük hata, veriyi beklemek için waitForReadyRead() gibi fonksiyonlarla ana arayüzü dondurmaktır.

Qt’nin olay tabanlı mimarisi gereği, işletim sistemi arabelleğine yeni bir bayt geldiği anda QSerialPort nesnesi readyRead sinyalini tetikler. Biz de sitemizdeki Signals ve Slots Mekanizması sayesinde bu sinyali bir slota bağlarız:

// Tampon bellek (parcali gelen paketleri toplamak icin)
QByteArray gelenTampon;

connect(serial, &QSerialPort::readyRead, this, [serial, &gelenTampon]() {
    // Porttaki tum mevcut veriyi oku
    gelenTampon.append(serial->readAll());

    // Satir sonu (\n) karakterine gore paketleri ayikla
    while (gelenTampon.contains('\n')) {
        int satirSonuIndex = gelenTampon.indexOf('\n');
        QByteArray satir = gelenTampon.left(satirSonuIndex).trimmed();
        gelenTampon.remove(0, satirSonuIndex + 1);

        QString okunanMetin = QString::fromUtf8(satir);
        qDebug() << "Sensorden Gelen Paket:" << okunanMetin;
        // Ornek: ui->textEdit->append(okunanMetin);
    }
});

Önemli İpucu: Seri haberleşmede veriler paket paket değil akış halinde gelir. Bu nedenle mikrodenetleyiciden gönderdiğiniz verinin sonuna \n (newline) eklemek ve Qt tarafında contains('\n') ile satır satır ayıklamak veri bozulmalarını önler.


4. Cihaza Veri / Komut Gönderme (Write)

Mikrodenetleyiciye komut (örneğin bir röleyi açmak veya LED yakmak) iletmek son derece basittir:

void komutGonder(const QString &komut) {
    if (serial && serial->isOpen()) {
        QByteArray veri = (komut + "\n").toUtf8();
        qint64 yazilanBayt = serial->write(veri);
        serial->flush(); // Veriyi hemen donanima pompala
        qDebug() << "Gonderilen Bayt:" << yazilanBayt;
    }
}

5. Portu Güvenli Kapatmak

Uygulama kapanırken veya cihazın bağlantısı kesildiğinde port mutlaka kapatılmalıdır:

void portuKapat() {
    if (serial && serial->isOpen()) {
        serial->close();
        qDebug() << "Seri port kapatildi.";
    }
}

Eğer mikrodenetleyiciden gelen veri saniyede yüzlerce paket gibi çok yüksek frekanstaysa, arayüzün akıcılığını korumak için veri okuma mantığını QThread ile GUI Donmasını Önleme rehberimizdeki gibi arka plan thread’ine taşıyabilirsiniz. Ayrıca ESP32 tarafındaki firmware hazırlığı için ESP-IDF ile Giriş serimize göz atabilirsiniz.

Ayrıntılı hata kodları ve sinyal parametreleri için resmi Qt QSerialPort Sınıf Dokümantasyonu sayfasını inceleyebilirsiniz.

Tags , , , , , , , ,

How can we help?