小工具--串口
功能实现:
1. 接收串口数据;
2.保存接收数据到TXT文档,主要是测试串口接收到数据,给python进行处理时的小应用(个人使用),避免长时间测试数据丢失的问题;
3.发送串口数据;
4.发送文件;
小细节:
1.串口没有打开之前,不能进行发送数据等操作,需要在发送槽函数中进行判断串口是否打开;
2.串口刷新监测;
3.串口发送框允许输入的字符a-f ,A-F,0-9,以及空格符,正则表达式的运用以及过滤器QValidator的使用;
4.接收框显示,发送数据什么格式,接收数据什么格式;
代码:
#include "serialportqmain.h" #include "ui_serialportqmain.h" #include <QFileDialog> #include<QMessageBox> #include<QTextStream> #include<QDebug> #include <QRegExp> #include<QValidator> #include<QSizePolicy> #include <QComboBox> #include <QTimer> #include<QDateTime> SerialPortQMain::SerialPortQMain(QWidget *parent) : QMainWindow(parent), ui(new Ui::SerialPortQMain) { ui->setupUi(this); initSerial(); //recv connect(ui->pushButton_Open,&QPushButton::clicked,this,&SerialPortQMain::slot_on_openSerial_clicked); connect(ui->pushButton_SaveRecv,&QPushButton::clicked,this,&SerialPortQMain::slot_on_saveRecvBtn_clicked); connect(ui->pushButton_ClearRecv,&QPushButton::clicked,this,&SerialPortQMain::slot_on_clearRecvBtn_clicked); //send connect(ui->pushButton_Send,&QPushButton::clicked,this,&SerialPortQMain::slot_on_sendBtn_clicked); connect(ui->pushButton_ClearSend,&QPushButton::clicked,this,&SerialPortQMain::slot_on_clearSendBtn_clicked); connect(ui->pushButton_OpenFile,&QPushButton::clicked,this,&SerialPortQMain::slot_on_openFileBtn_clicked); connect(ui->pushButton_SendFile,&QPushButton::clicked,this,&SerialPortQMain::slot_on_sendFileBtn_clicked); connect(ui->pushButton_StopSend,&QPushButton::clicked,this,&SerialPortQMain::slot_on_stopSend_clicked);//停止发送文件 //输入自定义波特率 connect(ui->comboBoxBaudRate, SIGNAL(currentIndexChanged(const QString &)), this, SLOT(slot_on_baudRate(const QString &))); //周期发送 connect(ui->checkBox_SendRegular,&QCheckBox::stateChanged,this,&SerialPortQMain::slot_on_periodSendCheckSelect); connect(ui->checkBox_Send,&QCheckBox::stateChanged,this,&SerialPortQMain::slot_on_StrOrHex); } SerialPortQMain::~SerialPortQMain() { delete ui; } void SerialPortQMain::slot_on_refreshCurrentTime() { currentTime=QTime::currentTime(); strTime= currentTime.toString("HH:mm"); currentDate =QDate::currentDate(); strDate = currentDate.toString("yyyy-MM-dd dddd"); strDate.append(strTime); currenttimeDisplay->setText("当前时间:"+strDate); } /*串口初始化*/ void SerialPortQMain::initSerial() { /*查找可用串口*/ foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) { QSerialPort serialPort ; serialPort.setPort(info); if(serialPort.open(QIODevice::ReadWrite)) { ui->comboBoxSerial->addItem(serialPort.portName()); serialPort.close(); } } //设置波特率下拉菜单默认显示第三项 ui->comboBoxBaudRate->setCurrentIndex(3); //statusbar operateState = new QLabel; ui->statusBar->addPermanentWidget(operateState,1); operateState->setText("当前操作状态:"+operateStateChange); operateState->setFixedSize(200,20); currenttimeDisplay=new QLabel; ui->statusBar->addPermanentWidget(currenttimeDisplay,3); timerPeriodSend = new QTimer(this); //周期发送数据定时器 refreshSerialTimer = new QTimer(this);//刷新串口定时器 connect(refreshSerialTimer, SIGNAL(timeout()), this, SLOT(slot_on_refreshComPort())); //定时刷新串口 refreshSerialTimer->start(1000); currentTimer=new QTimer(this); connect(currentTimer, SIGNAL(timeout()), this, SLOT(slot_on_refreshCurrentTime())); //定时刷新串口 currentTimer->start(1000); //发送输入规则 QRegExp exp("[A-Fa-f0-9\\s][A-Fa-f0-9\\s]+$"); QValidator *validator = new QRegExpValidator(exp,ui->lineEditSend); ui->lineEditSend->setValidator(validator); } /*刷新串口*/ void SerialPortQMain::slot_on_refreshComPort() { ui->comboBoxSerial->clear(); //每次将之前信息监测到的串口删除,重新扫描 foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) { QSerialPort serialPort ; serialPort.setPort(info); if(serialPort.open(QIODevice::ReadWrite)) { ui->comboBoxSerial->addItem(serialPort.portName()); serialPort.close(); } } } /*操作清除接收窗口按钮*/ void SerialPortQMain::slot_on_clearRecvBtn_clicked() { ui->textEditRecv->clear(); } /*操作保存接收窗口按钮*/ void SerialPortQMain::slot_on_saveRecvBtn_clicked() { QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"), "/home", tr("Text (*.txt *.*)")); if(fileName !="") //不为空 { QFile saveFile(fileName); if(!saveFile.open(QIODevice::WriteOnly)) { //操作提示 operateStateDisplay("保存文件失败!"); QMessageBox::about(this,"操作","操作错误"); } else{ QTextStream stream(&saveFile); stream<<ui->textEditRecv->toPlainText(); stream.flush(); saveFile.close(); } } } /*操作打开串口按钮*/ void SerialPortQMain:: slot_on_openSerial_clicked() { if(ui->pushButton_Open->text() == tr("打开串口")) { //若串口已经打开则不再继续刷新串口 refreshSerialTimer->stop(); serialPort = new QSerialPort; //设置串口名 serialPort->setPortName(ui->comboBoxSerial->currentText()); //打开串口模式 serialPort->open(QIODevice::ReadWrite); //设置波特率 serialPort->setBaudRate(ui->comboBoxBaudRate->currentText().toInt()); //设置数据位 switch (ui->comboBoxDataBit->currentIndex()) { case 8:serialPort->setDataBits(QSerialPort::Data8); break; case 7:serialPort->setDataBits(QSerialPort::Data7); break; default: break; } //设置奇偶校验位 switch (ui->comboBoxOdd->currentIndex()) { case 0:serialPort->setParity(QSerialPort::NoParity); break; case 2:serialPort->setParity(QSerialPort::EvenParity);break; case 3:serialPort->setParity(QSerialPort::OddParity);break; case 4:serialPort->setParity(QSerialPort::SpaceParity);break; case 5:serialPort->setParity(QSerialPort::MarkParity);break; default: break; } //设置停止位 switch(ui->comboBoxStopBit->currentIndex()) { case 1: serialPort->setStopBits(QSerialPort::OneStop); break; case 2: serialPort->setStopBits(QSerialPort::TwoStop); break; case 3: serialPort->setStopBits(QSerialPort::OneAndHalfStop); break; default: break; } //设置流控制 serialPort->setFlowControl(QSerialPort::NoFlowControl); ui->pushButton_Open->setText(tr("关闭串口")); ui->pushButton_Open->setStyleSheet("background: lightgreen"); //操作提示 operateStateDisplay("打开串口成功!"); if(ui->lineEdit_SaveRecv->text() != "") { save_TxtName = ui->lineEdit_SaveRecv->text(); QFile recvfliesave(QString("./%1.txt").arg(save_TxtName)); if(!recvfliesave.open(QFile::WriteOnly|QIODevice::Truncate|QIODevice::Text) ) { QMessageBox::warning(this,"提示","文件创建失败"); createTXTEnable = false; } else{ createTXTEnable = true; } } else { QMessageBox::warning(this,"提示","没有填写保存文件名称,可跳过;说明只显示,不保存"); } isOpenSerial =true; //串口打开后,连接接收 connect(serialPort,&QSerialPort::readyRead,this,&SerialPortQMain::slot_on_recvOperate,Qt::QueuedConnection); } else{ serialPort->close(); isOpenSerial=false; ui->pushButton_Open->setText(tr("打开串口")); ui->pushButton_Open->setStyleSheet("background:#e8e8e8"); //操作提示 operateStateDisplay("串口关闭!"); } } /*接收数据,在接收区显示数据*/ void SerialPortQMain::slot_on_recvOperate() { QByteArray readDataBuff(1024,0); static QByteArray buff; if(serialPort->bytesAvailable()) { //操作提示 operateStateDisplay("正在接收数据..."); readDataBuff= serialPort->readAll(); buff.append(readDataBuff); if(createTXTEnable) // 允许写入Txt { writeRecvDataToTXT(buff); } //接收区显示 if(ui->checkBox_RecvHex->checkState() == Qt::Unchecked){ ui->textEditRecv->insertPlainText(QString(buff)); } else if(ui->checkBox_RecvHex->checkState() == Qt::Checked) ui->textEditRecv->insertPlainText(buff.toHex()); buff.clear(); //每次接收完成要清除; } //操作提示 operateStateDisplay("数据接收完成!"); } //接收内容写入TXT void SerialPortQMain::writeRecvDataToTXT(QByteArray data) { QFile recvfliesave(QString("./%1.txt").arg(save_TxtName)); if(recvfliesave.open(QFile::WriteOnly|QFile::Append)){ recvfliesave.write(data); } } //发送端操作 /*发送数据*/ void SerialPortQMain::slot_on_sendBtn_clicked() { if(!isOpenSerial) { QMessageBox::warning(this,"提示","串口没有打开!"); return ; } slot_on_StrOrHex(); serialPort->write(sendData); } //发送str 或者hex void SerialPortQMain::slot_on_StrOrHex() { if(ui->checkBox_Send->checkState() == Qt::Unchecked) //没有选中,说明 发送字符 { sendData= ui->lineEditSend->text().toLatin1(); ui->lineEditSend->setText(ui->lineEditSend->text()); } else if(ui->checkBox_Send->checkState() == Qt::Checked) { StringToHex(ui->lineEditSend->text(),sendData); ui->lineEditSend->setText(ui->lineEditSend->text()); } } //周期发送 void SerialPortQMain::slot_on_periodSendCheckSelect() { int period = ui->lineEdit_time->text().toInt(); if(ui->checkBox_SendRegular->checkState() == Qt::Checked) //选中 { timerPeriodSend->start(period); connect(timerPeriodSend, SIGNAL(timeout()), this, SLOT(slot_on_sendBtn_clicked())); //定时刷新串口 ui->lineEdit_time->setEnabled(false); } else if(ui->checkBox_SendRegular->checkState() == Qt::Unchecked) //没选中 { timerPeriodSend->stop(); ui->lineEdit_time->setEnabled(true); } } /*打开文件*/ void SerialPortQMain::slot_on_openFileBtn_clicked() { QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"), "/home", tr("Text (*.txt *.*)")); ui->lineEdit_FilePath->setText(fileName); txtSendFilePathName = ui->lineEdit_FilePath->text(); qDebug()<<txtSendFilePathName; } /*发送文件*/ void SerialPortQMain::slot_on_sendFileBtn_clicked() { if(!isOpenSerial) { QMessageBox::warning(this,"提示","串口没有打开!"); return ; } if(txtSendFilePathName!="") { QFile fileexample(txtSendFilePathName); if(!fileexample.open(QIODevice::ReadOnly)) return ; while (!fileexample.atEnd()) { QByteArray line = fileexample.readLine(); serialPort->write(line); //操作提示 operateStateDisplay( "正在发送文件..."); int p = fileexample.pos()/fileexample.size() *100; ui->progressBar_SendFile->setValue(p ); } QMessageBox::warning(this,"提示","发送完成!"); ui->progressBar_SendFile->setValue(0); //操作提示 operateStateDisplay("文件发送完成..."); } else{ QMessageBox::warning(this,"提示","请先选择要发送文件!"); } } //停止发送文件 void SerialPortQMain::slot_on_stopSend_clicked() { } /*清空发送区*/ void SerialPortQMain::slot_on_clearSendBtn_clicked() { ui->lineEditSend->clear(); } //statebar显示 QString SerialPortQMain::operateStateDisplay(QString operateStateChange) { ui->statusBar->addWidget(operateState); operateState->setText("当前操作状态:"+operateStateChange); return operateStateChange; } //自定义波特率 void SerialPortQMain::slot_on_baudRate(const QString &text) { if(text == "custom") { ui->comboBoxBaudRate->setEditable(true); } else{ ui->comboBoxBaudRate->setEditable(false); } } //////////////////////// void SerialPortQMain::StringToHex(QString str,QByteArray &senddata) { int hexdata,lowhexdata; int hexdatalen = 0; int len = str.length(); senddata.resize(len/2); char lstr,hstr; for(int i=0; i<len; ) { //char lstr, hstr=str[i].toLatin1(); if(hstr == ' ') { i++; continue; } i++; if(i >= len) break; lstr = str[i].toLatin1(); hexdata = ConvertHexChar(hstr); lowhexdata = ConvertHexChar(lstr); if((hexdata == 16) || (lowhexdata == 16)) break; else hexdata = hexdata*16+lowhexdata; i++; senddata[hexdatalen] = (char)hexdata; hexdatalen++; } senddata.resize(hexdatalen); } char SerialPortQMain::ConvertHexChar(char ch) { if((ch >= '0') && (ch <= '9')) return ch-0x30; else if((ch >= 'A') && (ch <= 'F')) return ch-'A'+10; else if((ch >= 'a') && (ch <= 'f')) return ch-'a'+10; else return (-1); }