嵌入式开发之移植MQTT到RK3568

本文详细介绍了如何将MQTT库qmqtt移植到瑞芯微RK3568芯片上,包括下载源码、编译库文件、移植动态库到开发板以及制作和测试MQTTdemo的过程。通过这个过程,可以将RK3568开发板作为物联网终端,实现实时数据采集和通信。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

前言

一、下载qmqtt源码

二、编译库文件

三、移植到RK3568

3.1 移植动态库libQt5Qmqtt

四、联机测试

4.1 制作demo

4.1.1 创建demo新项目

4.1.2 添加network模块支持

4.1.3 添加qmqtt外部库

4.1.4 功能实现

4.1.5 编译与发布

4.2 移植与测试

4.2.1 启动应用程序

4.2.2 联合测试

总结


前言

        MQTT是一种基于发布/订阅模式的"轻量级"通讯协议。它最大优点在于,可以以极少的代码和有限的带宽,为连接远程设备提供实时可靠的消息服务。作为一种低开销、低带宽占用的即时通讯协议,使其在物联网、小型设备、移动应用等方面有较广泛的应用。

        瑞芯微RK3568芯片是一款定位中高端的通用型SOC,主要面向物联网、NVR存储、工控平板、工业检测、云终端、车载中控等行业定制市场。本人移植MQTT到RK3568的目的是将飞凌的RK3568开发板作为一个物联网的终端,来实时采集相关数据(例如:温度等)。

本次移植的软硬件环境如下:

  • 开发环境操作系统: Ubuntu 18.04 64位
  • 开发环境工具:Qt 5.14.2
  • 交叉工具链:aarch64-linux-gnu
  • 开发板芯片:飞凌 RK3568-C
  • 开发板内核:linux-4.1.19
  • 手机端工具:MQTT Dashboard

一、下载qmqtt源码

 github官网下载qmqtt源码(地址GitHub - emqx/qmqtt: MQTT client for Qt)。

下载完成后, 解压qmqtt-master.zip到本地文件夹。

forlinx@ubuntu:~/3568/mqtt$ sudo unzip qmqtt-master.zip

forlinx@ubuntu:~/3568/mqtt/qmqtt-master$ ls
CMakeLists.txt  examples      qmqtt.pri  README.md     tests
edl-v10         LICENSE       qmqtt.pro  src
epl-v10         qmqtt-API.md  qmqtt.qbs  sync.profile

二、编译库文件

 启动Qt-5.14.2,打开qmqtt.pro,配置为rk3568交叉编译环境,编译为Release下的message库。

 修改qmqtt-master/src/mqtt/qmqtt.pro配置文件,设置设置库文件的输出目录为mqtt_lib。

# qmqtt-master/src/mqtt/qmqtt.pro

TARGET = QtQmqtt
QT = core network
qtHaveModule(websockets): QMQTT_WEBSOCKETS: QT += websockets

DEFINES += QT_NO_CAST_TO_ASCII QT_NO_CAST_FROM_ASCII

# CONFIG += QMQTT_NO_SSL

HEADERS += \
    $$PWD/qmqtt_global.h \
    $$PWD/qmqtt.h

include(qmqtt.pri)

HEADERS += $$PUBLIC_HEADERS $$PRIVATE_HEADERS

load(qt_module)

# Set the output directory of library files
DESTDIR = $$MODULE_BASE_OUTDIR/../mqtt_lib

编译完成后,在mqtt_lib目录下生成库文件libQt5Qmqtt.so.1.0.2,详细查看如下:

root@ubuntu:/home/forlinx/3568/mqtt/mqtt_lib# ls -all
total 6540
drwxr-xr-x 3 root root    4096 Mar 11 18:19 .
drwx------ 4 root root    4096 Mar 11 18:26 ..
-rw-r--r-- 1 root root     809 Mar 11 18:26 libQt5Qmqtt.la
-rw-r--r-- 1 root root    1651 Mar 11 18:26 libQt5Qmqtt.prl
lrwxrwxrwx 1 root root      20 Mar 11 18:19 libQt5Qmqtt.so -> libQt5Qmqtt.so.1.0.2
lrwxrwxrwx 1 root root      20 Mar 11 18:19 libQt5Qmqtt.so.1 -> libQt5Qmqtt.so.1.0.2
lrwxrwxrwx 1 root root      20 Mar 11 18:19 libQt5Qmqtt.so.1.0 -> libQt5Qmqtt.so.1.0.2
-rwxr-xr-x 1 root root  285448 Mar 11 18:19 libQt5Qmqtt.so.1.0.2
-rw-r--r-- 1 root root 6388344 Mar 11 18:19 libQt5Qmqtt.so.1.0.2.debug
drwxr-xr-x 2 root root    4096 Mar 11 18:19 pkgconfig

三、移植到RK3568

3.1 移植动态库libQt5Qmqtt

复制Ubuntu18.04下交叉编译出的动态库libQt5Qmqtt.so.1.0.2,放到开发板/usr/lib目录下并对应的配置软链接。

cd /usr/lib
sudo ln -s libQt5Qmqtt.so.1.0.2 libQt5Qmqtt.so
sudo ln -s libQt5Qmqtt.so.1.0.2 libQt5Qmqtt.so.1
sudo ln -s libQt5Qmqtt.so.1.0.2 libQt5Qmqtt.so.1.0

若未正确配置软链接,则启动app客户端时会出现错误:

./mqtt_demo: error while loading shared libraries: libQt5Qmqtt.so.1: cannot open shared object file: No such file or directory

四、联机测试

4.1 制作demo

4.1.1 创建demo新项目

创建一个Widget应用程序,其控件布局如下:

4.1.2 添加network模块支持

在mqtt_demo项目的pro文件中添加对网络模块的支持。

QT += network

4.1.3 添加qmqtt外部库

库文件位于mqtt_lib下,mqtt头文件位于源码的src/mqtt目录下,浏览到对应的目录,即可。

 

4.1.4 功能实现

演示工具的源码已上传到github,链接地址:GitHub - lingdan2008/mqtt_demo

mqtt_demo.pro文件

QT       += core gui network

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++11

# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    main.cpp \
    widget.cpp

HEADERS += \
    widget.h

FORMS += \
    widget.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target



unix:!macx: LIBS += -L$$PWD/../../mqtt_lib/ -lQt5Qmqtt

INCLUDEPATH += $$PWD/../../qmqtt-master/src/mqtt
DEPENDPATH += $$PWD/../../qmqtt-master/src/mqtt

widget.h文件

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

// add necessary includes here
#include <qmqtt.h>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private slots:
    void on_pushButton_Connect_clicked();

    void on_pushButton_Subscribe_clicked();

    void on_pushButton_Publish_clicked();


    void slotConnectedMQTT();

    void slotDisconnectedMQTT();

    void slotSubscribedMQTT(QString sTopic, quint8 qos = 0);

    void slotReceivedMessageByMQTT(QMQTT::Message sMsg);

private:
    Ui::Widget *ui;

    // the mqtt client pointer
    QMQTT::Client *m_pMQTT = nullptr;
};
#endif // WIDGET_H

 widget.cpp文件

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    this->setWindowTitle(tr("MQTT Demo"));

    ui->pushButton_Connect->setEnabled(true);
    ui->pushButton_Publish->setEnabled(false);
    ui->pushButton_Subscribe->setEnabled(false);
}

Widget::~Widget()
{
    delete ui;
}


void Widget::on_pushButton_Connect_clicked()
{
    if(tr("Connect") == ui->pushButton_Connect->text().trimmed()) {
        ui->pushButton_Publish->setEnabled(true);
        ui->pushButton_Subscribe->setEnabled(true);

        ui->pushButton_Connect->setText(tr("Disconnect"));

        QString sHost = ui->lineEdit_Host->text().trimmed();
        int nPort = ui->lineEdit_Port->text().trimmed().toInt();

        // Create a QMQTT client
        if(nullptr == m_pMQTT) {
            m_pMQTT = new QMQTT::Client(QHostAddress(sHost), nPort);
            Q_ASSERT(m_pMQTT);
        }

        // Signal-slot initialization
        std::vector<bool> vecConnect;

        vecConnect.push_back(QObject::connect(m_pMQTT, SIGNAL(connected()), this, SLOT(slotConnectedMQTT())));
        vecConnect.push_back(QObject::connect(m_pMQTT, SIGNAL(disconnected()), this, SLOT(slotDisconnectedMQTT())));
        vecConnect.push_back(QObject::connect(m_pMQTT, SIGNAL(subscribed(QString, quint8)), this, SLOT(slotSubscribedMQTT(QString, quint8))));
        vecConnect.push_back(QObject::connect(m_pMQTT, SIGNAL(received(QMQTT::Message)), this, SLOT(slotReceivedMessageByMQTT(QMQTT::Message))));

        for(int i=0; i<(int)vecConnect.size(); i++) {
            Q_ASSERT(vecConnect.at(i));
        }

        // Connect to host
        m_pMQTT->setCleanSession(true);
        m_pMQTT->connectToHost();
    }
    else {
        ui->pushButton_Publish->setEnabled(false);
        ui->pushButton_Subscribe->setEnabled(false);

        ui->pushButton_Connect->setText(tr("Connect"));
        m_pMQTT->disconnectFromHost();

        delete m_pMQTT;
        m_pMQTT = nullptr;
    }



}

void Widget::on_pushButton_Subscribe_clicked()
{
    // Subscribe a topic
    QString sTopic = ui->lineEdit_SubscribeTopic->text().trimmed();
    m_pMQTT->subscribe(sTopic, 1);
}

void Widget::on_pushButton_Publish_clicked()
{
    // Publish a topic
    QMQTT::Message sMsg;
    QString sTopic = ui->lineEdit_PublishTopic->text().trimmed();
    QString sContent = ui->lineEdit_PublishContent->text().trimmed();

    sMsg.setTopic(sTopic);
    sMsg.setPayload(sContent.toLocal8Bit());

    m_pMQTT->publish(sMsg);
}

void Widget::slotConnectedMQTT()
{
    ui->textBrowser_ReceivedMessage->append(tr("Connection succeeded"));
}

void Widget::slotDisconnectedMQTT()
{
    ui->textBrowser_ReceivedMessage->append(tr("Connection disconnected"));
}

void Widget::slotSubscribedMQTT(QString sTopic,quint8 qos)
{
    Q_UNUSED(sTopic);
    Q_UNUSED(qos);

    QString sMsg = "Subscribe Topic ";
    sMsg += ui->lineEdit_SubscribeTopic->text();
    sMsg += " Succeeded";
    ui->textBrowser_ReceivedMessage->append(sMsg);
}

void Widget::slotReceivedMessageByMQTT(QMQTT::Message sMsg)
{
    QString sPayload = sMsg.payload();
    QString sMsgTotal = "Topic:";

    sMsgTotal += sMsg.topic();
    sMsgTotal += " Payload:";
    sMsgTotal += sPayload;

    ui->textBrowser_ReceivedMessage->append(sMsgTotal);
}

4.1.5 编译与发布

使用3568 Kit交叉编译后得到mqtt_demo,并将其发布到开发板。

4.2 移植与测试

4.2.1 启动应用程序

cd /home/forlinx/work/example/mqtt
sudo ./mqtt_dem

 

4.2.2 联合测试

(1)搭建MQTT服务器,

        启动MQTT服务器,可参阅我的博客linux下搭建MQTT服务

(2)启动MQTT Dashboard

        从Google Paly商店下载,安装到手机后,连接MQTT服务器后,即可在手机端监控开发板。

(3)连接网络

(4)运行demo

        在demo上配置服务器IP、端口、订阅主题、发布主题和发布内容,执行连接、订阅和发布,演示效果如下图所示:

 


总结

至此,云服务器、RK3568和手机端通过了联合测试,它们组成了一个小型的物联网智能监控系统,通过MQTT轻松的实现了物联网,很有成就感!已经深夜了,周末可以安心睡个好觉了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值