1. Linux Qt串口助手开发实战:从零到嵌入式部署
最近在i.MX6UL开发板上实现了一个Qt串口助手工具,整个过程涉及Qt界面编程、串口通信、交叉编译等多个技术环节。这个项目非常适合想要学习嵌入式Qt开发的工程师,下面我将完整分享开发过程和关键实现细节。
2. 项目环境准备与基础配置
2.1 开发环境搭建
在开始编码前,需要准备好以下开发环境:
- 主机开发环境:Ubuntu 20.04 LTS
- Qt版本:Qt 5.12.8
- 开发板:正点原子i.MX6UL开发板
- 交叉编译工具链:arm-linux-gnueabihf-gcc
提示:建议使用与教程相同的Qt版本,避免因版本差异导致兼容性问题
2.2 创建Qt项目并添加串口支持
在Qt Creator中创建Widgets Application项目后,需要在.pro文件中添加串口模块支持:
qmake复制QT += core gui serialport
这个配置会告诉Qt在编译时链接QtSerialPort模块,该模块提供了跨平台的串口通信功能支持。
3. 界面设计与布局实现
3.1 主窗口类设计
MainWindow类继承自QMainWindow,是整个应用的核心。与常规Qt项目不同,这里采用手动创建控件的方式而非使用.ui文件,这种方式在嵌入式开发中更为常见,可以更精确地控制内存使用。
cpp复制class MainWindow : public QMainWindow {
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
// 串口相关成员
QSerialPort *serialPort;
// UI控件
QTextBrowser *textBrowser; // 接收显示区
QTextEdit *textEdit; // 发送输入区
QPushButton *pushButton[2]; // 功能按钮
QComboBox *comboBox[5]; // 参数选择框
QLabel *label[5]; // 标签
// 布局
QVBoxLayout *vboxLayout;
QGridLayout *gridLayout;
// 初始化方法
void layoutInit();
void scanSerialPort();
void baudRateItemInit();
void dataBitsItemInit();
void parityItemInit();
void stopBitsItemInit();
};
3.2 自适应布局实现
考虑到应用需要在不同尺寸的屏幕上运行,布局系统需要具备自适应性:
cpp复制void MainWindow::layoutInit() {
/* 获取屏幕参数实现自适应 */
QList<QScreen *> list_screen = QGuiApplication::screens();
#if __arm__
// 在ARM平台全屏显示
this->resize(list_screen.at(0)->geometry().width(),
list_screen.at(0)->geometry().height());
system("echo none > /sys/class/leds/sys-led/trigger");
#else
// 在PC开发环境固定800x400大小
this->resize(800,400);
#endif
// 控件创建与布局代码...
}
这种条件编译的方式既方便开发时调试,又能确保在目标板上获得最佳显示效果。
4. 串口功能实现详解
4.1 串口参数初始化
串口通信需要配置多个参数,每个参数都需要正确初始化:
cpp复制// 波特率初始化
void MainWindow::baudRateItemInit() {
QList<QString> list;
list<<"1200"<<"2400"<<"4800"
<<"9600"<<"19200"<<"38400"<<"57600"
<<"115200"<<"230400"<<"460800"<<"921600";
for(int i=0;i<11;i++){
comboBox[1]->addItem(list[i]);
}
comboBox[1]->setCurrentIndex(7); // 默认115200
}
// 数据位初始化(5/6/7/8)
// 校验位初始化(无/奇/偶校验等)
// 停止位初始化(1/2)
4.2 串口打开与关闭
串口的打开过程需要配置所有参数,并处理可能的错误:
cpp复制void MainWindow::openSerialPortPushButtonClicked() {
if(pushButton[1]->text() == "打开串口") {
// 配置串口参数
serialPort->setPortName(comboBox[0]->currentText());
serialPort->setBaudRate(comboBox[1]->currentText().toInt());
// 设置数据位(5/6/7/8)
switch(comboBox[2]->currentText().toInt()) {
case 5: serialPort->setDataBits(QSerialPort::Data5); break;
// ...其他case
}
// 尝试打开串口
if(!serialPort->open(QIODevice::ReadWrite)) {
QMessageBox::about(NULL,"error","串口无法打开,可能已经被占用!");
} else {
// 禁用参数修改
for(int i=0;i<5;i++) comboBox[i]->setEnabled(false);
pushButton[1]->setText("关闭串口");
pushButton[0]->setEnabled(true); // 启用发送按钮
}
} else {
// 关闭串口
serialPort->close();
// 恢复UI状态
for(int i=0;i<5;i++) comboBox[i]->setEnabled(true);
pushButton[1]->setText("打开串口");
pushButton[0]->setEnabled(false);
}
}
4.3 数据收发实现
数据发送直接将文本编辑框内容写入串口,接收则通过readyRead信号触发:
cpp复制// 发送数据
void MainWindow::sendPushButtonClicked() {
QByteArray data = textEdit->toPlainText().toUtf8();
serialPort->write(data);
}
// 接收数据
void MainWindow::serialPortReadyRead() {
QByteArray buf = serialPort->readAll();
textBrowser->insertPlainText(QString(buf));
}
注意:在实际应用中,建议对接收数据添加时间戳和hex显示等功能增强实用性
5. 交叉编译与部署
5.1 本地编译测试
在开发过程中,先在x86环境的Ubuntu上进行编译测试:
bash复制qmake
make
./serial_port
这可以快速验证基本功能是否正常,提高开发效率。
5.2 交叉编译配置
针对ARM平台需要配置交叉编译工具链,在Qt Creator中:
- 添加arm-linux-gnueabihf交叉编译器
- 创建Qt for Device配置
- 指定工具链路径和sysroot
或者直接修改qmake配置:
bash复制qmake -spec linux-arm-gnueabihf-g++
make
5.3 开发板部署
将生成的可执行文件拷贝到开发板:
bash复制scp serial_port root@开发板IP:/usr/local/bin/
然后在开发板上运行:
bash复制chmod +x /usr/local/bin/serial_port
./serial_port
6. 常见问题与解决方案
6.1 串口无法打开
可能原因及解决方法:
-
串口被其他程序占用
- 检查是否有其他终端程序正在使用该串口
- 使用
fuser /dev/ttyS*查看占用进程
-
权限不足
- 将用户加入dialout组:
sudo usermod -aG dialout $USER - 或者直接修改权限:
sudo chmod 666 /dev/ttyS*
- 将用户加入dialout组:
6.2 数据传输乱码
排查步骤:
- 确认两端波特率、数据位、校验位设置一致
- 检查文本编码方式(建议统一使用UTF-8)
- 尝试发送简单ASCII字符测试
6.3 界面显示异常
在开发板上可能出现的问题:
-
字体缺失
- 部署Qt字体库到开发板
- 或在代码中指定嵌入式友好字体
-
触摸屏校准
- 使用
ts_calibrate校准触摸屏 - 设置环境变量指定触摸设备
- 使用
7. 功能扩展建议
基础功能实现后,可以考虑添加以下实用功能:
-
Hex显示与发送:
- 添加复选框切换Hex/文本模式
- 实现Hex字符串解析和显示
-
数据记录:
- 添加保存接收数据到文件功能
- 支持按时间自动分割日志文件
-
多语言支持:
- 使用Qt Linguist工具添加多语言
- 根据系统语言自动切换
-
自定义协议解析:
- 添加协议解析框架
- 支持常见串口协议如Modbus
这个Qt串口助手项目涵盖了嵌入式Qt开发的多个关键技术点,包括界面设计、串口通信、交叉编译等。在实际开发过程中,最大的挑战是确保代码在x86开发环境和ARM目标板上都能正常工作。通过条件编译和合理的架构设计,可以很好地解决这个问题。
