1)实验平台:正点原子阿尔法Linux开发板
2) 章节摘自【正点原子】《I.MX6U 嵌入式Qt开发指南》
3)购买链接:https://detail.tmall.com/item.htm?id=609033604451
4)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/arm-linux/zdyz-i.mx6ull.html
5)正点原子官方B站:https://space.bilibili.com/394620890
6)正点原子阿尔法Linux交流群:1027879335
第十七章 Serial Port
Qt提供了串口类,可以直接对串口访问。我们可以直接使用Qt的串口类编程即可,十分方便。Qt串口类不仅在Windows能用,还能在Linux下用,虽然串口编程不是什么新鲜事儿,既然Qt提供了这方面的接口,我们就充分利用起来,这将会使我们的开发十分方便!其实Qt也提供了相关的Qt串口的例子,我们也可以直接参考来编程,编者根据实际情况,化繁为易,直接写了个简单的例子给大家参考。
17.1 资源简介在正点原子的I.MX6U开发板的出厂系统里,默认已经配置了两路串口可用。一路是调试串口UART1(对应系统里的节点/dev/ttymxc0),另一路是UART3(对应系统里的节点/dev/ttymxc2)。由于UART1已经作为调试串口被使用。所以我们只能对UART3编程,(如需要使用多路串口,请自行设计底板与系统)。
17.2 应用实例项目简介:Qt串口的使用示例,应用到正点原子I.MX6U开发板上。 例03_serialport,Qt串口编程(难度:一般)。项目路径为Qt/3/03_serialport。 在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
复制代码第2行,添加的serialport就是串口模块的支持。 在头文件“mainwindow.h”的代码如下。 - /******************************************************************
- Copyright © Deng Zhimao Co., Ltd. 1990-2021. All rights reserved.
- * @projectName 03_serialport
- * @brief mainwindow.h
- * [url=home.php?mod=space&uid=90321]@Author[/url] Deng Zhimao
- * [url=home.php?mod=space&uid=55957]@EMAIL[/url] 1252699831@qq.com
- * [url=home.php?mod=space&uid=28414]@net[/url] www.openedv.com
- * @date 2021-03-12
- *******************************************************************/
- 1 #ifndef MAINWINDOW_H
- 2 #define MAINWINDOW_H
- 3
- 4 #include <QMainWindow>
- 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
复制代码上面代码是在mianwindow.h里声明需要用到的变量,方法及槽函数。 mainwindow.cpp的代码如下。 - /******************************************************************
- Copyright © Deng Zhimao Co., Ltd. 1990-2021. All rights reserved.
- * @projectName 03_serialport
- * @brief mainwindow.cpp
- * @author Deng Zhimao
- * @email 1252699831@qq.com
- * @net www.openedv.com
- * @date 2021-03-12
- *******************************************************************/
- 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 }
复制代码第29~121行,界面布局初始化设置,在嵌入式里,根据实际的屏的大小,设置全屏显示。其中我们用到垂直布局和网格布局,如果布局这方面内容理解不了,请回到第七章7.5小节学习布局内容,学以致用理解的时候到了。 第123~130行,查找系统可用的串口,并添加串口名到comboBox[0]中。 第132~144行,波特率初始化,预设常用的波特率,115200作为默认选项。并添加波特率到comboBox[1]中。 第146~155行,数据位项初始化,设置默认数据位为8。 第157~166行,校验位项初始化,默认无校验位。 第168~177行,停止位项初始化,默认停止位为1。 第179~184行,发送数据,点击发送按钮时触发。 第186~256行,打开或者关闭串口。以我们设置的项使用Qt串口提供的设置串口的方法如setDataBits(QSerialPort:ataBits)等,按第188~239行步骤设置完串口需要配置的参数就可以打开或者关闭串口了。 第258~263行,从缓冲区里读出数据,并显示到textBrowser里。
17.3 程序运行效果下面为Ubuntu上仿真界面的效果,请将程序交叉编译后到开发板运行,用串口线连接开发板的UART3到电脑串口,在电脑用正点原子的XCOM上位机软件(或者本程序亦可当上位机软件),设置相同的串口参数,选择串口号为ttymxc2(注意ttymxc0已经作为调试串口被使用了!),点击打开串口就可以进行消息收发了。默认参数为波特率为115200,数据位为8,校验为None,停止位为1,流控为关闭。
|