第81讲 串口调试助手实现自动发送
为这个名叫“定时发送”的QCheckBox编写槽函数。
想要做出定时发送的效果,必须引入QT框架下的毫秒级定时器QTimer,查阅手册了解详情。
在widget.h内添加新的私有成员变量:
QTimer *timer;
在widget类的构造函数内部进行变量初始化:
ui->setupUi(this);
this->setLayout(ui->gridLayoutGlobal);
writeCntGobal=0;
readCntGobal=0;
serialStatus=false;
serialPort = new QSerialPort(this);
timer=new QTimer(this);
关联信号与槽函数,信号是timeout超时函数,槽函数是发送文本函数:
connect(timer,&QTimer::timeout,[=](){
on_btnSendContext_clicked();
});
先测试一下信号与槽是否成功关联,checkBox槽函数的逻辑是勾选后定时器开起,超时后执行槽函数然后自动重装载,如果没有勾选就关闭定时器:
void Widget::on_checkBoxSendInTime_clicked(bool checked)
{
if(checked)
{
timer->start(ui->lineEditTimeeach->text().toInt());
}else{
timer->stop();
}
}
测试结果如下,1S发两个,程序正常跑起来了。
接下来,我们会在串口关闭状态下屏蔽“定时发送”按键与“发送”按键;
打开串口定时发送时,屏蔽发送频率输入框与文本输入框。
setEnabled方法可以屏蔽上述的所有控件,进入一种“不可选中”的状态。其次,对于可以勾选的Check Box,setCheckState方法可以取消勾选状态对控件进行重置。
综上所述:
#include "widget.h"
#include "ui_widget.h"
#include <QMessageBox>
#include <QSerialPort>
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{
ui->setupUi(this);
this->setLayout(ui->gridLayoutGlobal);
writeCntGobal=0;
readCntGobal=0;
serialStatus=false;
serialPort = new QSerialPort(this);
timer=new QTimer(this);
connect(serialPort,&QSerialPort::readyRead,this,&Widget::on_serialData_readytoRead);
connect(timer,&QTimer::timeout,[=](){
on_btnSendContext_clicked();
});
ui->comboBox_baudRate->setCurrentIndex(6);
ui->comboBox_dataBit->setCurrentIndex(3);
QList <QSerialPortInfo> serialList=QSerialPortInfo::availablePorts();
for(QSerialPortInfo serialInfo:serialList)
{
//qDebug()<<serialInfo.portName();
ui->comboBox_serialNum->addItem(serialInfo.portName());
}
ui->btnSendContext->setEnabled(false);
ui->checkBoxSendInTime->setEnabled(false);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_btnCloseOrOpenSerial_clicked()
{
if(serialStatus==false)
{
//1.选择端口号
serialPort->setPortName(ui->comboBox_serialNum->currentText());
//2.配置波特率
serialPort->setBaudRate(ui->comboBox_baudRate->currentText().toInt());
//3.配置数据位
serialPort->setDataBits(QSerialPort::DataBits(ui->comboBox_dataBit->currentText().toUInt()));
//4.配置校验位
/*MARK DOWN :
enum Parity {
NoParity = 0,
EvenParity = 2,
OddParity = 3,
SpaceParity = 4,
MarkParity = 5,
UnknownParity = -1
};
Q_ENUM(Parity)
*/
switch(ui->comboBox_checkBit->currentIndex())
{
case 0:
serialPort->setParity(QSerialPort::NoParity);
break;
case 1:
serialPort->setParity(QSerialPort::EvenParity);
break;
case 2:
serialPort->setParity(QSerialPort::OddParity);
break;
case 3:
serialPort->setParity(QSerialPort::SpaceParity);
break;
case 4:
serialPort->setParity(QSerialPort::MarkParity);
break;
default:
serialPort->setParity(QSerialPort::UnknownParity);
break;
}
//5.配置停止位
serialPort->setStopBits(QSerialPort::StopBits(ui->comboBox_stopBit->currentText().toInt()));
//6.流控
if(ui->comboBox_fileCon->currentText()=="None")
serialPort->setFlowControl(QSerialPort::NoFlowControl);
//7.打开串口
if(serialPort->open(QIODevice::ReadWrite))
{
qDebug()<<"serial open";
serialStatus=true;
ui->btnSendContext->setEnabled(true);
ui->btnCloseOrOpenSerial->setText("关闭串口 ");
ui->comboBox_dataBit->setEnabled(false);
ui->comboBox_fileCon->setEnabled(false);
ui->comboBox_stopBit->setEnabled(false);
ui->comboBox_baudRate->setEnabled(false);
ui->comboBox_checkBit->setEnabled(false);
ui->comboBox_serialNum->setEnabled(false);
ui->checkBoxSendInTime->setEnabled(true);
}else{
QMessageBox msgBox;
msgBox.setWindowTitle("错误");
msgBox.setText("此串口已被占用或拔出!");
msgBox.exec();
}
}else{
serialStatus=false;
ui->btnSendContext->setEnabled(false);
serialPort->close();
ui->btnCloseOrOpenSerial->setText("打开串口 ");
ui->comboBox_dataBit->setEnabled(true);
ui->comboBox_fileCon->setEnabled(true);
ui->comboBox_stopBit->setEnabled(true);
ui->comboBox_baudRate->setEnabled(true);
ui->comboBox_checkBit->setEnabled(true);
ui->comboBox_serialNum->setEnabled(true);
ui->checkBoxSendInTime->setEnabled(false);
ui->checkBoxSendInTime->setCheckState(Qt::Unchecked);
timer->stop();
ui->lineEditTimeeach->setEnabled(true);
ui->lineEditSendContext->setEnabled(true);
}
}
void Widget::on_btnSendContext_clicked()
{
int writeCnt=0;
const char* sendData=ui->lineEditSendContext->text().toStdString().c_str();
writeCnt=serialPort->write(sendData);
if(writeCnt==-1){
ui->labelSendStatus->setText("Send Error!");
}else{
writeCntGobal+=writeCnt;
qDebug()<<"Send Ok! "<<sendData;
ui->labelSendStatus->setText("Send Ok!");
ui->labelSendcnt->setNum(writeCntGobal);
if(strcmp(sendData,sendBack.toStdString().c_str())!=0)
{
ui->textEditRecord->append(sendData);
sendBack=QString(sendData);
}
}
}
void Widget::on_serialData_readytoRead()
{
QString revMessage=serialPort->readAll();
if(revMessage!=NULL){
qDebug()<<"getMessage:"<<revMessage;
ui->textEditRev->append(revMessage);
readCntGobal+=revMessage.size();
ui->labelRevcnt->setNum(readCntGobal);
}else{
}
}
void Widget::on_checkBoxSendInTime_clicked(bool checked)
{
if(checked)
{
ui->lineEditTimeeach->setEnabled(false);
ui->lineEditSendContext->setEnabled(false);
timer->start(ui->lineEditTimeeach->text().toInt());
}else{
ui->lineEditTimeeach->setEnabled(true);
ui->lineEditSendContext->setEnabled(true);
timer->stop();
}
}
第82讲 如何自我验证新控件
先布置UI:
然后编写槽函数就行:
#include "widget.h"
#include "ui_widget.h"
#include <QTimer>
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
htim1=new QTimer(this);
connect(htim1,&QTimer::timeout,[=](){
qDebug()<<"time out";
});
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_btnStart_clicked()
{
htim1->start(1000);
}
void Widget::on_btnEnd_clicked()
{
htim1->stop();
}
void Widget::on_checkBox_clicked()
{
if(ui->checkBox->checkState()==Qt::Checked)
{
qDebug()<<"checkBox Checked!";
}else if(ui->checkBox->checkState()==Qt::Unchecked)
{
qDebug()<<"checkBox Unchecked!";
}
}
第83讲 解决遗留的Bug
①如果传输的字符串较长,可能会导致历史记录里发送过的字符串再次发送;问题的根源是解决QString到const char*的数据转换。
const char* sendData=ui->lineEditSendContext->text().toLocal8Bit().constData();
并且在比较当前字符串与已发送字符串的时候也做出修改:
if(strcmp(sendData,sendBack.toStdString().c_str())!=0)
{
ui->textEditRecord->append(sendData);
sendBack=QString::fromUtf8(sendData);
}
这个地方的字符label本来被吞了,现在可以通过拼接字符串解决:
ui->labelSendcnt->setText("Sent:"+QString::number(writeCntGobal));
ui->labelRevcnt->setText("Received:"+QString::number(readCntGobal));
最后槽函数:
void Widget::on_btnSendContext_clicked()
{
int writeCnt=0;
const char* sendData=ui->lineEditSendContext->text().toLocal8Bit().constData();
writeCnt=serialPort->write(sendData);
if(writeCnt==-1){
ui->labelSendStatus->setText("Send Error!");
}else{
writeCntGobal+=writeCnt;
qDebug()<<"Send Ok! "<<sendData;
ui->labelSendStatus->setText("Send Ok!");
//ui->labelSendcnt->setNum(writeCntGobal);
ui->labelSendcnt->setText("Sent:"+QString::number(writeCntGobal));
if(strcmp(sendData,sendBack.toStdString().c_str())!=0)
{
ui->textEditRecord->append(sendData);
sendBack=QString::fromUtf8(sendData);
}
}
}
第84讲 串口调试助手保存接收记录
为这两个按键添加槽函数:
void Widget::on_btnRevClear_clicked()
{
ui->textEditRev->setText("");
}
void Widget::on_btnRevSave_clicked()
{
QString fileName=QFileDialog::getSaveFileName(this,tr("Save File"),
"E:\\6_Qt Projects\\38_SerialPort\\SerialData\\serialData.txt",
tr("Text(*.txt)") );
if(fileName!=NULL)
{
QFile file(fileName);
if(!file.open(QIODevice::WriteOnly|QIODevice::Text))
return;
QTextStream out(&file);
out<<ui->textEditRev->toPlainText();
file.close();
}
}
第85讲 获取当前系统时间QDateTime
修改时间戳需要使用QDateTime这个类。
这一讲我们先做一个简单的实验,按下按键把时间戳要显示的字符内容刷新出来。
通过QDateTime内部的静态函数currentDateTime获取日期与时间:
QDateTime currentTime=QDateTime ::currentDateTime();
它的内部有date和time分别可以用来抓取年月日与时分秒:
所以槽函数:
void Widget::on_pushButton_clicked()
{
QDateTime currentTime=QDateTime ::currentDateTime();
QDate date=currentTime.date();
// ui->textEdit->setText(QString::number(date.year()));
// ui->textEdit->append(QString::number(date.month()));
// ui->textEdit->append(QString::number(date.day()));
QTime time=currentTime.time();
// ui->textEdit->append(QString::number(time.hour()));
// ui->textEdit->append(QString::number(time.minute()));
// ui->textEdit->append(QString::number(time.second()));
// QString nowTime=QString("%1-%2-%3 %4:%5:%6",
// date.year(),date.month(), date.day(),time.hour(),time.minute(),time.second());
QString nowTime=QString("%1-%2-%3 %4:%5:%6").arg(date.year()).arg(date.month()).
arg(date.day()).arg(time.hour()).arg(time.minute()).arg(time.second());
ui->textEdit->setText(nowTime);
}
注意QString内用占位符拼接字符串需要使用arg方法。
第86讲 串口调试助手右下角时间刷新
新增两个私有变量:
在构造函数内部初始化sysTick、关联信号与槽并且开始定时器:
sysTick=new QTimer(this);
connect(sysTick,SIGNAL(timeout()),this,SLOT(time_reflash()));
sysTick->start(100);
注意,刷新周期为100ms可以让肉眼无法察觉初始label和时间戳的切换。
编写一个API获取windows桌面上的时间:
QString Widget::getSystime()
{
QDateTime currentTime=QDateTime ::currentDateTime();
QDate date=currentTime.date();
QTime time=currentTime.time();
QString nowTime=QString("%1-%2-%3 %4:%5:%6").arg(date.year()).arg(date.month()).
arg(date.day()).arg(time.hour()).arg(time.minute()).arg(time.second());
return nowTime;
}
刷新时间的槽函数可以利用这个API:
void Widget::time_reflash()
{
ui->labelCurrentTime->setText(getSystime());
}
测试结果:
记录一下widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include <QDateTime>
#include <QFileDialog>
#include <QMessageBox>
#include <QSerialPort>
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{
ui->setupUi(this);
this->setLayout(ui->gridLayoutGlobal);
writeCntGobal=0;
readCntGobal=0;
serialStatus=false;
serialPort = new QSerialPort(this);
timer=new QTimer(this);
sysTick=new QTimer(this);
connect(sysTick,SIGNAL(timeout()),this,SLOT(time_reflash()));
sysTick->start(100);
connect(serialPort,&QSerialPort::readyRead,this,&Widget::on_serialData_readytoRead);
connect(timer,&QTimer::timeout,[=](){
on_btnSendContext_clicked();
});
ui->comboBox_baudRate->setCurrentIndex(6);
ui->comboBox_dataBit->setCurrentIndex(3);
QList <QSerialPortInfo> serialList=QSerialPortInfo::availablePorts();
for(QSerialPortInfo serialInfo:serialList)
{
//qDebug()<<serialInfo.portName();
ui->comboBox_serialNum->addItem(serialInfo.portName());
}
ui->btnSendContext->setEnabled(false);
ui->checkBoxSendInTime->setEnabled(false);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_btnCloseOrOpenSerial_clicked()
{
if(serialStatus==false)
{
//1.选择端口号
serialPort->setPortName(ui->comboBox_serialNum->currentText());
//2.配置波特率
serialPort->setBaudRate(ui->comboBox_baudRate->currentText().toInt());
//3.配置数据位
serialPort->setDataBits(QSerialPort::DataBits(ui->comboBox_dataBit->currentText().toUInt()));
//4.配置校验位
/*MARK DOWN :
enum Parity {
NoParity = 0,
EvenParity = 2,
OddParity = 3,
SpaceParity = 4,
MarkParity = 5,
UnknownParity = -1
};
Q_ENUM(Parity)
*/
switch(ui->comboBox_checkBit->currentIndex())
{
case 0:
serialPort->setParity(QSerialPort::NoParity);
break;
case 1:
serialPort->setParity(QSerialPort::EvenParity);
break;
case 2:
serialPort->setParity(QSerialPort::OddParity);
break;
case 3:
serialPort->setParity(QSerialPort::SpaceParity);
break;
case 4:
serialPort->setParity(QSerialPort::MarkParity);
break;
default:
serialPort->setParity(QSerialPort::UnknownParity);
break;
}
//5.配置停止位
serialPort->setStopBits(QSerialPort::StopBits(ui->comboBox_stopBit->currentText().toInt()));
//6.流控
if(ui->comboBox_fileCon->currentText()=="None")
serialPort->setFlowControl(QSerialPort::NoFlowControl);
//7.打开串口
if(serialPort->open(QIODevice::ReadWrite))
{
qDebug()<<"serial open";
serialStatus=true;
ui->btnSendContext->setEnabled(true);
ui->btnCloseOrOpenSerial->setText("关闭串口 ");
ui->comboBox_dataBit->setEnabled(false);
ui->comboBox_fileCon->setEnabled(false);
ui->comboBox_stopBit->setEnabled(false);
ui->comboBox_baudRate->setEnabled(false);
ui->comboBox_checkBit->setEnabled(false);
ui->comboBox_serialNum->setEnabled(false);
ui->checkBoxSendInTime->setEnabled(true);
}else{
QMessageBox msgBox;
msgBox.setWindowTitle("错误");
msgBox.setText("此串口已被占用或拔出!");
msgBox.exec();
}
}else{
serialStatus=false;
ui->btnSendContext->setEnabled(false);
serialPort->close();
ui->btnCloseOrOpenSerial->setText("打开串口 ");
ui->comboBox_dataBit->setEnabled(true);
ui->comboBox_fileCon->setEnabled(true);
ui->comboBox_stopBit->setEnabled(true);
ui->comboBox_baudRate->setEnabled(true);
ui->comboBox_checkBit->setEnabled(true);
ui->comboBox_serialNum->setEnabled(true);
ui->checkBoxSendInTime->setEnabled(false);
ui->checkBoxSendInTime->setCheckState(Qt::Unchecked);
timer->stop();
ui->lineEditTimeeach->setEnabled(true);
ui->lineEditSendContext->setEnabled(true);
}
}
void Widget::on_btnSendContext_clicked()
{
int writeCnt=0;
const char* sendData=ui->lineEditSendContext->text().toLocal8Bit().constData();
writeCnt=serialPort->write(sendData);
if(writeCnt==-1){
ui->labelSendStatus->setText("Send Error!");
}else{
writeCntGobal+=writeCnt;
qDebug()<<"Send Ok! "<<sendData;
ui->labelSendStatus->setText("Send Ok!");
//ui->labelSendcnt->setNum(writeCntGobal);
ui->labelSendcnt->setText("Sent:"+QString::number(writeCntGobal));
if(strcmp(sendData,sendBack.toStdString().c_str())!=0)
{
ui->textEditRecord->append(sendData);
sendBack=QString::fromUtf8(sendData);
}
}
}
void Widget::on_serialData_readytoRead()
{
QString revMessage=serialPort->readAll();
if(revMessage!=NULL){
qDebug()<<"getMessage:"<<revMessage;
ui->textEditRev->append(revMessage);
readCntGobal+=revMessage.size();
//ui->labelRevcnt->setNum(readCntGobal);
ui->labelRevcnt->setText("Received:"+QString::number(readCntGobal));
}else{
}
}
void Widget::on_checkBoxSendInTime_clicked(bool checked)
{
if(checked)
{
ui->lineEditTimeeach->setEnabled(false);
ui->lineEditSendContext->setEnabled(false);
timer->start(ui->lineEditTimeeach->text().toInt());
}else{
ui->lineEditTimeeach->setEnabled(true);
ui->lineEditSendContext->setEnabled(true);
timer->stop();
}
}
void Widget::on_btnRevClear_clicked()
{
ui->textEditRev->setText("");
}
void Widget::on_btnRevSave_clicked()
{
QString fileName=QFileDialog::getSaveFileName(this,tr("Save File"),
"E:\\6_Qt Projects\\38_SerialPort\\SerialData\\serialData.txt",
tr("Text(*.txt)") );
if(fileName!=NULL)
{
QFile file(fileName);
if(!file.open(QIODevice::WriteOnly|QIODevice::Text))
return;
QTextStream out(&file);
out<<ui->textEditRev->toPlainText();
file.close();
}
}
QString Widget::getSystime()
{
QDateTime currentTime=QDateTime ::currentDateTime();
QDate date=currentTime.date();
QTime time=currentTime.time();
QString nowTime=QString("%1-%2-%3 %4:%5:%6").arg(date.year()).arg(date.month()).
arg(date.day()).arg(time.hour()).arg(time.minute()).arg(time.second());
return nowTime;
}
void Widget::time_reflash()
{
ui->labelCurrentTime->setText(getSystime());
}
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QSerialPortInfo>
#include <QDebug>
#include <QTimer>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private slots:
void on_btnCloseOrOpenSerial_clicked();
void on_btnSendContext_clicked();
void on_serialData_readytoRead();
void on_checkBoxSendInTime_clicked(bool checked);
void on_btnRevClear_clicked();
void on_btnRevSave_clicked();
void time_reflash();
private:
Ui::Widget *ui;
QSerialPort *serialPort;
int writeCntGobal;
int readCntGobal;
QString sendBack;
bool serialStatus;
QTimer *timer;
// QString nowTime;
QString getSystime();
QTimer *sysTick;
};
#endif // WIDGET_H
第87讲 优化时间显示
优化了arg方法的使用,约束数据的数位,如果不足,就用0来补:
QString Widget::getSystime()
{
QDateTime currentTime=QDateTime ::currentDateTime();
QDate date=currentTime.date();
QTime time=currentTime.time();
QString nowTime=QString("%1-%2-%3 %4:%5:%6")
.arg(date.year(),4,10,QChar('0'))
.arg(date.month(),2,10,QChar('0'))
.arg(date.day(),2,10,QChar('0'))
.arg(time.hour(),2,10,QChar('0'))
.arg(time.minute(),2,10,QChar('0'))
.arg(time.second(),2,10,QChar('0'));
return nowTime;
}
同时把接收时间的打印做出来。
修改on_serialData_readytoRead函数即可:
void Widget::on_serialData_readytoRead()
{
QString revMessage = serialPort->readAll();
if(revMessage != NULL){
if(ui->checkBoxRevTime->checkState()== Qt::Unchecked){
ui->textEditRev->append(revMessage);
}
else if(ui->checkBoxRevTime->checkState()== Qt::Checked){
ui->textEditRev->append("["+getSystime()+"] "+revMessage);
}
readCntGobal += revMessage.size();
ui->labelRevcnt->setText("Received:"+QString::number(readCntGobal));
}
}
第88讲 串口调试助手初步实现HEX显示
这一讲实现的功能是将textEditRev控件上面的字符串转换成Hex格式:
void Widget::on_checkBoxHexDisplay_clicked(bool checked)
{
if(checked){
//1.读取textEdit上的内容
QString temp=ui->textEditRev->toPlainText();
//2.转换成Hex
QByteArray qtemp=temp.toUtf8();
qtemp=qtemp.toHex();
//3.显示
ui->textEditRev->setText(QString::fromUtf8(qtemp));
}else{
//1.读取textEdit上的Hex内容
QString tempHexString=ui->textEditRev->toPlainText();
QByteArray tempHexQByteArray=tempHexString.toUtf8();
QByteArray tempQByteString=QByteArray::fromHex(tempHexQByteArray);
ui->textEditRev->setText(QString::fromUtf8(tempQByteString));
}
}
第89讲 串口调试助手关联Hex接收
我们现在希望勾选checkBoxHexDisplay之后,接收的内容都能自动转换为Hex,解决的思路还是和添加时间戳一样,修改readytoRead函数:
void Widget::on_serialData_readytoRead()
{
QString revMessage = serialPort->readAll();
if(revMessage != NULL){
if(ui->checkBoxHexDisplay->isChecked())
{
//将接受到的字符串转换为十六进制
QByteArray tempHexString=revMessage.toUtf8().toHex();
//捕获原来控件上的内容
QString orignalString=ui->textEditRev->toPlainText();
//拼接字符串
tempHexString=orignalString.toUtf8()+tempHexString;
ui->textEditRev->setText(QString::fromUtf8(tempHexString));
}else{
if(ui->checkBoxRevTime->checkState()== Qt::Unchecked){
ui->textEditRev->append(revMessage);
}
else if(ui->checkBoxRevTime->checkState()== Qt::Checked){
ui->textEditRev->append("["+getSystime()+"]"+revMessage);
}
readCntGobal += revMessage.size();
ui->labelRevcnt->setText("Received:"+QString::number(readCntGobal));
}
}
}
第90讲 串口调试助手HEX发送单片机联调测试
修改发送函数,新添加了勾选上Hex发送的条件判断语句。
void Widget::on_btnSendContext_clicked()
{
int writeCnt=0;
const char* sendData=ui->lineEditSendContext->text().toLocal8Bit().constData();
if(ui->checkBoxHexSend->isChecked()){
QString temp=ui->lineEditSendContext->text();
//判断是否为偶数位
QByteArray tempArray=temp.toLocal8Bit();
if(tempArray.size()%2!=0)
{
ui->labelSendStatus->setText("Error Input!");
return;
}
//判断是否符合十六进制的表达
for(char c:tempArray)
{
if(!std::isxdigit(c)){
ui->labelSendStatus->setText("Error Input!");
return;
}else{
}
}
//转换成十六进制数发送
QByteArray arraySend=QByteArray::fromHex(tempArray);
writeCnt=serialPort->write(arraySend);
}else{
writeCnt=serialPort->write(sendData);
}
if(writeCnt==-1){
ui->labelSendStatus->setText("Send Error!");
}else{
writeCntGobal+=writeCnt;
qDebug()<<"Send Ok! "<<sendData;
ui->labelSendStatus->setText("Send OK!");
//ui->labelSendcnt->setNum(writeCntGobal);
ui->labelSendcnt->setText("Sent:"+QString::number(writeCntGobal));
if(strcmp(sendData,sendBack.toStdString().c_str())!=0)
{
ui->textEditRecord->append(sendData);
sendBack=QString::fromUtf8(sendData);
}
}
}
本章结束,上传一下代码块作为备份
widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include <QDateTime>
#include <QFileDialog>
#include <QMessageBox>
#include <QSerialPort>
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{
ui->setupUi(this);
this->setLayout(ui->gridLayoutGlobal);
writeCntGobal=0;
readCntGobal=0;
serialStatus=false;
serialPort = new QSerialPort(this);
timer=new QTimer(this);
sysTick=new QTimer(this);
connect(sysTick,SIGNAL(timeout()),this,SLOT(time_reflash()));
sysTick->start(100);
connect(serialPort,&QSerialPort::readyRead,this,&Widget::on_serialData_readytoRead);
connect(timer,&QTimer::timeout,[=](){
on_btnSendContext_clicked();
});
ui->comboBox_baudRate->setCurrentIndex(6);
ui->comboBox_dataBit->setCurrentIndex(3);
QList <QSerialPortInfo> serialList=QSerialPortInfo::availablePorts();
for(QSerialPortInfo serialInfo:serialList)
{
//qDebug()<<serialInfo.portName();
ui->comboBox_serialNum->addItem(serialInfo.portName());
}
ui->btnSendContext->setEnabled(false);
ui->checkBoxSendInTime->setEnabled(false);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_btnCloseOrOpenSerial_clicked()
{
if(serialStatus==false)
{
//1.选择端口号
serialPort->setPortName(ui->comboBox_serialNum->currentText());
//2.配置波特率
serialPort->setBaudRate(ui->comboBox_baudRate->currentText().toInt());
//3.配置数据位
serialPort->setDataBits(QSerialPort::DataBits(ui->comboBox_dataBit->currentText().toUInt()));
//4.配置校验位
/*MARK DOWN :
enum Parity {
NoParity = 0,
EvenParity = 2,
OddParity = 3,
SpaceParity = 4,
MarkParity = 5,
UnknownParity = -1
};
Q_ENUM(Parity)
*/
switch(ui->comboBox_checkBit->currentIndex())
{
case 0:
serialPort->setParity(QSerialPort::NoParity);
break;
case 1:
serialPort->setParity(QSerialPort::EvenParity);
break;
case 2:
serialPort->setParity(QSerialPort::OddParity);
break;
case 3:
serialPort->setParity(QSerialPort::SpaceParity);
break;
case 4:
serialPort->setParity(QSerialPort::MarkParity);
break;
default:
serialPort->setParity(QSerialPort::UnknownParity);
break;
}
//5.配置停止位
serialPort->setStopBits(QSerialPort::StopBits(ui->comboBox_stopBit->currentText().toInt()));
//6.流控
if(ui->comboBox_fileCon->currentText()=="None")
serialPort->setFlowControl(QSerialPort::NoFlowControl);
//7.打开串口
if(serialPort->open(QIODevice::ReadWrite))
{
qDebug()<<"serial open";
serialStatus=true;
ui->btnSendContext->setEnabled(true);
ui->btnCloseOrOpenSerial->setText("关闭串口 ");
ui->comboBox_dataBit->setEnabled(false);
ui->comboBox_fileCon->setEnabled(false);
ui->comboBox_stopBit->setEnabled(false);
ui->comboBox_baudRate->setEnabled(false);
ui->comboBox_checkBit->setEnabled(false);
ui->comboBox_serialNum->setEnabled(false);
ui->checkBoxSendInTime->setEnabled(true);
}else{
QMessageBox msgBox;
msgBox.setWindowTitle("错误");
msgBox.setText("此串口已被占用或拔出!");
msgBox.exec();
}
}else{
serialStatus=false;
ui->btnSendContext->setEnabled(false);
serialPort->close();
ui->btnCloseOrOpenSerial->setText("打开串口 ");
ui->comboBox_dataBit->setEnabled(true);
ui->comboBox_fileCon->setEnabled(true);
ui->comboBox_stopBit->setEnabled(true);
ui->comboBox_baudRate->setEnabled(true);
ui->comboBox_checkBit->setEnabled(true);
ui->comboBox_serialNum->setEnabled(true);
ui->checkBoxSendInTime->setEnabled(false);
ui->checkBoxSendInTime->setCheckState(Qt::Unchecked);
timer->stop();
ui->lineEditTimeeach->setEnabled(true);
ui->lineEditSendContext->setEnabled(true);
}
}
void Widget::on_btnSendContext_clicked()
{
int writeCnt=0;
const char* sendData=ui->lineEditSendContext->text().toLocal8Bit().constData();
if(ui->checkBoxHexSend->isChecked()){
QString temp=ui->lineEditSendContext->text();
//判断是否为偶数位
QByteArray tempArray=temp.toLocal8Bit();
if(tempArray.size()%2!=0)
{
ui->labelSendStatus->setText("Error Input!");
return;
}
//判断是否符合十六进制的表达
for(char c:tempArray)
{
if(!std::isxdigit(c)){
ui->labelSendStatus->setText("Error Input!");
return;
}else{
}
}
//转换成十六进制数发送
QByteArray arraySend=QByteArray::fromHex(tempArray);
writeCnt=serialPort->write(arraySend);
}else{
writeCnt=serialPort->write(sendData);
}
if(writeCnt==-1){
ui->labelSendStatus->setText("Send Error!");
}else{
writeCntGobal+=writeCnt;
qDebug()<<"Send Ok! "<<sendData;
ui->labelSendStatus->setText("Send OK!");
//ui->labelSendcnt->setNum(writeCntGobal);
ui->labelSendcnt->setText("Sent:"+QString::number(writeCntGobal));
if(strcmp(sendData,sendBack.toStdString().c_str())!=0)
{
ui->textEditRecord->append(sendData);
sendBack=QString::fromUtf8(sendData);
}
}
}
void Widget::on_serialData_readytoRead()
{
QString revMessage = serialPort->readAll();
if(revMessage != NULL){
if(ui->checkBoxHexDisplay->isChecked())
{
//将接受到的字符串转换为十六进制
QByteArray tempHexString=revMessage.toUtf8().toHex();
//捕获原来控件上的内容
QString orignalString=ui->textEditRev->toPlainText();
//拼接字符串
tempHexString=orignalString.toUtf8()+tempHexString;
ui->textEditRev->setText(QString::fromUtf8(tempHexString));
}else{
if(ui->checkBoxRevTime->checkState()== Qt::Unchecked){
ui->textEditRev->append(revMessage);
}
else if(ui->checkBoxRevTime->checkState()== Qt::Checked){
ui->textEditRev->append("["+getSystime()+"]"+revMessage);
}
readCntGobal += revMessage.size();
ui->labelRevcnt->setText("Received:"+QString::number(readCntGobal));
}
}
}
void Widget::on_checkBoxSendInTime_clicked(bool checked)
{
if(checked)
{
ui->lineEditTimeeach->setEnabled(false);
ui->lineEditSendContext->setEnabled(false);
timer->start(ui->lineEditTimeeach->text().toInt());
}else{
ui->lineEditTimeeach->setEnabled(true);
ui->lineEditSendContext->setEnabled(true);
timer->stop();
}
}
void Widget::on_btnRevClear_clicked()
{
ui->textEditRev->setText("");
}
void Widget::on_btnRevSave_clicked()
{
QString fileName=QFileDialog::getSaveFileName(this,tr("Save File"),
"E:\\6_Qt Projects\\42_SerialTime\\SerialData\\serialData.txt",
tr("Text(*.txt)") );
if(fileName!=NULL)
{
QFile file(fileName);
if(!file.open(QIODevice::WriteOnly|QIODevice::Text))
return;
QTextStream out(&file);
out<<ui->textEditRev->toPlainText();
file.close();
}
}
QString Widget::getSystime()
{
QDateTime currentTime=QDateTime ::currentDateTime();
QDate date=currentTime.date();
QTime time=currentTime.time();
QString nowTime=QString("%1-%2-%3 %4:%5:%6")
.arg(date.year(),4,10,QChar('0'))
.arg(date.month(),2,10,QChar('0'))
.arg(date.day(),2,10,QChar('0'))
.arg(time.hour(),2,10,QChar('0'))
.arg(time.minute(),2,10,QChar('0'))
.arg(time.second(),2,10,QChar('0'));
return nowTime;
}
void Widget::time_reflash()
{
ui->labelCurrentTime->setText(getSystime());
}
void Widget::on_checkBoxHexDisplay_clicked(bool checked)
{
if(checked){
//1.读取textEdit上的内容
QString temp=ui->textEditRev->toPlainText();
//2.转换成Hex
QByteArray qtemp=temp.toUtf8();
qtemp=qtemp.toHex();
//3.显示
ui->textEditRev->setText(QString::fromUtf8(qtemp));
}else{
//1.读取textEdit上的Hex内容
QString tempHexString=ui->textEditRev->toPlainText();
QByteArray tempHexQByteArray=tempHexString.toUtf8();
QByteArray tempQByteString=QByteArray::fromHex(tempHexQByteArray);
ui->textEditRev->setText(QString::fromUtf8(tempQByteString));
}
}
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QSerialPortInfo>
#include <QDebug>
#include <QTimer>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private slots:
void on_btnCloseOrOpenSerial_clicked();
void on_btnSendContext_clicked();
void on_serialData_readytoRead();
void on_checkBoxSendInTime_clicked(bool checked);
void on_btnRevClear_clicked();
void on_btnRevSave_clicked();
void time_reflash();
void on_checkBoxHexDisplay_clicked(bool checked);
private:
Ui::Widget *ui;
QSerialPort *serialPort;
int writeCntGobal;
int readCntGobal;
QString sendBack;
bool serialStatus;
QTimer *timer;
// QString nowTime;
QString getSystime();
QTimer *sysTick;
};
#endif // WIDGET_H
界面UI概览