Logs
Consultez les logs.
OK
Liste des données
Consultez la liste des données.
OK
Loading...
Formulaire
Saisissez vos données.
Enregistrer
Annuler

Qt Oscilloscope

Vues
485

Introduction


La nature se déplace sous la forme d'une onde sinusoïdale, qu'il s'agisse d'une vague océanique, d'un tremblement de terre, d'un bang sonique, d'une explosion, d'un son dans l'air ou de la fréquence naturelle d'un corps en mouvement. L'énergie, les particules vibrantes et d'autres forces invisibles imprègnent notre univers physique. Même la lumière, en partie particule, en partie onde, a une fréquence fondamentale, qui peut être observée sous forme de couleur. Les capteurs peuvent convertir ces forces en signaux électriques que vous pouvez observer et étudier avec un oscilloscope. Les oscilloscopes permettent aux scientifiques, ingénieurs, techniciens, enseignants et autres de voir les événements qui changent au fil du temps. Les oscilloscopes sont des outils indispensables pour quiconque conçoit, fabrique ou répare des équipements électroniques. Dans le monde en évolution rapide d'aujourd'hui, les ingénieurs ont besoin des meilleurs outils disponibles pour résoudre leurs problèmes de mesure avec rapidité et précision. Aux yeux de l'ingénieur, les oscilloscopes sont la clé pour relever les défis de mesure exigeants d'aujourd'hui. L'utilité d'un oscilloscope ne se limite pas au monde de l'électronique. Avec le capteur approprié, un oscilloscope peut mesurer toutes sortes de phénomènes. Un capteur est un appareil qui crée un signal électrique en réponse à des stimuli physiques, tels que le son, le stress mécanique, la pression, la lumière ou la chaleur. Un microphone est un capteur qui convertit le son en signal électrique. Les oscilloscopes sont utilisés par tout le monde, des physiciens aux techniciens en réparation de téléviseurs. Un ingénieur automobile utilise un oscilloscope pour corréler les données analogiques des capteurs avec les données série de l'unité de commande du moteur. Un chercheur en médecine utilise un oscilloscope pour mesurer les ondes cérébrales. Les possibilités sont infinies.

image.png


Recommandations techniques


Pour tester les extraits de code dans ce tutoriel, vous aurez besoin des éléments suivants:

Une bibliothèque de création d'interface homme machine Qt.
Un émulateur de ports séries virtuels VSPE (Virtual Serial Ports Emulator).
Lien vers la bibliothèque Qt: https://www.qt.io/download
Lien vers l'émulateur VSPE: https://eterlogic.com/Downloads.html


Affichage d'une boîte de dialogue d'information


Résultat:

image.png

Affichage d'une boîte de dialogue d'information:

//===============================================
void GWindow::on_actionOpen_triggered(bool checked) {
    QMessageBox::information(this
            , "Enregistrement des données"
            , "Aucune donnée n'a été collectée\n"
              "connectez-vous d'abord à un appareil"
    );
}
//===============================================


Affichage d'une boîte de dialogue d'erreur critique


Résultat:

image.png

Affichage de la boîte de dialogue d'erreur critique:

//===============================================
void GWindow::on_actionOpen_triggered(bool checked) {
    QMessageBox::critical(this
            , "Erreur d'enregistrement des données"
            , "Impossible d'écrire dans le fichier"
    );
}
//===============================================


Affichage d'une boîte de dialogue d'enregistrement


Résultat:

image.png

Affichage d'une boîte de dialogue d'enregistrement:

//===============================================
void GWindow::on_actionOpen_triggered(bool checked) {
    QString lFilename = QFileDialog::getSaveFileName(this
            , "Enregistrement des données"
            , QString()
            , "Text (*.txt)");

    if(!lFilename.isNull()) {
        qDebug() << lFilename;
    }
    else {
        qDebug() << "Aucun fichier n'a été sélectionné.";
    }
}
//===============================================


Affichage d'une boîte de dialogue d'ouvertement de fichier


Résultat:

image.png

//===============================================
void GWindow::on_actionOpen_triggered(bool checked) {
    QString lFilename = QFileDialog::getOpenFileName(this
            ,"Chargement des paramètres"
            , QString()
            , "Settings (*.ini)"
    );
    if(!lFilename.isNull()) {
        qDebug() << lFilename;
    }
    else {
        qDebug() << "Aucun fichier n'a été sélectionné.";
    }
}
//===============================================


Affichage d'une boîte de dialogue à propos


Résultat:

image.png

Affichage d'une boîte de dialogue à propos:

//===============================================
void GWindow::on_actionOpen_triggered(bool checked) {
    QMessageBox::about(this
            , "À propos"
            , "<p><b>ReadyScope</b> - v1.0</p>"
              ""
              "<p>ReadyScope est un oscilloscope numérique "
              "pour le streaming de données textuelles ou binaires "
              "via TCP, ports série et Bluetooth RFCOMM. "
              "Il offre un rendu flexible et un format de streaming "
              "binaire ou des flux de texte hautement configurables.</p>"
              ""
              "<p>@ 2017-2023 | ReadyDev<br>"
              "Produit par <b>Gérard KESSE</b><br>"
              "Polytech'Montpellier<br></p>"
    );
}
//===============================================


Affichage d'une boîte de dialogue d'aide


Résultat:

image.png

Affichage d'une boîte de dialogue d'aide:

//===============================================
void GWindow::on_actionOpen_triggered(bool checked) {
    QFile lFile("howto.html");
    lFile.open(QIODevice::ReadOnly | QIODevice::Text);
    QByteArray lFileData = lFile.readAll();

    GHelperDialog lHelperDialog;
    lHelperDialog.setText(lFileData);
    lHelperDialog.exec();
}
//===============================================
GHelperDialog::GHelperDialog(QWidget *parent)
: QDialog(parent)
, ui(new Ui::GHelperDialog) {
    ui->setupUi(this);
    ui->label->setWordWrap(true);
    ui->label->setOpenExternalLinks(true);
    ui->label->setFixedWidth(380);
}
//===============================================
void GHelperDialog::setText(const QString& _text) {
    ui->label->setText(_text);
}
//===============================================



Utilisation d'un évènement de peinture


Résultat:

image.png

Utilisation d'un évènement de peinture:

//===============================================
void GWindow::on_actionOpen_triggered(bool checked) {
    GScopeWindow* lScopeWindow = new GScopeWindow;
    lScopeWindow->show();
}
//===============================================
GScopeWindow::GScopeWindow(QWidget* parent) {
    setWindowTitle("ReadyScope");
    resize(400, 300);
    setAttribute(Qt::WA_DeleteOnClose);
}
//===============================================
void GScopeWindow::paintEvent(QPaintEvent* event) {
    qDebug() << __PRETTY_FUNCTION__;
}
//===============================================


Utilisation d'un évènement d'appui sur les boutons de la souris


Résultat:

image.png

Utilisation d'un évènement d'appui sur les boutons de la souris:

//===============================================
void GWindow::on_actionOpen_triggered(bool checked) {
    GScopeWindow* lScopeWindow = new GScopeWindow;
    lScopeWindow->show();
}
//===============================================
GScopeWindow::GScopeWindow(QWidget* parent) {
    setWindowTitle("ReadyScope");
    resize(400, 300);
    setAttribute(Qt::WA_DeleteOnClose);
}
//===============================================
void GScopeWindow::mousePressEvent(QMouseEvent* event ) {
    qDebug() << __PRETTY_FUNCTION__;
}
//===============================================


Utilisation d'un évènement de roue de la souris


Résultat:

image.png

Utilisation d'un évènement de roue de la souris:

//===============================================
void GWindow::on_actionOpen_triggered(bool checked) {
    GScopeWindow* lScopeWindow = new GScopeWindow;
    lScopeWindow->show();
}
//===============================================
GScopeWindow::GScopeWindow(QWidget* parent) {
    setWindowTitle("ReadyScope");
    resize(400, 300);
    setAttribute(Qt::WA_DeleteOnClose);
}
//===============================================
void GScopeWindow::wheelEvent(QWheelEvent* event) {
    qDebug() << __PRETTY_FUNCTION__;
}
//===============================================


Ecriture de données textuelles dans un fichier


Résultat:

image.png

Ecriture de données textuelles dans un fichier:
 
//===============================================
void GWindow::on_actionOpen_triggered(bool checked) {
    QFile lFile("data.txt");
    if (lFile.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
        QTextStream lOutput(&lFile);
        for(int i = 0; i < 5; i++) {
            for(int j = 0; j < 10; j++) {
                lOutput << (i + j + i*j) << " ";
            }
            lOutput << "\n";
        }
        lFile.close();
    }
}
//===============================================


Lecture de données textuelles depuis un fichier


Résultat:

image.png

Lecture de données textuelles depuis un fichier:

//===============================================
void GWindow::on_actionOpen_triggered(bool checked) {
    QFile lFile("howto.html");
    lFile.open(QIODevice::ReadOnly | QIODevice::Text);
    QByteArray lFileData = lFile.readAll();
    qDebug() << lFileData;
}
//===============================================


Listing des ports séries disponibles (Terminal)


Résultat:

image.png

Listing des ports séries disponibles (Terminal):

//===============================================
void GWindow::on_actionOpen_triggered(bool checked) {
    QList<QSerialPortInfo> lPorts = QSerialPortInfo::availablePorts();
    for (int i = 0; i < lPorts.size(); i++) {
        QSerialPortInfo lPort = lPorts.at(i);
        qDebug() << "portName-----------: " << lPort.portName();
        qDebug() << "description--------: " << lPort.description();
        qDebug() << "manufacturer-------: " << lPort.manufacturer();
        qDebug() << "productIdentifier--: " << lPort.productIdentifier();
        qDebug() << "vendorIdentifier---: " << lPort.vendorIdentifier();
        qDebug() << "serialNumber-------: " << lPort.serialNumber();
        qDebug() << "";
    }
}
//===============================================


Listing des ports séries disponibles (QTableWidget)


Résultat:

image.png

Listing des ports séries disponibles (QTableWidget):

//===============================================
GPortDialog::GPortDialog(QWidget *parent)
: QDialog(parent)
, ui(new Ui::GPortDialog) {
    ui->setupUi(this);

    QList<QSerialPortInfo> lPorts = QSerialPortInfo::availablePorts();
    ui->tableWidget->setRowCount(lPorts.size());
    ui->tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
    ui->tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);


    for (int i = 0; i < lPorts.size(); i++) {
        QTableWidgetItem* lNewItem;
        QSerialPortInfo lPort = lPorts.at(i);

        // portName
        lNewItem = new QTableWidgetItem(lPort.portName());
        ui->tableWidget->setItem(i, 0, lNewItem);
        // description
        lNewItem = new QTableWidgetItem(lPort.description());
        ui->tableWidget->setItem(i, 1, lNewItem);
        // manufacturer
        lNewItem = new QTableWidgetItem(lPort.manufacturer());
        ui->tableWidget->setItem(i, 2, lNewItem);
        // productIdentifier
        lNewItem = new QTableWidgetItem(QString::number(lPort.productIdentifier()));
        ui->tableWidget->setItem(i, 3, lNewItem);
        // vendorIdentifier
        lNewItem = new QTableWidgetItem(QString::number(lPort.vendorIdentifier()));
        ui->tableWidget->setItem(i, 4, lNewItem);
        // serialNumber
        lNewItem = new QTableWidgetItem(lPort.serialNumber());
        ui->tableWidget->setItem(i, 5, lNewItem);
    }

    ui->tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
    ui->tableWidget->horizontalHeader()->setStretchLastSection(true);

    if(lPorts.size() > 0) {
        ui->tableWidget->selectRow(0);
    }
}
//===============================================

Gestion du double-clic sur un port série:

//===============================================
void GPortDialog::on_tableWidget_cellDoubleClicked(int row, int column) {
    accept();
}
//===============================================

Sélection d'un port série: 

//===============================================
void GPortDialog::accept() {
    int row = ui->tableWidget->currentRow();
    if(row != -1) {
        m_portName = ui->tableWidget->item(row, 0)->text();
    }
    QDialog::accept();
    qDebug() << m_portName;
}
//===============================================

Lecture du nom du port série:

//===============================================
const QString& GPortDialog::getPortName() const {
    return m_portName;
}
//===============================================


Enregistrement des paramètres de configuration dans un fichier INI


Résultat:

image.png

Enregistrement des paramètres de configuration dans un fichier INI:
 
//===============================================
void GWindow::on_actionOpen_triggered(bool checked) {
    QSettings *lSettings;
    lSettings = new QSettings("settings.ini", QSettings::IniFormat);

    if(lSettings->status() != QSettings::NoError)
        return;

    QString lDisplayFormat = "DisplayFormat";
    QString lBinaryFormat = "BinaryFormat";
    QString lInputDevice = "InputDevice";
    int lBufferSize = 10000;
    int lNanValue = 0;
    int lAfterGlow = 0;
    int lRefreshRate = 30;
    double lScalingA = 1.0;
    double lScalingB = 0.0;
    bool lScalingEnabled = false;

    lSettings->setValue("DisplayFormat", lDisplayFormat);
    lSettings->setValue("BinaryFormat", lBinaryFormat);
    lSettings->setValue("InputDevice", lInputDevice);
    lSettings->setValue("BufferSize", lBufferSize);
    lSettings->setValue("NanValue", lNanValue);
    lSettings->setValue("RefreshRate", lRefreshRate);
    lSettings->setValue("AfterGlow", lAfterGlow);
    lSettings->setValue("ScalingA", lScalingA);
    lSettings->setValue("ScalingB", lScalingB);
    lSettings->setValue("ScalingEnabled", lScalingEnabled);

    delete lSettings;
}
//===============================================


Chargement des paramètres de configuration à partir d'un fichier INI


Résultat:

image.png

Chargement des paramètres de configuration à partir d'un fichier INI: 

//===============================================
void GWindow::on_actionOpen_triggered(bool checked) {
    QSettings *lSettings;
    lSettings = new QSettings("settings.ini", QSettings::IniFormat);

    if(lSettings->status() != QSettings::NoError)
        return;

    QString lDisplayFormat = lSettings->value("DisplayFormat", "").toString();
    QString lBinaryFormat = lSettings->value("BinaryFormat", "").toString();
    QString lInputDevice = lSettings->value("InputDevice", "").toString();
    int lBufferSize = lSettings->value("BufferSize", 100000).toInt();
    int lNanValue = lSettings->value("NanValue", 0).toInt();
    int lAfterGlow = lSettings->value("AfterGlow", 0).toInt();
    int lRefreshRate = lSettings->value("RefreshRate", 10).toInt();
    double lScalingA = lSettings->value("ScalingA", 1.0).toDouble();
    double lScalingB = lSettings->value("ScalingB", 0.0).toDouble();
    bool lScalingEnabled = lSettings->value("ScalingEnabled", false).toBool();

    qDebug() << "DisplayFormat-------: " << lDisplayFormat;
    qDebug() << "BinaryFormat--------: " << lBinaryFormat;
    qDebug() << "InputDevice---------: " << lInputDevice;
    qDebug() << "BufferSize----------: " << lBufferSize;
    qDebug() << "NanValue------------: " << lNanValue;
    qDebug() << "AfterGlow-----------: " << lAfterGlow;
    qDebug() << "RefreshRate---------: " << lRefreshRate;
    qDebug() << "ScalingA------------: " << lScalingA;
    qDebug() << "ScalingB------------: " << lScalingB;
    qDebug() << "ScalingEnabled------: " << lScalingEnabled;
}
//===============================================