Виталий Антипов
Виталий Антипов22 июля 2017 г. 7:26

Передача данных из цикла С++ в QML

Здравствуйте! У меня следующая задача: с датчика mpu6050 передать данные ускорения восьми измерений подряд на ODROID XU4, вычислить СКЗ каждого измерения и последовательно передать их в QML в поле TextField. Ниже представленный код работает отлично, вот только в поле TextField отображается лишь СКЗ последнего измерения, а хотелось бы визуально наблюдать изменения от замера к замеру с перспективой построения графика в реальном времени. Прошу помощи.

 
main.cpp
#include <QQmlApplicationEngine>
#include <QApplication>
#include <QObject>
#include <QDebug>
#include <QQmlContext>
#include "dataport.h"

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QApplication app(argc, argv);

    QQmlApplicationEngine engine;
    engine.load(QUrl(QLatin1String("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;
    QObject* root = engine.rootObjects().first();
    dataport *port = new dataport(root);
    QObject::connect(root, SIGNAL(startSignal()), port, SLOT(start()));
    return app.exec();
}
 
dataport.h
#ifndef DATAPORT_H
#define DATAPORT_H

#include <QObject>
#include <QDebug>
#include <QTime>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>

#include <unistd.h>
#include <string.h>
#include <time.h>

#define I2C_SLAVE	0x0703
#define I2C_SMBUS	0x0720

#define I2C_SMBUS_READ	1
#define I2C_SMBUS_WRITE	0

#define I2C_SMBUS_QUICK		    0
#define I2C_SMBUS_BYTE		    1
#define I2C_SMBUS_BYTE_DATA	    2
#define I2C_SMBUS_WORD_DATA	    3
#define I2C_SMBUS_PROC_CALL	    4
#define I2C_SMBUS_BLOCK_DATA	    5
#define I2C_SMBUS_I2C_BLOCK_BROKEN  6
#define I2C_SMBUS_BLOCK_PROC_CALL   7	
#define I2C_SMBUS_I2C_BLOCK_DATA    8

#define I2C_SMBUS_BLOCK_MAX	    32	
#define I2C_SMBUS_I2C_BLOCK_MAX	32	

class dataport : public QObject
{
    Q_OBJECT

public:
    explicit dataport(QObject *parent = 0);

signals:
    //void sendToQml(QString skz);

public slots:
    void start();

private:
    QString dataX;
    int i,k,l;
    int16_t val1, val2;
    int accX;
    double massive[2048];
    double massiveX[2048];
    char ch1, ch2;
    double sumkv;
    double sum;
QString skz;

    union i2c_smbus_data
    {
      uint8_t   byte;
      uint16_t  word;
      uint8_t   block [I2C_SMBUS_BLOCK_MAX + 2] ;
    };

    struct i2c_smbus_ioctl_data
    {
      char                  read_write;
      uint8_t               command ;
      int                   size;
      union i2c_smbus_data  *data;
    };

    static inline int i2c_smbus_access (int fd, char rw, uint8_t command, int size, union i2c_smbus_data *data)
    {
      struct i2c_smbus_ioctl_data args ;

      args.read_write = rw ;
      args.command    = command ;
      args.size       = size ;
      args.data       = data ;
      return ioctl (fd, I2C_SMBUS, &args) ;
    }

    int i2c_smbus_read_byte_data(int fd, int reg)
    {
      union i2c_smbus_data data;

      if (i2c_smbus_access (fd, I2C_SMBUS_READ, reg, I2C_SMBUS_BYTE_DATA, &data))
        return -1 ;
      else
        return data.byte & 0xFF ;
    }

    void data_update (void);
    int system_init(void);

    const char *i2cHandleNode = "/dev/i2c-1";
    int i2c_fd = -1;

};

#endif // DATAPORT_H
 
dataport.cpp
#include "dataport.h"

    dataport::dataport(QObject *parent) : QObject(parent)
    {

    }

    void dataport::data_update(void)
    {
        if(ioctl(i2c_fd, I2C_SLAVE, 0x68) < 0)  {
            fprintf(stdout, "%s : ioctl I2C_SLAVE Setup Error!\n", __func__);
            return;
        }
        ch1 = i2c_smbus_read_byte_data(i2c_fd, 0x3b);
        ch2 = i2c_smbus_read_byte_data(i2c_fd, 0x3c);
        val1 = ch1<<8|ch2;
    }

    int dataport::system_init(void)
    {
        if((i2c_fd = open(i2cHandleNode, O_RDWR)) < 0)  {
            fprintf(stdout, "%s : %s Open Error!\n", __func__, i2cHandleNode);
            return  -1;
        }
        return  0;
    }

    void dataport::start()
    {
        QObject* textX1 = this->parent()->findChild<QObject*>("textX");
        if (system_init() < 0)
            {
                fprintf (stderr, "%s: System Init failed\n", __func__); fflush(stdout);
                //return -1;
            }
        for(l=0;l<8;l++){
QTime start = QTime::currentTime();
                   for(i=0;i<2048;i++){
                       usleep(70);
                        if(ioctl(i2c_fd, I2C_SLAVE, 0x68) < 0)  {
                            fprintf(stdout, "%s : ioctl I2C_SLAVE Setup Error!\n", __func__);
                            return;
                        }
                        ch1 = i2c_smbus_read_byte_data(i2c_fd, 0x3b);
                        ch2 = i2c_smbus_read_byte_data(i2c_fd, 0x3c);
                        val1 = ch1<<8|ch2;
                        massive[i]=val1;
                    }
qDebug()<< "time "<< start.elapsed();
sumkv = 0;
for(k=0;k<2048;k++){
    massiveX[k]=(fabs(massive[k]/16384) - 1)*9.81;
    sum = massiveX[k]*massiveX[k];
    sumkv = sumkv + sum;
}
            qDebug()<<massive[15];
            qDebug()<<massiveX[15];
            skz = QString::number(sqrt(sumkv/2048));///(l+1);
            qDebug()<<skz;
            textX1->setProperty("text",skz);
        }          
}
 
main.qml
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3
import QtCharts 2.0

ApplicationWindow {
    id: tex
    objectName: "tex"
    visible: true
    width: 640
    height: 480
    title: qsTr("TEST2")

signal startSignal()
    
    Button{
        text: "START"
        onClicked: startSignal()
    }

    TextField{
        id: textX
        objectName: "textX"
        width: parent.width/3
        height: parent.height/10
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.top: parent.top
    }
    Text {
        id: textXx
        objectName: "textXx"
        //text: qsTr("text")
    }
    ChartView{
        title: "SKZ"
        anchors.top: textX.bottom
        anchors.left: parent.left
        anchors.right: parent.right
        anchors.bottom: parent.bottom
        antialiasing: true       
    }
}
Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Вам это нравится? Поделитесь в социальных сетях!

5
Виталий Антипов
  • 23 июля 2017 г. 0:56

Попробовал через QQmlContext - результат тот же. В console.log("skz = ", skz) вижу что данные в qml приходят как задумано, но обновление текста в TextField происходит только после окончания работы функции. И при попытке цикл выполнить в qml даже с насильным textX.update() не приводит к желаемому результату.

    Evgenii Legotckoi
    • 23 июля 2017 г. 9:44

    День добрый.

    Под QQmlContext , подразумеваете, что регистрировали dataport в контексте QML , и через Connections устанавливали обработчик для сигнала sendToQml ? Как вариант данные могут обрабатываться очень быстро, и вы просто не успеваете заметить изменения.
    Вообще, применение сигнала sendToQml считаю наиболее оптимальным вариантом для этого User Case.

    Если говорить о том, что изменения происходят после выполнения функции, то возможно, что это из-за очереди слотов. Установка данных в QML тоже осуществляется через сигнал/слотовые соединения.
    Как вариант, можете сначала сделать буфер подготовленных данных, а потом уже их выкидывать через таймер, но мне кажется это несколько не правильным. Всё-таки работа с embedded, в котором обычно любые задержки критичны...
      Виталий Антипов
      • 23 июля 2017 г. 14:43

      Да, сигнально-слотовое соединение построил по вашим урокам. Таймер через qDebug показывает, что на взятие 2048 сигналов с датчика уходит 1000 мс. qDebug совместно с console.log из QML показывают новые данные раз в секунду как и задумано, не заметить изменения как-то сложно.

      Пару месяцев назад делал проект с Arduino и соответственно работал с буфером. Вот там приходящие данные сразу обновлялись в QML, трехмерная визуализация работала хорошо, но как вы правильно заметили возникли проблемы с временем - временные интервалы были абсолютно не стабильны, и если для визуализации не страшно, то для расчетов неприемлемо.
      Погуглив, четкого ответа не нашел. Некоторые предлагают в цикл подсунуть QApplication::processEvents(), другие говорят что это не хорошо. Завтра попробую.

        А вы не пробовали вставлять сигнал или выставление text через setProperty внутри цикла, где забираете значения с шины данных?

        А то я тут внимательно присмотрелся к коду, и у меня возник вопрос. Почему выставление значения происходит только в конце метода start... По мне так, так там только один раз вызывается qDebug() ...
          Виталий Антипов
          • 25 июля 2017 г. 0:08
          • (ред.)

          У меня в главный цикл (цикл количества измерений) вложены два последовательных (цикл сбора данных и цикл обработки данных). setProperty (или emit sendToQml в случае использования context) вызывается в конце главного цикла.

          Я тут почитал немного про синхронные и асинхронные потоки и понял что так все и задумано (для безопасности потоков). Пока не закончится основной цикл ничего в интерфейсе не обновляется (хоть данные и передаются). И тут 2 варианта - либо использовать наглое прерывание цикла qApp->processEvents() (я проверил - работает), либо разложить код на два потока и управлять ими используя QThread (так правильнее и надежнее). Как разберусь с управлением потоков - выложу код.

            Комментарии

            Только авторизованные пользователи могут публиковать комментарии.
            Пожалуйста, авторизуйтесь или зарегистрируйтесь
            e
            • ehot
            • 1 апреля 2024 г. 0:29

            C++ - Тест 003. Условия и циклы

            • Результат:78баллов,
            • Очки рейтинга2
            B

            C++ - Тест 002. Константы

            • Результат:16баллов,
            • Очки рейтинга-10
            B

            C++ - Тест 001. Первая программа и типы данных

            • Результат:46баллов,
            • Очки рейтинга-6
            Последние комментарии
            k
            kmssr9 февраля 2024 г. 5:43
            Qt Linux - Урок 001. Автозапуск Qt приложения под Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
            АК
            Анатолий Кононенко5 февраля 2024 г. 12:50
            Qt WinAPI - Урок 007. Работаем с ICMP Ping в Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
            EVA
            EVA25 декабря 2023 г. 21:30
            Boost - статическая линковка в CMake проекте под Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
            J
            JonnyJo25 декабря 2023 г. 19:38
            Boost - статическая линковка в CMake проекте под Windows Сделал всё по-как у вас, но выдаёт ошибку [build] LINK : fatal error LNK1104: не удается открыть файл "libboost_locale-vc142-mt-gd-x64-1_74.lib" Хоть убей, не могу понять в чём дел…
            G
            Gvozdik19 декабря 2023 г. 8:01
            Qt/C++ - Урок 056. Подключение библиотеки Boost в Qt для компиляторов MinGW и MSVC Для решения твой проблемы добавь в файл .pro строчку "LIBS += -lws2_32" она решит проблему , лично мне помогло.
            Сейчас обсуждают на форуме
            a
            a_vlasov14 апреля 2024 г. 16:41
            Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Евгений, добрый день! Такой вопрос. Верно ли следующее утверждение: Любое Android-приложение, написанное на Java/Kotlin чисто теоретически (пусть и с большими трудностями) можно написать и на C+…
            Павел Дорофеев
            Павел Дорофеев14 апреля 2024 г. 12:35
            QTableWidget с 2 заголовками Вот тут есть кастомный QTableView с многорядностью проект поддерживается, обращайтесь
            f
            fastrex4 апреля 2024 г. 14:47
            Вернуть старое поведение QComboBox, не менять индекс при resetModel Добрый день! У нас много проектов в которых используется QComboBox, в версии 5.5.1, когда модель испускает сигнал resetModel, currentIndex не менялся. В версии 5.15 при resetModel происходит try…
            P
            Pisych27 февраля 2023 г. 15:04
            Как получить в массив значения из связанной модели? Спасибо, разобрался:))
            AC
            Alexandru Codreanu19 января 2024 г. 22:57
            QML Обнулить значения SpinBox Доброго времени суток, не могу разобраться с обнулением значение SpinBox находящего в делегате. import QtQuickimport QtQuick.ControlsWindow { width: 640 height: 480 visible: tr…

            Следите за нами в социальных сетях