Виталий Антипов
Виталий Антипов22 липня 2017 р. 07: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 р. 00:56

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

    Evgenii Legotckoi
    • 23 липня 2017 р. 09: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(), другие говорят что это не хорошо. Завтра попробую.
        Evgenii Legotckoi
        • 24 липня 2017 р. 18:11

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

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

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

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

            Коментарі

            Only authorized users can post comments.
            Please, Log in or Sign up
            AD

            C++ - Тест 004. Указатели, Массивы и Циклы

            • Результат:50бали,
            • Рейтинг балів-4
            m
            • molni99
            • 26 жовтня 2024 р. 01:37

            C++ - Тест 004. Указатели, Массивы и Циклы

            • Результат:80бали,
            • Рейтинг балів4
            m
            • molni99
            • 26 жовтня 2024 р. 01:29

            C++ - Тест 004. Указатели, Массивы и Циклы

            • Результат:20бали,
            • Рейтинг балів-10
            Останні коментарі
            ИМ
            Игорь Максимов22 листопада 2024 р. 11:51
            Django - Підручник 017. Налаштуйте сторінку входу до Django Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
            Evgenii Legotckoi
            Evgenii Legotckoi31 жовтня 2024 р. 14:37
            Django - Урок 064. Як написати розширення для Python Markdown Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
            A
            ALO1ZE19 жовтня 2024 р. 08:19
            Читалка файлів fb3 на Qt Creator Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
            ИМ
            Игорь Максимов05 жовтня 2024 р. 07:51
            Django - Урок 064. Як написати розширення для Python Markdown Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
            d
            dblas505 липня 2024 р. 11:02
            QML - Урок 016. База даних SQLite та робота з нею в QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
            Тепер обговоріть на форумі
            Evgenii Legotckoi
            Evgenii Legotckoi24 червня 2024 р. 15:11
            добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
            t
            tonypeachey115 листопада 2024 р. 06:04
            google domain [url=https://google.com/]domain[/url] domain [http://www.example.com link title]
            NSProject
            NSProject04 червня 2022 р. 03:49
            Всё ещё разбираюсь с кешем. В следствии прочтения данной статьи. Я принял для себя решение сделать кеширование свойств менеджера модели LikeDislike. И так как установка evileg_core для меня не была возможна, ибо он писался…
            9
            9Anonim25 жовтня 2024 р. 09:10
            Машина тьюринга // Начальное состояние 0 0, ,<,1 // Переход в состояние 1 при пустом символе 0,0,>,0 // Остаемся в состоянии 0, двигаясь вправо при встрече 0 0,1,>…

            Слідкуйте за нами в соціальних мережах