因最近有个客户找我用ZYNQ设计QT界面,通过QT界面去控制LED,然后正好总结一下,供大家参考一下。
制作不易,记得三连哦,给我动力,持续更新!!!
完整工程文件下载:QT界面控制ZYNQ的LED完整工程 (点击蓝色字体获取)
前言
在嵌入式开发中,Zynq平台的强大性能使其成为许多项目的首选。继之前分享的基于Zynq的AXI GPIO按键控制LED实验后,这次我将介绍一个更具交互性的设计:通过Qt界面实现Zynq开发板上4个LED的顺序点亮控制。本文将详细讲解项目的需求、实现过程、代码设计以及调试经验,希望能为有类似需求的开发者提供参考。
项目需求
本次设计的目标是利用Qt开发一个图形界面程序,控制Zynq开发板上的4个LED(2个位于PL端,2个位于PS端),实现以下功能:
- 正序点亮:LED按顺序逐个点亮(pl_led0 → pl_led1 → ps_led0 → ps_led1),每次只有一个LED亮,前一个LED在下一个亮起时熄灭。
- 反序点亮:LED按反序逐个点亮(ps_led1 → ps_led0 → pl_led1 → pl_led0),同样每次只有一个LED亮。
- 可调时间间隔:通过界面输入框设置每个LED的点亮时间,最后一个LED亮起后保持相同时间再熄灭。
- 界面设计:包含“正序点亮”和“反序点亮”两个按钮,以及一个时间间隔输入框。
开发环境
1、开发板:正点原子zynq7020启明星
2、开发软件:vivado2018.3、petalinux2018.3、QT5.9
3、其他:网线、鼠标、键盘、HDMI接口显示器、HDMI线等
如果是同样开发板的小伙伴可以完全抄作业!!
一、软件设计
1.1 vivado工程设计
本工程基于Xilinx Vivado设计套件,采用Block Design方法论实现多接口FPGA系统集成。系统以Zynq-7000系列SoC为核心(或Artix-7等目标器件),主要完成HDMI视频接口的硬件配置,并协同管理串口(UART)、USB 2.0/3.0、以太网(Ethernet)、GPIO(LED)等标准外设接口,其余未指定模块均保持正点原子开发板默认配置。
Block Design架构
1.2 rootfs配置
设置rootfs从SD启动,然后勾选上以下qt和OpenCV软件包
Filesystem Packages ---> libs ---> opencv ---> [*] opencv // opencv Filesystem Packages ---> misc ---> qtbase ---> [*] qtbase // qt [*] qtbase-plugins // qt 相关插件
1.3 设备树配置
硬件环境基于Zynq开发板,LED通过设备树定义为GPIO控制,具体如下:
gpio-led2 {
label = "pl_led0";
gpios = <&gpio0 55 GPIO_ACTIVE_HIGH>;
default-state = "on";
};
gpio-led3 {
label = "pl_led1";
gpios = <&gpio0 56 GPIO_ACTIVE_HIGH>;
default-state = "on";
};
gpio-led4 {
label = "ps_led0";
gpios = <&gpio0 7 GPIO_ACTIVE_HIGH>;
default-state = "on";
};
gpio-led5 {
label = "ps_led1";
gpios = <&gpio0 8 GPIO_ACTIVE_HIGH>;
default-state = "on";
};
二、Qt界面设计
2.1 使用Qt Designer设计了一个简单的界面,
包含:
- 正序点亮按钮:触发正序点亮逻辑。
- 反序点亮按钮:触发反序点亮逻辑。
- 时间间隔输入框:允许用户输入点亮间隔(单位:秒,默认1秒)。
界面布局代码(mainwindow.ui)保持简洁,核心部分如下:
<widget class="QPushButton" name="forwardButton">
<property name="text">
<string>正序点亮</string>
</property>
</widget>
<widget class="QPushButton" name="reverseButton">
<property name="text">
<string>反序点亮</string>
</property>
</widget>
<widget class="QLineEdit" name="intervalEdit">
<property name="text">
<string>1</string>
</property>
</widget>
2.2 核心代码实现
程序使用C++和Qt框架编写,核心逻辑集中在mainwindow.cpp中。以下是关键部分的实现:
初始化与LED控制
void MainWindow::initLeds()
{
for (int i = 0; i < 4; i++) { // 循环遍历4个LED
setLedState(i, false); // 将每个LED设置为熄灭状态
}
}
void MainWindow::setLedState(int ledIndex, bool state)
{
if (ledIndex < 0 || ledIndex >= 4) return; // 检查LED索引是否有效
QString path = QString("/sys/class/leds/%1/brightness").arg(ledNames[ledIndex]); // 构造brightness文件路径
QFile brightnessFile(path); // 创建文件对象
if (!brightnessFile.open(QIODevice::WriteOnly)) { // 尝试打开文件
qDebug() << "Cannot open brightness file for" << ledNames[ledIndex]; // 打开失败则输出错误
return;
}
QTextStream out(&brightnessFile); // 创建文本流
out << (state ? "1" : "0"); // 写入"1"点亮或"0"熄灭
brightnessFile.close(); // 关闭文件
}
- initLeds():初始化时关闭所有LED。
- setLedState():通过写入/sys/class/leds/下的brightness文件控制LED状态。
正反序逻辑
void MainWindow::on_forwardButton_clicked()
{
timer->stop(); // 停止当前定时器
currentLed = 0; // 设置起点为第一个LED
isForward = true; // 设置正序方向
for (int i = 0; i < 4; i++) { // 关闭所有LED
setLedState(i, false);
}
double interval = ui->intervalEdit->text().toDouble(); // 获取用户输入的时间间隔
timer->start(interval * 1000); // 启动定时器(毫秒)
}
void MainWindow::on_reverseButton_clicked()
{
timer->stop(); // 停止当前定时器
currentLed = 3; // 设置起点为最后一个LED
isForward = false; // 设置反序方向
for (int i = 0; i < 4; i++) { // 关闭所有LED
setLedState(i, false);
}
double interval = ui->intervalEdit->text().toDouble(); // 获取用户输入的时间间隔
timer->start(interval * 1000); // 启动定时器(毫秒)
}
- 两个按钮分别设置正序和反序的起点和方向,并根据用户输入启动定时器。
三、上板测试
3.1 添加QT中文显示包
# 检查现有字体
ls /usr/share/fonts/ttf
# 下载字体包
下载网站:https://sourceforge.net/projects/wqy/files/wqy-microhei/0.2.0-beta/wqy-microhei-0.2.0-beta.tar.gz/
# 将下载好的字体,解压缩后放到以下目录
cp -rf wqy-microhei.ttc /usr/share/fonts/ttf
# 更新字体缓存
fc-cache -fv
3.2 设置QT运行环境
export QT_QPA_PLATFORM=linuxfb
3.3 运行QT程序
将生成的QT可执行文件,拷贝到开发板,然后执行
chmod +x Flowing_LED
./Flowing_LED
最终现象如下视频所示,界面设置比较简陋,后期可进行优化
使用Qt实现Zynq开发板上的LED顺序点亮控制
这样一个简单的QT结合ZYNQ的小程序就设计完成了,后期还可以进行优化调整。
制作不易,记得三连哦,给我动力,持续更新!!!