Qt在工业上的使用场景包括工业自动化、嵌入式系统、汽车行业、航空航天、医疗设备、制造业和物联网应用。Qt被用来开发工业设备的用户界面、控制系统、嵌入式应用和其他工业应用,因其跨平台性和丰富的功能而备受青睐。
Qt能够为工业领域带来什么好处:
- Qt提供了强大的图形引擎,使开发人员能够创建具有吸引力和高性能的用户界面。
- Qt允许开发人员根据具体需求定制用户界面和功能。这对于满足不同行业和项目的独特需求至关重要,使工业应用能够实现个性化的解决方案
- Qt提供了丰富的库和工具,涵盖了各种应用程序开发需求,包括图形、网络通信、多媒体处理、数据存储等。这简化了工业应用程序的开发流程
- Qt可以轻松与各种硬件设备和通信协议集成,这对于工业自动化和控制系统来说非常重要,因为它们需要与各种传感器、执行器和其他工业设备进行通信
本次开发教程的测试板卡来自创龙科技的TLT113-EVM国产工业评估板,基于全志科技T113-i双核ARM Cortex-A7 + 玄铁C906 RISC-V + HiFi4 DSP异构多核处理器设计,ARM Cortex-A7处理器单元主频高达1.2GHz。
评估板由核心板和评估底板组成,核心板CPU、ROM、RAM、电源、晶振等所有元器件均采用国产工业级方案,国产化率100%。同时,评估底板大部分元器件亦采用国产工业级方案。核心板经过专业的PCB Layout和高低温测试验证,稳定可靠,可满足各种工业应用环境。
T113-i国产工业评估板硬件资源图解
此外,T113-i国产工业开发板的接口资源丰富,能够支持引出双路网口、双路CAN、双路USB、双路RS485、RS232等通信接口,同时引出LVDS LCD、TFT LCD、MIPI LCD、HDMI OUT、CVBS IN/OUT、LINE IN、MIC IN、H/P OUT等音视频多媒体接口,板载WIFI、4G(选配)模块,支持1080P@60fps JPEG/MJPEG视频硬件编码,支持4K@30fps H.265、4K@24fps H.264视频硬件解码,方便用户快速进行产品方案评估与技术预研。
接下来我们来聊聊如何在创龙科技T113-i工业开发板上部署Qt应用。
开发板Qt运行环境
开发板SDK准备
创龙科技的资料中提供了开发板的SDK-T113-i_v1.0.tar.gz,需要解压ubuntu中解压出来:
rice@rice:~$ mkdir t113 //创建t113工作目录,然后将压缩包拷贝到此目录 rice@rice:~$ cd t113 .... rice@rice:~/t113$ tar -zxvf SDK-T113-i_v1.0.tar.gz rice@rice:~/t113$ cd T113-i_v1.0/ rice@rice:~/t113/T113-i_v1.0$ ls brandy buildroot device install_tools.sh out rtos-dsp tools build build.sh kernel platform test
安装依赖软件,创龙科技提供了安装脚本:install_tools.sh,我们执行该脚本即可完成依赖工具的安装:
rice@rice:~/t113/T113-i_v1.0$ ./install_tools.sh [sudo] password for rice: Reading package lists... Done Building dependency tree Reading state information... Done texinfo is already the newest version (6.5.0.dfsg.1-2). 0 upgraded, 0 newly installed, 0 to remove and 121 not upgraded. Reading package lists... Done Building dependency tree Reading state information... Done pkg-config is already the newest version (0.29.1-0ubuntu2). 0 upgraded, 0 newly installed, 0 to remove and 121 not upgraded. Reading package lists... Done ......
解压Buildroot dl--dl.tar.gz,其为 Buildroot dl 目录压缩包,用于存放从官网下载的开源软件包:
rice@rice:~/t113$ tar -xvf dl.tar.gz -C ~/t113/buildroot/buildroot-201902/
构建Qt固件
在编译固件前,先清理一下SDK的编译和配置生成文件:
rice@rice:~/t113/T113-i_v1.0$ ./build.sh distclean
配置linux内核,处理器型号,显示方式,编译器等信息
rice@rice:~/t113/T113-i_v1.0$ ./build.sh config Welcome to mkscript setup progress All available platform: 0. linux Choice [linux]: 0 All available linux_dev: 0. bsp 1. dragonboard 2. longan 3. tinyos Choice [longan]: 2 All available kern_ver: 0. linux-5.4 Choice [linux-5.4]: 0 All available ic: 0. t113 1. t113_i Choice [t113_i]: 1 All available board: 0. evb1 1. evb1_auto 2. evb1_auto_nand 3. evb1_auto_nor 4. tlt113-evm-emmc 5. tlt113-evm-nand 6. tlt113-minievm-emmc 7. tlt113-minievm-nand Choice [tlt113-evm-nand]: 5 All available output_configs: 0. hdmi 1. lvds-lcd 2. mipi-lcd 3. tft-lcd 4. cvbs Choice [hdmi]: 0 All available flash: 0. default 1. nor Choice [default]: 0 All available build_root: 0. buildroot-201902 1. ubuntu Choice [buildroot-201902]: 0 All available gnueabi: 0. gnueabi 1. gnueabihf Choice [gnueabi]: 0
设置编译的环境变量:
rice@rice:~/t113/T113-i_v1.0$ source ./build/envsetup.sh
我们采用一键编译 SPL、U-Boot、Linux 内核和 buildroot文件系统。
rice@rice:~/t113/T113-i_v1.0$ ./build.sh ACTION List: mklichee;======== Execute command: mklichee INFO: ---------------------------------------- INFO: build lichee ... INFO: chip: sun8iw20p1 INFO: platform: linux INFO: kernel: linux-5.4 INFO: board: tlt113-evm-nand INFO: output: /home/rice/t113/T113-i_v1.0/out/t113_i/tlt113-evm-nand/longan INFO: ---------------------------------------- INFO: build buildroot ... Prepare br toolchain gcc-linaro-5.3.1-2016.05-x86_64_arm-linux-gnueabi.tar.xz... make: Entering directory '/home/rice/t113/T113-i_v1.0/buildroot/buildroot-201902' ...
编译Qt库,使其开发板固件支持Qt应用运行环境:
rice@rice:~/t113/T113-i_v1.0$ ./build.sh qt ACTION List: mkqt;======== Execute command: mkqt INFO: build Qt ... INFO: build arm-linux-gnueabi version's Qt /home/rice/t113/T113-i_v1.0/platform/framework/qt/qt-everywhere-src-5.12.5 Using built-in specs. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/7/lto-wrapper OFFLOAD_TARGET_NAMES=nvptx-none OFFLOAD_TARGET_DEFAULT=1 Target: x86_64-linux-gnu Configured with: ../src/configure -v --with-pkgversion='Ubuntu 7.5.0-3ubuntu1~18.04' --with-bugurl=file:///usr/share/doc/gcc-7/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++ --prefix=/usr --with-gcc-major-version-only --program-suffix=-7 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --enable-default-pie --with-system-zlib --with-target-system-zlib --enable-objc-gc=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu Thread model: posix .....
打包系统镜像文件,执行之后,可以看到生成的固件文件,它默认生成两个版本的固件,分别是:nand固件和SD卡固件,我们是采用SD卡启动,所以使用SD卡固件。
rice@rice:~/t113/T113-i_v1.0$ ./build.sh pack ACTION List: mkpack ;======== Execute command: mkpack INFO: packing firmware ... INFO: Use BIN_PATH: /home/rice/t113/T113-i_v1.0/device/config/chips/t113_i/bin copying tools file copying configs file copying product configs file /home/rice/t113/T113-i_v1.0/out/pack_out/aultls32.fex /home/rice/t113/T113-i_v1.0/out/pack_out/aultools.fex /home/rice/t113/T113-i_v1.0/out/pack_out/boot_package.cfg /home/rice/t113/T113-i_v1.0/out/pack_out/boot_package.fex ...... dsp0.fex Len: 0x3fc78 Vdsp0.fex Len: 0x4 BuildImg 0 Dragon execute image.cfg SUCCESS ! ----------image is at---------- size:613M /home/rice/t113/T113-i_v1.0/out/t113_i_linux_tlt113-evm-nand-sdboot_uart0.img pack finish
运行环境验证
下载运行实例
将编译打包后的固件(t113_i_linux_tlt113-evm-nand-sdboot_uart0.img)放到windows上,通过工具PhoenixCard.exe烧录到SD卡上。将SD卡插到读卡器上,然后插进电脑:
创龙科技提供了qt的demo,我们将led_control的实例拷贝到板子上:
rice@rice:~/t113/qt-demos/led_control/bin$ scp led_control root@ip:~/
创龙T113-i上运行实例
关闭默认的Qt运行程序,设置qt的环境变量
root@T113-Tronlong:~# killall Launcher root@T113-Tronlong:~# source /etc/qtenv.sh add /dev/input/event1 to Qt Application. find qt5 installed done
运行实例验证Qt功能,运行效果如图:
root@T113-Tronlong:~# ./led_control
Qt开发环境
开发环境下载
Qt开发环境下载,作者是使用Qt 5.12.0,下载链接:https://download.qt.io/archive/qt/5.12/5.12.0/,Ubuntu需要下载:qt-opensource-linux-x64-5.12.0.run
开发环境交叉编译环境配置
配置Debuggers
点击菜单栏"Tools -> Options"
击"Kits -> Debuggers -> Add -> Browse…"
选择目标平台的GDB,路径:/home/rice/t113/T113-i_v1.0/out/t113_i/tlt113-evm-nand/longan/buildroot/host/usr/bin/arm-linux-gnueabi-gdb
配置交叉工具链
点击菜单栏"Tools -> Options"
击"Kits -> Compilers -> Add -> GCC -> C++ -> Browse…"
选择目标平台的交叉工具链,路径:/home/rice/t113/T113-i_v1.0/out/t113_i/tlt113-evm-nand/longan/buildroot/host/usr/bin/arm-linux-gnueabi-g++
配置Qt Versions
点击菜单栏"Tools -> Options"
击"Kits -> Qt Versions -> Add -> GCC -> C++ -> Browse…"
选择目标平台的Qt Versions,路径:/home/rice/t113/T113-i_v1.0/platform/framework/qt/qt-everywhere-src-5.12.5/Qt_5.12.5/bin/qmake
配置Kits
点击菜单栏"Tools -> Options"
击"Kits -> Kits"
将 Name 修改为"T113",Device type 选择"Generic Linux Device",Compiler 的 C++选择"T113-GCC",Debugger 选择"T113-Debugger",Qt version 选择"T113-qt5",点击 Apply,然后点击 OK 完成配置
开发Qt应用
作者开发了一个快速验证硬件功能的,主要功能包含:
板载LED灯控制,代码实现:
static QString ledPath = "/sys/class/leds/user-led0"; void rice::ledInit() { setLedStatus(0); ui->ledPushButton->setText("LED OFF"); ui->ledPushButton->setStyleSheet("border-width:1px;" "border-style:solid; " "border-color:white;" "background-color:rgba(88, 88, 88, 200)"); } void rice::ledDeinit() { } bool rice::setLedStatus(int status) { QString cmd = "echo " + QString::number(status) + " > " + ledPath + "/brightness"; if (system(cmd.toStdString().c_str()) == -1) { printf("set led status failed! "); return false; } return true; } int rice::getLedStatus(void) { QString cmd = "cat " + ledPath + "/brightness"; FILE *fp = popen(cmd.toStdString().c_str(), "r"); if (fp == nullptr) { return -1; } char led_status[32]; if (fgets(led_status, sizeof(led_status), fp) == nullptr) { printf("fgets error: %s ", cmd.toStdString().c_str()); pclose(fp); return -1; } pclose(fp); return atoi(led_status); } void rice::on_ledPushButton_clicked() { int ledStatus = getLedStatus(); if (ledStatus == 0) { setLedStatus(1); ui->ledPushButton->setText("LED ON"); ui->ledPushButton->setStyleSheet("border-width:1px;" "border-style:solid; " "border-color:white;" "background-color:rgba(00, 205, 00, 255)"); } else { setLedStatus(0); ui->ledPushButton->setText("LED OFF"); ui->ledPushButton->setStyleSheet("border-width:1px;" "border-style:solid; " "border-color:white;" "background-color:rgba(88, 88, 88, 200)"); } }
板载按键检测,代码实现:
void rice::keyInit() { keyFd = open(keyPath.toUtf8().data(), O_RDONLY); if(keyFd == -1) { printf("Can not open file(%s)", keyPath.toUtf8().data()); return; } ui->keyTextEdit->append("Key Monitor! "); ui->keyTextEdit->append("Key user0 pressed!"); keyNotify = new QSocketNotifier(this->keyFd, QSocketNotifier::Read, this); connect(this->keyNotify, SIGNAL(activated(int)), this, SLOT(keyHandler())); } void rice::keyDeinit() { } void rice::keyHandler() { struct input_event buf; if(read(keyFd, &buf, sizeof(struct input_event)) > 0) { if(buf.code == KEY_PROG1 && buf.value == 1) { ui->keyTextEdit->append("Key user0 pressed!"); } } }
RTC时钟获取并显示,代码实现:
void rice::dateInit() { struct rtc_time rtc_tm_temp; dateFd = open(datePath.toUtf8().data(), O_RDONLY); if(dateFd == -1) { printf("Can not open file(%s)", keyPath.toUtf8().data()); return; } if(ioctl(dateFd, RTC_RD_TIME, &rtc_tm_temp) < 0) { printf("Get date failed"); return; } ui->yearLineEdit->setText(QString::number(rtc_tm_temp.tm_year + 1900)); ui->monthLineEdit->setText(QString::number(rtc_tm_temp.tm_mon + 1)); ui->dayLineEdit->setText(QString::number(rtc_tm_temp.tm_mday)); } void rice::dateDeint() { }
网络调试助手,代码实现:
void rice::netInit() { server = new QTcpServer(); socket = new QTcpSocket(); } void rice::netDeint() { } void rice::netNewClientConnect() { socket = server->nextPendingConnection(); connect(socket, &QTcpSocket::readyRead, this, &rice::netNewRcve); } void rice::on_netPushButton_clicked() { int port = ui->portLineEdit->text().toInt(); if(ui->netPushButton->text() == tr("Open")) { if(ui->typeComboBox->currentText() == tr("Server")) { connect(server, &QTcpServer::newConnection, this, &rice::netNewClientConnect); if(!server->listen(QHostAddress::Any, port)) { printf("Listen failed "); return; } } else if(ui->typeComboBox->currentText() == tr("Client")) { QString ip = ui->ipComboBox->currentText(); socket->abort(); socket->connectToHost(ip, port); if(!socket->waitForConnected(3000)) { printf("Connect server failed"); return; } connect(socket, &QTcpSocket::readyRead, this, &rice::netNewRcve); } ui->netPushButton->setText("Close"); } else if(ui->netPushButton->text() == tr("Close")) { if(ui->typeComboBox->currentText() == tr("Server")) { socket->abort(); server->close(); } else if(ui->typeComboBox->currentText() == tr("Client")) { socket->disconnectFromHost(); } ui->netPushButton->setText("Open"); } } void rice::on_sendPushButton_clicked() { if(socket->isOpen()) { socket->write(ui->sendLineEdit->text().toUtf8().data()); } } void rice::netNewRcve() { ui->recvTextEdit->append(socket->readAll()); } void rice::on_typeComboBox_currentIndexChanged(const QString &arg1) { if(arg1 == tr("Server")) { ui->ipComboBox->setEditable(false); } else { ui->ipComboBox->setEditable(true); } }
Qt应用验证
板载LED灯控制验证,当点击开关LED按钮时,LED灯会根据状态亮灭:
当应用运行起来时,会获取RTC时间,并显示:
当板载按键按下时,窗口会显示按键按下:
网络调试助手支持TCP客户端和TCP服务器两种类型,下面演示服务器验证。开发板上设置板子的IP,和端口号,然后通过PC上网络调试助手连接上板子,并克实现数据的收发:
客户端往服务器发送数据
服务器往客户端发送数据
本文转载自Rice嵌入式
全部0条评论
快来发表一下你的评论吧 !