搜索
bottom↓
回复: 0

《I.MX6U嵌入式Qt开发指南》第十七章 Serial Port

[复制链接]

出0入234汤圆

发表于 2021-7-19 14:58:16 | 显示全部楼层 |阅读模式
本帖最后由 正点原子 于 2021-8-11 12:26 编辑

1)实验平台:正点原子i.MX6ULL Linux阿尔法开发板
2)  章节摘自【正点原子】《I.MX6U嵌入式Qt开发指南》
3)购买链接:https://item.taobao.com/item.htm?&id=603672744434
4)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/arm-linux/zdyz-i.mx6ull.html
5)正点原子官方B站:https://space.bilibili.com/394620890
6)
正点原子Linux技术交流群:1027879335    1.png


2.jpg


3.png


第十七章 Serial Port

       Qt提供了串口类,可以直接对串口访问。我们可以直接使用Qt的串口类编程即可,十分方便。Qt串口类不仅在Windows能用,还能在Linux下用,虽然串口编程不是什么新鲜事儿,既然Qt提供了这方面的接口,我们就充分利用起来,这将会使我们的开发十分方便!其实Qt也提供了相关的Qt串口的例子,我们也可以直接参考来编程,编者根据实际情况,化繁为易,直接写了个简单的例子给大家参考。


17.1 资源简介
      

        在正点原子的I.MX6U开发板的出厂系统里,默认已经配置了两路串口可用。一路是调试串口UART1(对应系统里的节点/dev/ttymxc0),另一路是UART3(对应系统里的节点/dev/ttymxc2)。由于UART1已经作为调试串口被使用。所以我们只能对UART3编程,(如需要使用多路串口,请自行设计底板与系统)。
17.2 应用实例
        项目简介:设置一个按钮,点击即可控制BEEP状态反转(打开蜂鸣器或者关闭蜂鸣器)。
        例03_serialport,Qt串口编程(难度:一般)。项目路径为Qt/3/03_serialport。
        在03_serialport.pro里,我们需要使用串口,需要在pro项目文件中添加串口模块的支持,如下。
  1. 1   # 添加串口模块支持
  2. 2   QT       += core gui serialport
  3. 3
  4. 4   greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
  5. 5
  6. 6   CONFIG += c++11
  7. 7
  8. 8   # The following define makes your compiler emit warnings if you use
  9. 9   # any Qt feature that has been marked deprecated (the exact warnings
  10. 10  # depend on your compiler). Please consult the documentation of the
  11. 11  # deprecated API in order to know how to port your code away from it.
  12. 12  DEFINES += QT_DEPRECATED_WARNINGS
  13. 13
  14. 14  # You can also make your code fail to compile if it uses deprecated APIs.
  15. 15  # In order to do so, uncomment the following line.
  16. 16  # You can also select to disable deprecated APIs only up to a certain version of Qt.
  17. 17  #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0
  18. 18
  19. 19  SOURCES += \
  20. 20      main.cpp \
  21. 21      mainwindow.cpp
  22. 22
  23. 23  HEADERS += \
  24. 24      mainwindow.h
  25. 25
  26. 26  # Default rules for deployment.
  27. 27  qnx: target.path = /tmp/${TARGET}/bin
  28. 28  else: unix:!android: target.path = /opt/${TARGET}/bin
  29. 29  !isEmpty(target.path): INSTALLS += target
复制代码

       第2行,添加的serialport就是串口模块的支持。
       在头文件“mainwindow.h”的代码如下。
  1.    /******************************************************************
  2.     Copyright © Deng Zhimao Co., Ltd. 1990-2021. All rights reserved.
  3.     * @projectName   03_serialport
  4.     * @brief         mainwindow.h
  5.     * @author        Deng Zhimao
  6.     * @email         <a href="mailto:1252699831@qq.com">1252699831@qq.com</a>
  7.     * @net            <a href="www.openedv.com" target="_blank">www.openedv.com</a>
  8.     * @date           2021-03-12
  9.     *******************************************************************/
  10. 1   #ifndef MAINWINDOW_H
  11. 2   #define MAINWINDOW_H
  12. 3
  13. 4   #include <QMainWindow>
  14. 5   #include <QSerialPort>
  15. 6   #include <QSerialPortInfo>
  16. 7   #include <QPushButton>
  17. 8   #include <QTextBrowser>
  18. 9   #include <QTextEdit>
  19. 10  #include <QVBoxLayout>
  20. 11  #include <QLabel>
  21. 12  #include <QComboBox>
  22. 13  #include <QGridLayout>
  23. 14  #include <QMessageBox>
  24. 15  #include <QDebug>
  25. 16
  26. 17  class MainWindow : public QMainWindow
  27. 18  {
  28. 19      Q_OBJECT
  29. 20
  30. 21  public:
  31. 22      MainWindow(QWidget *parent = nullptr);
  32. 23      ~MainWindow();
  33. 24
  34. 25  private:
  35. 26      /* 串口对象 */
  36. 27      QSerialPort *serialPort;
  37. 28
  38. 29      /* 用作接收数据 */
  39. 30      QTextBrowser *textBrowser;
  40. 31
  41. 32      /* 用作发送数据 */
  42. 33      QTextEdit *textEdit;
  43. 34
  44. 35      /* 按钮 */
  45. 36      QPushButton *pushButton[2];
  46. 37
  47. 38      /* 下拉选择盒子 */
  48. 39      QComboBox *comboBox[5];
  49. 40
  50. 41      /* 标签 */
  51. 42      QLabel *label[5];
  52. 43
  53. 44      /* 垂直布局 */
  54. 45      QVBoxLayout *vboxLayout;
  55. 46
  56. 47      /* 网络布局 */
  57. 48      QGridLayout *gridLayout;
  58. 49
  59. 50      /* 主布局 */
  60. 51      QWidget *mainWidget;
  61. 52
  62. 53      /* 设置功能区域 */
  63. 54      QWidget *funcWidget;
  64. 55
  65. 56      /* 布局初始化 */
  66. 57      void layoutInit();
  67. 58
  68. 59      /* 扫描系统可用串口 */
  69. 60      void scanSerialPort();
  70. 61
  71. 62      /* 波特率项初始化 */
  72. 63      void baudRateItemInit();
  73. 64
  74. 65      /* 数据位项初始化 */
  75. 66      void dataBitsItemInit();
  76. 67
  77. 68      /* 检验位项初始化 */
  78. 69      void parityItemInit();
  79. 70
  80. 71      /* 停止位项初始化 */
  81. 72      void stopBitsItemInit();
  82. 73
  83. 74  private slots:
  84. 75      void sendPushButtonClicked();
  85. 76      void openSerialPortPushButtonClicked();
  86. 77      void serialPortReadyRead();
  87. 78  };
  88. 79  #endif // MAINWINDOW_H
复制代码

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

  第29~121行,界面布局初始化设置,在嵌入式里,根据实际的屏的大小,设置全屏显示。其中我们用到垂直布局和网格布局,如果布局这方面内容理解不了,请回到第七章7.5小节学习布局内容,学以致用理解的时候到了。
        第123~130行,查找系统可用的串口,并添加串口名到comboBox[0]中。
        第132~144行,波特率初始化,预设常用的波特率,115200作为默认选项。并添加波特率到comboBox[1]中。
        第146~155行,数据位项初始化,设置默认数据位为8。
        第157~166行,校验位项初始化,默认无校验位。
        第168~177行,停止位项初始化,默认停止位为1。
        第179~184行,发送数据,点击发送按钮时触发。
  1. 187 void MainWindow::sendPushButtonClicked()
  2. 188 {
  3. 189     /* 获取textEdit数据,转换成utf8格式的字节流 */
  4. 190     QByteArray data = textEdit->toPlainText().toUtf8();
  5. 191     serialPort->write(data);
  6. 192 }
复制代码

        第186~256行,打开或者关闭串口。以我们设置的项使用Qt串口提供的设置串口的方法如setDataBits(QSerialPort::DataBits)等,按如188~239行步骤设置完串口需要配置的参数就可以打开或者关闭串口了。
        第258~263行,从缓冲区里读出数据,并显示到textBrowser里。
17.3 程序运行效果
下面为Ubuntu上仿真界面的效果,请将程序交叉编译后到开发板运行,用串口线连接开发板的UART3到电脑串口,在电脑用正点原子的XCOM上位机软件(或者本程序亦可当上位机软件),设置与相同的串口参数,选择串口号为ttymxc2(注意ttymxc0已经作为调试串口被使用了!),点击打开串口就可以进行消息收发了。默认参数为波特率为115200,数据位为8,校验为None,停止位为1,流控为关闭。
Serial Port13199.png







阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-3-29 19:54

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表