Qt5串口编程详解

 

Qt5串口编程详解【新版】

分类: qt   520人阅读  评论(0)  收藏  举报

Qt5的串口比Qt4的好用得多,Qt4的貌似没有集成官方库。

之前我也写过Qt5的串口,不过有一些缺陷,这次试图改进。转载请保留链接:http://blog.csdn.net/qq363692146/article/details/26049355

本文发表于2014.5.17。


如果在linux下,记得使用root权限,可以用root权限打开可执行文件,或者用root权限打开Qt Creator。(原因是串口常常需要特权,有些串口有特权也只能度而不能写,这个可能是Qt本身的问题)【至于安卓端,其实没试过。】【用root打开Qt Creator似乎是一个一劳永逸的方法,这样每次运行都以root权限,但是一些配置文件也会被改变为root权限。下一次再以普通权限打开Qt Creator就会提示错误,需要输入这样命令 sudo chmod 777 `find 对应目录`,这样能将目录的每个文件去掉权限限制】



好了,准备开始。



先建立Qt Widgets Application,只要注意尽量不用中文路径即可,一直下一步,直到完成。


接着修改“项目名.pro”文件,增加这一单独行。(这个项目文件可以根据需要裁剪和增加,以增快编译效率和设置选项,而这一行表示“我想用到串口”)

  1. QT       += serialport  



进入mainwindow.ui,给它一个Combo Box(用于选择哪一个串口,一台电脑常常有多个串口)、一个label(用于显示串口是否正常)、一个Text Edit(用于接收数据)、一个lineEdit(用于发送数据)、一个Push Button(当按下一次,就发送一次),这里为了方便读者理解,与博文统一,请读者先别急着修改它们的ObeectName,至于布局,请随意。

给Combo Box一个槽,来改变串口(右键,转到槽,选择currentIndexChange(QString))。//当改变选择的选项则触发,可得到选项名

给Push Button一个槽,用于发送(右键,选择槽,选择第一个函数)。//当按下触发




在mainWindow.h文件中

加入头文件:(这里QSerialPort是必须的,而QSerialPortInfo是可选的,它能提供本机可用串口列表(列表的每一个元素都自动获取了对应的端口号、波特率、校验位等信息!),如果不使用它则需要手动编码,设置对应的串口、波特率等信息,最后完成之后单独拿出来讲,见下面的黄色阴影字体部分)

  1. #include <QSerialPort>  
  2. #include <QSerialPortInfo>  
接着,给它一个private变量(表示串口及其操作函数)、一个private函数(用于初始化)、一个连接槽,(用于接收串口过来的数据,发送是不需要槽的,原因是发送是主动、随时的,而接收是被动、等待的):

private变量:

  1. QSerialPort serial;  

一个private函数:

  1. void initSeialPort();  

连接槽:

  1. private slots:  
  2.     void serialRead();  


进入mainWindow.cpp中

在构造函数中:

在ui->setupUi(this);之后加入这一句:

  1. initSeialPort();  

在析构函数中:

在delete ui;之前加入这一句:

  1. serial.close();  


接下来补齐这些没有函数体为空的函数,为了方便可以直接复制(仔细浏览,看看它们已经定义了没有,或者是否ui触发的槽选择错误,如果有问题,请投诉):

initSerialPort函数

先连接槽,然后获取可用的infos(所有本地存在串口信息),如果都不可用,提示“无效”,如果存在,则为Combo Box添加选项,第一项是“串口”(只是提示,由于combo Box的选项从无到有,将触发一次 on_comboBox_currentIndexChanged(const QString &arg1) 槽 ,见下面橙色阴影字体),这个选项之后是其他的串口的端口号作为选项。

  1. void MainWindow::initSeialPort()  
  2. {  
  3.   
  4.     connect(&serial,SIGNAL(readyRead()),this,SLOT(serialRead()));   //连接槽  
  5.   
  6.     //get name for choose  
  7.     QList<QSerialPortInfo>  infos = QSerialPortInfo::availablePorts();  
  8.     if(infos.isEmpty())  
  9.     {  
  10.         ui->comboBox->addItem("无效");  
  11.         return;  
  12.     }  
  13.     ui->comboBox->addItem("串口");  
  14.     foreach (QSerialPortInfo info, infos) {  
  15.         ui->comboBox->addItem(info.portName());  
  16.     }  
  17. }  



当每次combo Box选项变化,将触发下面的函数:

arg1为该选择的Combo Box选项名称(第一次触发为“串口”,之后被用户选择为需要的串口号,根据上面的addItem函数可以逆推)

根据arg1查找可用的串口列表,如果找不到(例如arg1为“串口”这个字符串,当然找不到)则提示“[出错]”,否则打开并提示"[已开启]"。

这里serial先关后开,防止先前的串口忘了关闭(因为每改变一次选项就要开启一次,那么当然要把上一次的串口给关了才行)。

  1. void MainWindow::on_comboBox_currentIndexChanged(const QString &arg1)  
  2. {  
  3.     QSerialPortInfo info;  
  4.     QList<QSerialPortInfo> infos = QSerialPortInfo::availablePorts();  
  5.     int i = 0;  
  6.     foreach (info, infos) {  
  7.         if(info.portName() == arg1) break;  
  8.         i++;  
  9.     }  
  10.     if(i != infos.size ()){//can find  
  11.         ui->label->setText("[已开启]");  
  12.         serial.close();  
  13.         serial.setPort(info);  
  14.         serial.open(QIODevice::ReadWrite);         //读写打开  
  15.     }  
  16.     else  
  17.     {  
  18.         serial.close();  
  19.         ui->label->setText("[出错]");  
  20.     }  
  21. }  



下面两个函数便不详述:

  1. void MainWindow::serialRead()  
  2. {  
  3.     ui->textEdit->append(serial.readAll());  
  4. }  

toLatin1可用转换QString到QByteArray类型:

  1. void MainWindow::on_pushButton_clicked()  
  2. {  
  3.     if(ui->lineEdit->text().isEmpty())  
  4.         return;  
  5.     serial.write(ui->lineEdit->text().toLatin1());  
  6. }  



好已经完成全部工作,测试一下吧。




补充一下自己摸索的其他方法,作为阅读即可:


问题1:如何去掉QSerialPortInfo头文件,并手动设置串口信息,这里举个例子:

  1. //注意这里serial是指针形式,而且下面的顺序有一定要求:  
  2. //下面这些设置都是针对单片机11.0592的晶振的,请根据具体情况设置:  
  3.   
  4. serial = new QSerialPort("COM4");       //串口号,一定要对应好,大写!!!串口号一般要修改。  
  5.     serial->open(QIODevice::ReadWrite);      //读写打开    
  6.     serial->setBaudRate(QSerialPort::Baud9600);  //波特率    
  7.     serial->setDataBits(QSerialPort::Data8); //数据位    
  8.     serial->setParity(QSerialPort::NoParity);    //无奇偶校验    
  9.     serial->setStopBits(QSerialPort::OneStop);   //无停止位    
  10.     serial->setFlowControl(QSerialPort::NoFlowControl);  //无控制    


问题2:如何解决传接收断断续续的问题(在某些情况串口无意地经常把一条数据拆成多条数据,这时候多次触发了serialRead槽,得到不想要的结果):

解决方法:

1.对于固定长度的数据,假如有数据长度不正确,就请求重发。

2.对于不固定长度的,可以在数据后面加上特殊符号作为识别,这里将举例(当特殊符号为'~')【不过这个代码没考虑多线程:static变量存在着】:

  1. void MainWindow::serialRead()    
  2. {    
  3.     static QByteArray allData;         //静态变量!!在串口只得到一部分的时候用来累加数据    
  4.     QByteArray dataTemp;                //本次接收的数据,可能是前半部分数据或者后半部分数据(甚至是被分割为多段数据的其中一部分数据),或者也可能是完整数据。  
  5.     while (!serial->atEnd()) {    
  6.         QByteArray dataTemp = serial->readAll();                //因为串口是不稳定的,也许读到的是部分数据而已,但也可能是全部数据    
  7.         if( dataTemp.data()[dataTemp.length() - 1] == '~'){     //当临时数据最后一位是'~',代表一条数据读完了    
  8.             allData += dataTemp;                                //总数据加上本次数据    
  9.             allData.resize(allData.size() - 1);                 //删除结尾的~符号    
  10.             qCritical() << allData;                             //这时候allData将是你要的数据    
  11.             allData.clear();                                    //清除数据!!!!!    
  12.         }    
  13.         else                                                  //当最后一位数据不是'~',即未读完    
  14.             allData += dataTemp;                               //每次累加这部分数据,因为还没发完    
  15.     }    
  16. }    
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值