• I.MX6U开发板上的Qt串口编程


    真正串口通讯所需的功能是比较多的,此处的上位机只实现发送和接收功能。因为Linux、windows和开发板上均有串口,所以所开发的上位机在其上都是可以运行的。

    1. 资源简介

    在正点原子的 I.MX6U 开发板的出厂系统里,默认已经配置了两路串口可用。一路是调试串口UART1(对应系统里的节点/dev/ttymxc0),另一路是UART3(对应系统里的节点/dev/ttymxc2)。由于 UART1 已经作为调试串口被使用。所以我们只能对 UART3 编程,(如需要使用多路串口,请自行设计底板与系统)。

    2. 应用实例

    2.1 项目简介:

    Qt 串口的使用示例,应用到正点原子 I.MX6U 开发板上。

    2.2 03_serialport.pro

    在 03_serialport.pro 里, 我们需要使用串口,需要在 pro 项目文件中添加串口模块的支持,如下。

    1 # 添加串口模块支持
    2 QT += core gui serialport
    3 4
    greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
    5 6
    CONFIG += c++11
    7 8
    # The following define makes your compiler emit warnings if you use
    9 # any Qt feature that has been marked deprecated (the exact warnings
    10 # depend on your compiler). Please consult the documentation of the
    11 # deprecated API in order to know how to port your code away from it.
    12 DEFINES += QT_DEPRECATED_WARNINGS
    13
    14 # You can also make your code fail to compile if it uses deprecated APIs.
    15 # In order to do so, uncomment the following line.
    16 # You can also select to disable deprecated APIs only up to a certain
    version of Qt.
    17 #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the
    APIs deprecated before Qt 6.0.0
    18
    19 SOURCES += \
    20 main.cpp \
    21 mainwindow.cpp
    22
    23 HEADERS += \
    24 mainwindow.h
    25
    26 # Default rules for deployment.
    27 qnx: target.path = /tmp/$${TARGET}/bin
    28 else: unix:!android: target.path = /opt/$${TARGET}/bin
    29 !isEmpty(target.path): INSTALLS += target
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    第 2 行,添加的 serialport 就是串口模块的支持。

    2.3 mainwindow.h

    在头文件“mainwindow.h”的代码如下。

    1 #ifndef MAINWINDOW_H
    2 #define MAINWINDOW_H
    3 4
    #include 
    5 #include <QSerialPort>
    6 #include <QSerialPortInfo>
    7 #include <QPushButton>
    8 #include <QTextBrowser>
    9 #include <QTextEdit>
    10 #include <QVBoxLayout>
    11 #include <QLabel>
    12 #include <QComboBox>
    13 #include <QGridLayout>
    14 #include <QMessageBox>
    15 #include <QDebug>
    16
    17 class MainWindow : public QMainWindow
    18 {
    19 Q_OBJECT
    20
    21 public:
    22 MainWindow(QWidget *parent = nullptr);
    23 ~MainWindow();
    24
    25 private:
    26 /* 串口对象 */
    27 QSerialPort *serialPort;
    28
    29 /* 用作接收数据 */
    30 QTextBrowser *textBrowser;
    31
    32 /* 用作发送数据 */
    33 QTextEdit *textEdit;
    34
    35 /* 按钮 */
    36 QPushButton *pushButton[2];
    37
    38 /* 下拉选择盒子 */
    39 QComboBox *comboBox[5];
    40
    41 /* 标签 */
    42 QLabel *label[5];
    43
    44 /* 垂直布局 */
    45 QVBoxLayout *vboxLayout;
    46
    47 /* 网络布局 */
    48 QGridLayout *gridLayout;
    49
    50 /* 主布局 */
    51 QWidget *mainWidget;
    52
    53 /* 设置功能区域 */
    54 QWidget *funcWidget;
    55
    56 /* 布局初始化 */
    57 void layoutInit();
    58
    59 /* 扫描系统可用串口 */
    60 void scanSerialPort();
    61
    62 /* 波特率项初始化 */
    63 void baudRateItemInit();
    64
    65 /* 数据位项初始化 */
    66 void dataBitsItemInit();
    67
    68 /* 检验位项初始化 */
    69 void parityItemInit();
    70
    71 /* 停止位项初始化 */
    72 void stopBitsItemInit();
    73
    74 private slots:
    75 void sendPushButtonClicked();
    76 void openSerialPortPushButtonClicked();
    77 void serialPortReadyRead();
    78 };
    79 #endif // MAINWINDOW_H
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79

    上面代码是在 mianwindow.h 里声明需要用到的变量,方法及槽函数。

    2.4 mainwindow.cpp

    mainwindow.cpp 的代码如下。

    1 #include "mainwindow.h"
    2 #include <QDebug>
    3 #include <QGuiApplication>
    4 #include <QScreen>
    5 #include <QRect>
    6 7
    MainWindow::MainWindow(QWidget *parent)
    8 : QMainWindow(parent)
    9 {
    10 /* 布局初始化 */
    11 layoutInit();
    12
    13 /* 扫描系统的串口 */
    14 scanSerialPort();
    15
    16 /* 波特率项初始化 */
    17 baudRateItemInit();
    18
    19 /* 数据位项初始化 */
    20 dataBitsItemInit();
    21
    22 /* 检验位项初始化 */
    23 parityItemInit();
    24
    25 /* 停止位项初始化 */
    26 stopBitsItemInit();
    27 }
    28
    29 void MainWindow::layoutInit()
    30 {
    31 /* 获取屏幕的分辨率, Qt 官方建议使用这
    32 * 种方法获取屏幕分辨率,防上多屏设备导致对应不上
    33 * 注意,这是获取整个桌面系统的分辨率
    34 */
    35 QList <QScreen *> list_screen = QGuiApplication::screens();
    36
    37 /* 如果是 ARM 平台,直接设置大小为屏幕的大小 */
    38 #if __arm__
    39 /* 重设大小 */
    40 this->resize(list_screen.at(0)->geometry().width(),
    41 list_screen.at(0)->geometry().height());
    42 #else
    43 /* 否则则设置主窗体大小为 800x480 */
    44 this->resize(800, 480);
    45 #endif
    46 /* 初始化 */
    47 serialPort = new QSerialPort(this);
    48 textBrowser = new QTextBrowser();
    49 textEdit = new QTextEdit();
    50 vboxLayout = new QVBoxLayout();
    51 funcWidget = new QWidget();
    52 mainWidget = new QWidget();
    53 gridLayout = new QGridLayout();
    54
    55 /* QList 链表,字符串类型 */
    56 QList <QString> list1;
    57 list1<<"串口号:"<<"波特率:"<<"数据位:"<<"检验位:"<<"停止位:";
    58
    59 for (int i = 0; i < 5; i++) {
    60 label[i] = new QLabel(list1[i]);
    61 /* 设置最小宽度与高度 */
    62 label[i]->setMinimumSize(80, 30);
    63 /* 自动调整 label 的大小 */
    64 label[i]->setSizePolicy(
    65 QSizePolicy::Expanding,
    66 QSizePolicy::Expanding
    67 );
    68 /* 将 label[i]添加至网格的坐标(0, i) */
    69 gridLayout->addWidget(label[i], 0, i);
    70 }
    71
    72 for (int i = 0; i < 5; i++) {
    73 comboBox[i] = new QComboBox();
    74 comboBox[i]->setMinimumSize(80, 30);
    75 /* 自动调整 label 的大小 */
    76 comboBox[i]->setSizePolicy(
    77 QSizePolicy::Expanding,
    78 QSizePolicy::Expanding
    79 );
    80 /* 将 comboBox[i]添加至网格的坐标(1, i) */
    81 gridLayout->addWidget(comboBox[i], 1, i);
    82 }
    83
    84 /* QList 链表,字符串类型 */
    85 QList <QString> list2;
    86 list2<<"发送"<<"打开串口";
    87
    88 for (int i = 0; i < 2; i++) {
    89 pushButton[i] = new QPushButton(list2[i]);
    90 pushButton[i]->setMinimumSize(80, 30);
    91 /* 自动调整 label 的大小 */
    92 pushButton[i]->setSizePolicy(
    93 QSizePolicy::Expanding,
    94 QSizePolicy::Expanding
    95 );
    96 /* 将 pushButton[0]添加至网格的坐标(i, 5) */
    97 gridLayout->addWidget(pushButton[i], i, 5);
    98 }
    99 pushButton[0]->setEnabled(false);
    100
    101 /* 布局 */
    102 vboxLayout->addWidget(textBrowser);
    103 vboxLayout->addWidget(textEdit);
    104 funcWidget->setLayout(gridLayout);
    105 vboxLayout->addWidget(funcWidget);
    106 mainWidget->setLayout(vboxLayout);
    107 this->setCentralWidget(mainWidget);
    108
    109 /* 占位文本 */
    110 textBrowser->setPlaceholderText("接收到的消息");
    111 textEdit->setText("www.openedv.com");
    112
    113 /* 信号槽连接 */
    114 connect(pushButton[0], SIGNAL(clicked()),
    115 this, SLOT(sendPushButtonClicked()));
    116 connect(pushButton[1], SIGNAL(clicked()),
    117 this, SLOT(openSerialPortPushButtonClicked()));
    118
    119 connect(serialPort, SIGNAL(readyRead()),
    120 this, SLOT(serialPortReadyRead()));
    121 }
    122
    123 void MainWindow::scanSerialPort()
    124 {
    125 /* 查找可用串口 */
    126 foreach (const QSerialPortInfo &info,
    127 QSerialPortInfo::availablePorts()) {
    128 comboBox[0]->addItem(info.portName());
    129 }
    130 }
    131
    132 void MainWindow::baudRateItemInit()
    133 {
    134 /* QList 链表,字符串类型 */
    135 QList <QString> list;
    136 list<<"1200"<<"2400"<<"4800"<<"9600"
    137 <<"19200"<<"38400"<<"57600"
    138 <<"115200"<<"230400"<<"460800"
    139 <<"921600";
    140 for (int i = 0; i < 11; i++) {
    141 comboBox[1]->addItem(list[i]);
    142 }
    143 comboBox[1]->setCurrentIndex(7);
    144 }
    145
    146 void MainWindow::dataBitsItemInit()
    147 {
    148 /* QList 链表,字符串类型 */
    149 QList <QString> list;
    150 list<<"5"<<"6"<<"7"<<"8";
    151 for (int i = 0; i < 4; i++) {
    152 comboBox[2]->addItem(list[i]);
    153 }
    154 comboBox[2]->setCurrentIndex(3);
    155 }
    156
    157 void MainWindow::parityItemInit()
    158 {
    159 /* QList 链表,字符串类型 */
    160 QList <QString> list;
    161 list<<"None"<<"Even"<<"Odd"<<"Space"<<"Mark";
    162 for (int i = 0; i < 5; i++) {
    163 comboBox[3]->addItem(list[i]);
    164 }
    165 comboBox[3]->setCurrentIndex(0);
    166 }
    167
    168 void MainWindow::stopBitsItemInit()
    169 {
    170 /* QList 链表,字符串类型 */
    171 QList <QString> list;
    172 list<<"1"<<"2";
    173 for (int i = 0; i < 2; i++) {
    174 comboBox[4]->addItem(list[i]);
    175 }
    176 comboBox[4]->setCurrentIndex(0);
    177 }
    178
    179 void MainWindow::sendPushButtonClicked()
    180 {
    181 /* 获取 textEdit 数据,转换成 utf8 格式的字节流 */
    182 QByteArray data = textEdit->toPlainText().toUtf8();
    183 serialPort->write(data);
    184 }
    185
    186 void MainWindow::openSerialPortPushButtonClicked()
    187 {
    188 if (pushButton[1]->text() == "打开串口") {
    189 /* 设置串口名 */
    190 serialPort->setPortName(comboBox[0]->currentText());
    191 /* 设置波特率 */
    192 serialPort->setBaudRate(comboBox[1]->currentText().toInt());
    193 /* 设置数据位数 */
    194 switch (comboBox[2]->currentText().toInt()) {
    195 case 5:
    196 serialPort->setDataBits(QSerialPort::Data5);
    197 break;
    198 case 6:
    199 serialPort->setDataBits(QSerialPort::Data6);
    200 break;
    201 case 7:
    202 serialPort->setDataBits(QSerialPort::Data7);
    203 break;
    204 case 8:
    205 serialPort->setDataBits(QSerialPort::Data8);
    206 break;
    207 default: break;
    208 }
    209 /* 设置奇偶校验 */
    210 switch (comboBox[3]->currentIndex()) {
    211 case 0:
    212 serialPort->setParity(QSerialPort::NoParity);
    213 break;
    214 case 1:
    215 serialPort->setParity(QSerialPort::EvenParity);
    216 break;
    217 case 2:
    218 serialPort->setParity(QSerialPort::OddParity);
    219 break;
    220 case 3:
    221 serialPort->setParity(QSerialPort::SpaceParity);
    222 break;
    223 case 4:
    224 serialPort->setParity(QSerialPort::MarkParity);
    225 break;
    226 default: break;
    227 }
    228 /* 设置停止位 */
    229 switch (comboBox[4]->currentText().toInt()) {
    230 case 1:
    231 serialPort->setStopBits(QSerialPort::OneStop);
    232 break;
    233 case 2:
    234 serialPort->setStopBits(QSerialPort::TwoStop);
    235 break;
    236 default: break;
    237 }
    238 /* 设置流控制 */
    239 serialPort->setFlowControl(QSerialPort::NoFlowControl);
    240 if (!serialPort->open(QIODevice::ReadWrite))
    241 QMessageBox::about(NULL, "错误",
    242 "串口无法打开!可能串口已经被占用! ");
    243 else {
    244 for (int i = 0; i < 5; i++)
    245 comboBox[i]->setEnabled(false);
    246 pushButton[1]->setText("关闭串口");
    247 pushButton[0]->setEnabled(true);
    248 }
    249 } else {
    250 serialPort->close();
    251 for (int i = 0; i < 5; i++)
    252 comboBox[i]->setEnabled(true);
    253 pushButton[1]->setText("打开串口");
    254 pushButton[0]->setEnabled(false);
    255 }
    256 }
    257
    258 void MainWindow::serialPortReadyRead()
    259 {
    260 /* 接收缓冲区中读取数据 */
    261 QByteArray buf = serialPort->readAll();
    262 textBrowser->insertPlainText(QString(buf));
    263 }
    264
    265 MainWindow::~MainWindow()
    266 {
    267 }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267

    第 29~121 行, 界面布局初始化设置,在嵌入式里,根据实际的屏的大小,设置全屏显示。
    其中我们用到垂直布局和网格布局。
    习布局内容,学以致用理解的时候到了。
    第 123~130 行, 查找系统可用的串口, 并添加串口名到 comboBox[0]中。
    第 132~144 行, 波特率初始化,预设常用的波特率, 115200 作为默认选项。 并添加波特率
    到 comboBox[1]中。
    第 146~155 行, 数据位项初始化,设置默认数据位为 8。
    第 157~166 行, 校验位项初始化,默认无校验位。
    第 168~177 行, 停止位项初始化,默认停止位为 1。
    第 179~184 行, 发送数据,点击发送按钮时触发。
    第 186~256 行, 打开或者关闭串口。以我们设置的项使用 Qt 串口提供的设置串口的方法
    如 setDataBits(QSerialPort::DataBits)等,按第 188~239 行步骤设置完串口需要配置的参数就可以
    打开或者关闭串口了。
    第 258~263 行, 从缓冲区里读出数据,并显示到 textBrowser 里。

    3. 程序运行效果

    下面为 Ubuntu 上仿真界面的效果,请将程序交叉编译后到开发板运行,用串口线连接开发板的 UART3 到电脑串口,在电脑用正点原子的 XCOM 上位机软件(或者本程序亦可当上位机软件),设置相同的串口参数,选择串口号为 ttymxc2 (注意 ttymxc0 已经作为调试串口被使用了!),点击打开串口就可以进行消息收发了。默认参数为波特率为 115200,数据位为 8,校验为 None,停止位为 1,流控为关闭。
    在这里插入图片描述

    4. 串口测试

    关于串口测试的硬件软件,请参考“01【正点原子】I.MX6U用户快速体验V2.6”
    实际测试时,请参考Qt串口编程3-开发板验证,下图是实现了上位机与板卡连接的UI上位机的通讯。
    在这里插入图片描述

    对应地址:Qt串口编程1-上位机界面设计Qt串口编程2-编写程序功能Qt串口编程3-开发板验证

  • 相关阅读:
    【机器学习】安全领域:突破威胁检测的边界
    open clip论文阅读摘要
    DAOS整体设计分析 (一)
    【文生视频】Diffusion Transformer:OpenAI Sora 原理、Stable Diffusion 3 同源技术
    局域网内其他主机无法ip访问我的django网页
    CMakeList 编写示例
    【博学谷学习记录】超强总结,用心分享丨大数据超神之路(五):Hadooop基础篇
    20天深度复习JavaSE的详细笔记(十三)——集合(Set、Collections、Map、集合嵌套)
    Tailwindcss Layout布局相关样式及实战案例,5万字长文,附完整源码和效果截图
    卷积神经网络(CNN)
  • 原文地址:https://blog.csdn.net/Dasis/article/details/133935902