Qt串口通信,QSerialPort的使用

96 篇文章 7 订阅
85 篇文章 9 订阅

前言

Qt写上位机时,串口通信是个常用功能,在Qt4的时候有第三方模块QextSerialPort,到了Qt5.1官方提供了QSerialPort模块。

目录

前言

获取串口信息:QSerialPortInfo

串口IO操作:QSerialPort

实例操作

补充:16进制文本(如“0A 13 EF”)转16进制数据(如0x0A 0x13 0xEF)


使用该模块需要在pro文件中添加:QT += serialport 

主要使用两个类:QSerialPort和QSerialPortInfo

获取串口信息:QSerialPortInfo

获取串口名列表


 
 
  1. QStringList slist;
  2. foreach ( const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) {
  3. //检测是否可用
  4. f(!info.isBusy())
  5. slist<<info.portName();
  6. }

除了串口名还能获取其他的相关信息,可以看文档,或者该链接 https://blog.csdn.net/mcu_tian/article/details/43527385

串口IO操作:QSerialPort

串口IO的主要操作有参数设置/开/关/读/写等


 
 
  1. //[1]串口设置
  2. QSerialPort *serialIo= new QSerialPort;
  3. serialIo->setPortName( "COM4"); //串口名
  4. serialIo->setBaudRate( 115200); //波特率
  5. serialIo->setDataBits(QSerialPort::Data8); //数据位
  6. serialIo->setParity(QSerialPort::NoParity); //校验位
  7. serialIo->setStopBits(QSerialPort::OneStop); //停止位
  8. serialIo->setFlowControl(QSerialPort::NoFlowControl); //流控制一般没用
  9. //[2]串口开启
  10. if(serialIo->open(QIODevice::ReadWrite)){
  11. qDebug()<< "串口已打开,读写模式";
  12. } else{
  13. qDebug()<< "串口打开异常"<<serialIo->errorString();
  14. serialIo->clearError();
  15. }
  16. //[3]数据发送
  17. const QByteArray send_data=ui->textSend->toPlainText().toUtf8(); //一般没发字符串,特别是中文
  18. if(serialIo->isOpen()){
  19. serialIo->write(send_data);
  20. qDebug()<< "已发送:"<<QString::fromUtf8(send_data);
  21. } else{
  22. qDebug()<< "发送失败,串口未打开";
  23. }
  24. if(!serialIo->waitForBytesWritten( 30000)){
  25. qDebug()<< "命令发送异常"<<serialIo->errorString();
  26. serialIo->clearError();
  27. }
  28. //[4]数据接收
  29. connect(serialIo,&QSerialPort::readyRead, this,[ this](){
  30. if (serialIo->bytesAvailable()) {
  31. //串口收到的数据可能不是连续的,需要的话应该把数据缓存下来再进行协议解析,类似tcp数据处理
  32. const QByteArray recv_data=serialIo->readAll();
  33. //接收发送要一致,如果是处理字节数据,可以把QByteArray当数组一样取下标,或者用data()方法转为char*形式
  34. ui->textRecv->append(QString::fromUtf8(recv_data)); //显示
  35. qDebug()<< "已接收:"<<QString::fromUtf8(recv_data);
  36. }
  37. });
  38. //[5]串口关闭
  39. serialIo->clear();
  40. serialIo->close();

实例操作

为了方便,ui我直接用的设计师拖得,工程文件我把百度云链接放在了最后,需要的可以下载

串口

头文件MainWidget.h(记得pro里引入serialport模块)


 
 
  1. #ifndef MAINWIDGET_H
  2. #define MAINWIDGET_H
  3. #include <QWidget>
  4. class QSerialPort;
  5. namespace Ui {
  6. class MainWidget;
  7. }
  8. class MainWidget : public QWidget
  9. {
  10. Q_OBJECT
  11. public:
  12. explicit MainWidget(QWidget *parent = 0);
  13. ~MainWidget();
  14. void initSerial(); //初始化串口设置
  15. void initMainUi(); //初始化界面操作
  16. void openSerial(); //槽函数-打开串口
  17. void closeSerial(); //槽函数-关闭串口
  18. void refreshSerial(); //槽函数-刷新串口名列表
  19. private:
  20. QStringList getSerialPortNames(); //获取串口名列表
  21. void setSerialEnable(bool enabled); //串口开启时就不能动ui配置了
  22. void sendData(); //槽函数-发送数据
  23. void recvData(); //槽函数-接收数据
  24. private:
  25. Ui::MainWidget *ui;
  26. QSerialPort *serialIo; //串口io,一般可以把串口io扔到线程里去,避免阻塞ui
  27. };
  28. #endif // MAINWIDGET_H

实现文件MainWidget.cpp


 
 
  1. #include "MainWidget.h"
  2. #include "ui_MainWidget.h"
  3. #include <QSerialPort>
  4. #include <QSerialPortInfo>
  5. #include <QListView>
  6. #include <QDebug>
  7. MainWidget::MainWidget(QWidget *parent) :
  8. QWidget(parent),
  9. ui( new Ui::MainWidget)
  10. {
  11. ui->setupUi( this);
  12. initSerial();
  13. initMainUi();
  14. }
  15. MainWidget::~MainWidget()
  16. {
  17. delete ui;
  18. }
  19. void MainWidget::initSerial()
  20. {
  21. //[1]创建串口io对象
  22. serialIo= new QSerialPort( this);
  23. //数据接收处理
  24. connect(serialIo,&QSerialPort::readyRead, this,&MainWidget::recvData);
  25. //[2]界面初始化
  26. //注:items的选项值是根据文档中的枚举来写的
  27. //串口名
  28. refreshSerial();
  29. ui->boxPortName->setView( new QListView( this));
  30. //波特率
  31. QStringList baudrateList;
  32. baudrateList<< "1200"<< "2400"<< "4800"<< "9600"<< "19200"<< "38400"<< "57600"<< "115200";
  33. ui->boxBaudRate->addItems(baudrateList); //添加下拉列表选项
  34. ui->boxBaudRate->setEditable( true); //串口波特率可编辑
  35. ui->boxBaudRate->setCurrentText( "115200"); //界面中初始值
  36. ui->boxBaudRate->setView( new QListView( this)); //该设置是配合qss的,不然item行高设置没效果
  37. //数据位
  38. QStringList databitList;
  39. databitList<< "5"<< "6"<< "7"<< "8";
  40. ui->boxDataBits->addItems(databitList);
  41. ui->boxDataBits->setCurrentText( "8");
  42. ui->boxDataBits->setView( new QListView( this));
  43. //校验位
  44. QStringList parityList;
  45. parityList<< "No"<< "Even偶"<< "Odd奇"<< "Space"<< "Mark";
  46. ui->boxParity->addItems(parityList);
  47. ui->boxParity->setCurrentText( "No");
  48. ui->boxParity->setView( new QListView( this));
  49. //停止位
  50. QStringList stopbitList;
  51. stopbitList<< "1"<< "1.5"<< "2";
  52. ui->boxStopBits->addItems(stopbitList);
  53. ui->boxStopBits->setCurrentText( "1");
  54. ui->boxStopBits->setView( new QListView( this));
  55. //流控制
  56. QStringList flowctrlList;
  57. flowctrlList<< "No"<< "Hardware"<< "Software";
  58. ui->boxFlowControl->addItems(flowctrlList);
  59. ui->boxFlowControl->setCurrentText( "No");
  60. ui->boxFlowControl->setView( new QListView( this));
  61. }
  62. void MainWidget::initMainUi()
  63. {
  64. //点击串口[开启]/[关闭]按钮
  65. connect(ui->btnOpen,&QPushButton::clicked, this,[ this](){
  66. if(ui->btnOpen->text()== "打开"){
  67. openSerial();
  68. } else{
  69. closeSerial();
  70. }
  71. });
  72. //点击串口[刷新]按钮-刷新串口名列表
  73. connect(ui->btnRefresh,&QPushButton::clicked, this,&MainWidget::refreshSerial);
  74. //点击数据[发送]按钮
  75. connect(ui->btnSend,&QPushButton::clicked, this,&MainWidget::sendData);
  76. }
  77. void MainWidget::openSerial()
  78. {
  79. const QString portnameStr=ui->boxPortName->currentText();
  80. if(!portnameStr.isEmpty()){
  81. QSerialPortInfo info(portnameStr);
  82. if(info.isBusy()){
  83. qDebug()<< "当前串口繁忙,可能已被占用,请确认后再连接"<<portnameStr;
  84. return;
  85. }
  86. //
  87. qint32 baudrate=ui->boxBaudRate->currentText().toInt();
  88. QSerialPort::DataBits databit;
  89. switch (ui->boxDataBits->currentIndex()) {
  90. case 0:databit=QSerialPort::Data5; break;
  91. case 1:databit=QSerialPort::Data6; break;
  92. case 2:databit=QSerialPort::Data7; break;
  93. case 3:databit=QSerialPort::Data8; break;
  94. default:databit=QSerialPort::Data8; break;
  95. }
  96. QSerialPort::Parity parity;
  97. switch (ui->boxParity->currentIndex()) {
  98. case 0:parity=QSerialPort::NoParity; break;
  99. case 1:parity=QSerialPort::EvenParity; break;
  100. case 2:parity=QSerialPort::OddParity; break;
  101. case 3:parity=QSerialPort::SpaceParity; break;
  102. case 4:parity=QSerialPort::MarkParity; break;
  103. default:parity=QSerialPort::NoParity; break;
  104. }
  105. QSerialPort::StopBits stopbit;
  106. switch (ui->boxStopBits->currentIndex()) {
  107. case 0:stopbit=QSerialPort::OneStop; break;
  108. case 1:stopbit=QSerialPort::OneAndHalfStop; break;
  109. case 2:stopbit=QSerialPort::TwoStop; break;
  110. default:stopbit=QSerialPort::OneStop; break;
  111. }
  112. QSerialPort::FlowControl flowcontrol;
  113. switch (ui->boxFlowControl->currentIndex()) {
  114. case 0:flowcontrol=QSerialPort::NoFlowControl; break;
  115. case 1:flowcontrol=QSerialPort::HardwareControl; break;
  116. case 2:flowcontrol=QSerialPort::SoftwareControl; break;
  117. default:flowcontrol=QSerialPort::NoFlowControl; break;
  118. }
  119. //串口配置设置
  120. serialIo->setPortName(portnameStr);
  121. serialIo->setBaudRate(baudrate);
  122. serialIo->setDataBits(databit);
  123. serialIo->setParity(parity);
  124. serialIo->setStopBits(stopbit);
  125. serialIo->setFlowControl(flowcontrol); //这个我一般没用
  126. if(serialIo->open(QIODevice::ReadWrite)){
  127. qDebug()<< "串口已打开,读写模式";
  128. setSerialEnable( false); //改变ui状态
  129. } else{
  130. qDebug()<< "串口打开异常"<<portnameStr<<serialIo->errorString();
  131. serialIo->clearError();
  132. setSerialEnable( true);
  133. }
  134. } else{
  135. qDebug()<< "未找到可用串口,请确认串口连接正常后点击刷新";
  136. }
  137. }
  138. void MainWidget::closeSerial()
  139. {
  140. serialIo->clear();
  141. serialIo->close();
  142. qDebug()<< "串口已关闭";
  143. setSerialEnable( true);
  144. }
  145. void MainWidget::refreshSerial()
  146. {
  147. ui->boxPortName->clear();
  148. ui->boxPortName->addItems(getSerialPortNames());
  149. }
  150. QStringList MainWidget::getSerialPortNames()
  151. {
  152. QStringList slist;
  153. foreach ( const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) {
  154. //检测是否可用
  155. if(!info.isBusy())
  156. slist<<info.portName();
  157. }
  158. if(slist.isEmpty()){
  159. qDebug()<< "未找到可用串口,请确认串口连接正常后点击刷新";
  160. }
  161. return slist;
  162. }
  163. void MainWidget::setSerialEnable( bool enabled)
  164. {
  165. //打开成功就false不能再修改配置,关闭状态true可以进行设置
  166. ui->btnRefresh->setEnabled(enabled);
  167. ui->btnOpen->setText(enabled?QString( "打开"):QString( "关闭"));
  168. //可以把btn和配置分在两个widget里,这样直接设置widget的enable就没这么麻烦了
  169. ui->boxPortName->setEnabled(enabled);
  170. ui->boxBaudRate->setEnabled(enabled);
  171. ui->boxDataBits->setEnabled(enabled);
  172. ui->boxParity->setEnabled(enabled);
  173. ui->boxStopBits->setEnabled(enabled);
  174. ui->boxFlowControl->setEnabled(enabled);
  175. }
  176. void MainWidget::sendData()
  177. {
  178. //注意收发的编码问题,我一般只是发命令吗和字节数据,没怎么发字符串,用latin1就行了
  179. const QByteArray send_data=ui->textSend->toPlainText().toUtf8();
  180. if(send_data.size()<= 0)
  181. return;
  182. if(serialIo->isOpen()){
  183. serialIo->write(send_data);
  184. qDebug()<< "已发送:"<<QString::fromUtf8(send_data);
  185. } else{
  186. qDebug()<< "发送失败,串口未打开";
  187. return;
  188. }
  189. //Qt新版本默认值是30 000
  190. if(!serialIo->waitForBytesWritten( 30000)){
  191. qDebug()<< "命令发送异常"<<serialIo->errorString();
  192. serialIo->clearError();
  193. }
  194. }
  195. void MainWidget::recvData()
  196. {
  197. if (serialIo->bytesAvailable()) {
  198. //串口收到的数据可能不是连续的,需要的话应该把数据缓存下来再进行协议解析,类似tcp数据处理
  199. const QByteArray recv_data=serialIo->readAll();
  200. //接收发送要一致,如果是处理字节数据,可以把QByteArray当数组一样取下标,或者用data()方法转为char*形式
  201. ui->textRecv->append(QString::fromUtf8(recv_data));
  202. qDebug()<< "已接收:"<<QString::fromUtf8(recv_data);
  203. }
  204. }

由于时间有限,所以有两个点没有写,一是一般我把串口IO放在子线程中避免阻塞ui;二是串口协议得解析,可以参照TCP数据的处理,先缓存起来再循环判断,一般一帧数据有帧头、帧长度、帧命令码、帧数据、帧尾/CRC校验等字段。

时间仓促,可能代码有bug,望大佬纠正。

附上百度云链接 https://pan.baidu.com/s/1gzHC6Q4fBZ_G1Db7tMcIaw 

提取码 inxh   文件名TestSerialPort.rar

补充:16进制文本(如“0A 13 EF”)转16进制数据(如0x0A 0x13 0xEF)

有时候需要这种功能,输入十六进制文本,发送的是对应的十六进制数据,Qt中通过QByteArray类可以轻松的搞定。


 
 
  1. QString str= "0A 13 EF"; //假设为文本框读取到的字符串
  2. QByteArray temp=QByteArray::fromHex(str.toLatin1());
  3. qDebug()<<str<<temp;

(输出结果中的十六进制因为被Qt做了转义,所以0x0A是个换行符)

当然,也可以把十六进制数据转为十六进制文本。


 
 
  1. const char arr[]={ 0x0A, 0x13, 0xEF};
  2. QByteArray temp=QByteArray(arr, 3); //假设为收到的数据
  3. QString str=temp.toHex( ' ').toUpper(); //老版本Qt的toHex没有参数设置,需要自己分割
  4. qDebug()<<temp<<str;

(2019-07-24晨)

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Qt串口通信是一种可以在Qt平台上进行串口通信的解决方案。其中,Qt串口通信模块qserialport是实现串口通信的关键模块。本文将为大家介绍Qt串口通信模块qserialport的开发完整实例。 首先,我们需要在Qt中打开串口通信模块qserialport。在Qt 5.2及以上版本中,qserialport已经被包含在QtCore模块中。因此,我们只需要在代码中引入QtCore模块即可使用qserialport。 接下来,我们需要定义串口参数。我们可以利用QSerialPort类中提供的函数setBaudRate()、setDataBits()、setParity()等来设置参数。例如: ```cpp QSerialPort serial; serial.setBaudRate(QSerialPort::Baud9600); serial.setDataBits(QSerialPort::Data8); serial.setParity(QSerialPort::NoParity); serial.setStopBits(QSerialPort::OneStop); serial.setFlowControl(QSerialPort::NoFlowControl); ``` 然后,我们需要打开串口。我们可以使用QSerialPort类的open()函数来打开串口。例如: ```cpp serial.setPortName("COM1"); // 设置串口号为COM1 if (serial.open(QIODevice::ReadWrite)) { qDebug() << "串口已打开"; } else { qDebug() << "串口打开失败"; } ``` 接下来,我们可以通过QSerialPort类的函数write()和read()来进行数据读写。例如: ```cpp // 向串口写入数据 char buf[] = "hello world"; serial.write(buf, sizeof(buf)); // 从串口读取数据 QByteArray data = serial.readAll(); qDebug() << data; ``` 最后,在程序结束时我们需要关闭串口。我们可以使用QSerialPort类的close()函数来关闭串口。例如: ```cpp serial.close(); ``` 综上所述,以上就是Qt串口通信模块qserialport的开发完整实例。在实际应用中,我们可以根据需要对以上代码进行修改,从而实现更加复杂的串口通信功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值