初学Qt,完成一个简单的串口调试工具
最终效果图,图上功能都可实现
UI界面绘制
代码如下
串口调试工具开发
1.创建工程QWidget,根据串口调试工具绘制Ui界面
给每个控件设置特定名,方便调用
2.在.pro文件添加代码
QT += core gui serialport
3.在.h文件头添加代码
#include <QSerialPort>
#include <QSerialPortInfo>
private:
Ui::Widget *ui;
QSerialPort * serialport;//串口端口
QTimer *timSend;//创建定时器对象
QString mTime;//拼接日志样式对象
QDateTime mDateTime;//获取当前时间
QByteArray Sendtext;//发送缓存区
QByteArray Receivetext;//接收缓存区
long int SendByte=0;//发送字符数
long int ReceByte=0;//接收字符数
4.给串口号设置自动获取电脑中的串口
//遍历可用串口设备
//创建一个QStringList 对象来存储端口名
QStringList serialPort_Name;
//foreach遍历方法
foreach(const QSerialPortInfo &info,QSerialPortInfo::availablePorts()){
//端口名呈现格式
serialPort_Name << info.portName();
}
//添加到控件串口显示
ui->PostName->addItems(serialPort_Name);
*如果需要过滤无用串口,代码如下
//获取串口列表
int snum=0;
//用下面的方法会过滤掉一些无用的串口
QSerialPort temp_serial;
foreach (const QSerialPortInfo &Info, QSerialPortInfo::availablePorts()) {
temp_serial.setPort(Info);
if(temp_serial.open(QIODevice::ReadWrite)){//如果串口是可以读写方式打开的
ui->PostName->addItem(Info.portName());
temp_serial.close();
++snum;
}
}
//默认选中第0项
if(snum>2){
ui->PostName->setCurrentIndex(1);
}
ui->PostName->currentText();
*如果需要对下拉框进行自适应设置,代码如下
//下拉列表自适应
/* 获取最长字符串 */
int maxlen = 0;
for (int index = 0; index < ui->PostName->count(); index++)
{
if (ui->PostName->itemText(index).length() > maxlen)
{
maxlen = ui->PostName->itemText(index).length();
}
}
/*获取字体磅值转换为像素值*/
int fontsize = ui->PostName->font().pointSize();//获取字体的磅值
ui->PostName->setFixedWidth(fontsize * maxlen * 0.75);//设置像素值
```
接下来需声明一个串口全局对象,在.h文件中
QSerialPort * serialport;//串口端口
声明后在.cpp文件中创建出来
serialport = new QSerialPort(this);//声明后把对象创建出来
给打开按钮设置转到槽
.h文件自动生成
private slots:
void on_Btn_Open_clicked();//打开键按下
/*打开按钮配置*/
/*串口参数配置*/
void Widget::on_Btn_Open_clicked()
{
if (ui->Btn_Open->text()=="打开") {
//设置串口名
serialport->setPortName(ui->PostName->currentText());
//设置波特率
switch (ui->BaudRate->currentIndex())
{
case 0:
serialport->setBaudRate(QSerialPort::Baud19200,QSerialPort::AllDirections);
break;
case 1:
serialport->setBaudRate(QSerialPort::Baud38400,QSerialPort::AllDirections);
break;
case 2:
serialport->setBaudRate(QSerialPort::Baud57600,QSerialPort::AllDirections);
break;
default:
serialport->setBaudRate(QSerialPort::Baud115200,QSerialPort::AllDirections);
break;
}
/* 检验位、数据位、停止位、流控制 与 波特率(switch)写法一致 */
//打开串口
if(!serialport->open(QIODevice::ReadWrite)){
QMessageBox::about(NULL,"提示","无法打开串口");
return;
}
/*点击后效果*/
//设置控件不可编辑
ui->PostName->setEnabled(false);
ui->BaudRate->setEnabled(false);
ui->Parity->setEnabled(false);
ui->DataBits->setEnabled(false);
ui->StopBits->setEnabled(false);
ui->FlowControl->setEnabled(false);
//点击打开按钮后发送和循环发送可编辑
ui->Btn_Send->setEnabled(true);
ui->Cyclet_time->setEnabled(true);
//点击打开后显示关闭
ui->Btn_Open->setText("关闭");
ui->Btn_Open->setStyleSheet("QPushButton{color:red;background:yellow}");
/*点击前效果*/
与上方代码相反,写在else{}中
```
获取时间戳
/*获取时间戳*/
先在.h头文件创建对象,如经常使用的对象,都在头文件创建,减少损耗资源
QString mTime;
QDateTime mDateTime;
.cpp文件写对应事件
if(ui->Re_Log->isChecked()){
mDateTime = QDateTime::currentDateTime();
//拼接日志样式
mTime = "[";
mTime += mDateTime.toString("[yyyy-MM-dd hh:mm:ss.zzz]") ;
mTime += "]:RECV ->" ;
mTime += Receivetext;
ui->Re_Edit->append(mTime);
}
添加数据换行问题,insertPlainText函数在原数据末尾直接添加,可以使用append函数替代换行添加
if(ui->Re_Line->checkState()==Qt::Checked)
{
ui->Re_Edit->append(Receivetext);
}
else
{
ui->Re_Edit->insertPlainText(Receivetext);
}
```
**串口接收代码**
/*串口接收*/
void Widget::on_SerialPort_readyRead(){
int i,length;
Receivetext = serialport->readAll();
//接收字节并显示
ReceByte+=Receivetext.length();
ui->Re_Byte->setText(QString::number(ReceByte));
//十六进制
if(ui->Re_Hex->checkState()==Qt::Checked)
{
//字符串转十六进制
Receivetext = Receivetext.toHex().toUpper();
length=Receivetext.length();
for(i=0;i<=length/2;i++)
{
//插入空格字符串
Receivetext.insert((2+3*i),' ');
}
}
//自动换行
if(ui->Re_Line->checkState()==Qt::Checked)
{
ui->Re_Edit->append(Receivetext);
}
//日志显示样式
else if(ui->Re_Log->isChecked()){
//获取当前时间
mDateTime = QDateTime::currentDateTime();
//时间展示拼接样式
mTime = "[";
mTime += mDateTime.toString("[yyyy-MM-dd hh:mm:ss.zzz]") ;
mTime += "]:RECV ->" ;
mTime += Receivetext;
//append自动换行
ui->Re_Edit->append(mTime);
}
else
{
//原数据末尾添加(文本接收)
ui->Re_Edit->insertPlainText(Receivetext);
}
}
**串口发送代码**
void Widget::on_Btn_Send_clicked()
{
int i,length;
Sendtext = ui->Se_Edit->toPlainText().toUtf8();
//发送设置HEX
if(ui->Se_Hex->checkState()==Qt::Checked)
{
//转换成十六进制
Sendtext = Sendtext.toHex().toUpper();
length=Sendtext.length();
for(i=0;i<=length/2;i++)
{
//插入空格字符串
Sendtext.insert((2+3*i),' ');
}
serialport->write(Sendtext);
}
else
{
serialport->write(Sendtext);
}
//发送字节显示
SendByte+=Sendtext.length();
ui->Se_Byte->setText(QString::number(SendByte));
// ui->Se_Edit->moveCursor(QTextCursor::End);
}
定时器使用方法
在.h头文件中
//定义并初始化mTimerID
int mTimerID= 0;
/*定时器定时发送*/
//设置默认值1000ms
mTimerID = startTimer(500);
在.cpp文件中
void Widget::timerEvent(QTimerEvent *event)
{
qDebug()<<"我是定时器!";
}
void Widget::closeEvent(QCloseEvent *event)
{
if(mTimerID)
{
killTimer(mTimerID);
mTimerID = 0;
}
}
**串口循环发送代码**
在.h头文件
QTimer *timSend;//创建定时器对象
在.cpp文件
//定时发送=定时器
timSend=new QTimer;
timSend->setInterval(1000);//设置默认值1000ms
//定时器信号连接发送信号
connect(timSend,&QTimer::timeout,this,[=]()
{
on_Btn_Send_clicked();
});
ui界面给循环发送checkbox转到槽
void on_Cyclet_time_stateChanged(int arg1);//循环发送
void Widget::on_Cyclet_time_stateChanged(int arg1)
{
//获取复选框状态,没有选就为0,选择了就为2
if(arg1==0)
{
timSend->stop();
}
else {
//对输入的值大小的限制,小于10会弹出对话框提示
if(ui->Se_Line_2->text().toInt()>=10)
{
timSend->start(ui->Se_Line_2->text().toInt());//设置时长,重新计数
}
else {
ui->Cyclet_time->setCheckState(Qt::Unchecked);
QMessageBox::information(this,"错误提示","定时发送最小间隔为10ms!");
}
}
}
```
清空按钮
在.h头文件
void on_Btn_Reclean_clicked();//清空接收区域
void on_Btn_Seclean_clicked();//清空发送区域
在.cpp文件
/*清空接收区域*/
void Widget::on_Btn_Reclean_clicked()
{
ui->Re_Edit->clear();
}
/*清空发送区域*/
void Widget::on_Btn_Seclean_clicked()
{
ui->Se_Edit->clear();
}
ASCII、HEX发送与接收
在.h头文件中
void on_Re_Hex_clicked();//点击十六进制接收
void on_Se_Ascll_clicked();//点击ASCII发送
在.cpp文件中
/*十六进制接收*/
void Widget::on_Re_Hex_clicked()
{
ui->Re_Ascll->setCheckState(Qt::Unchecked);
ui->Re_Hex->setCheckState(Qt::Checked);
}
/*ASCII发送*/
void Widget::on_Se_Ascll_clicked()
{
ui->Se_Ascll->setCheckState(Qt::Checked);
ui->Se_Hex->setCheckState(Qt::Unchecked);
}
复位计数
在.h头文件中
void on_Btn_Reset_clicked();//复位计数
在.cpp文件中
/*清除计数*/
void Widget::on_Btn_Reset_clicked()
{
SendByte = 0;
ReceByte = 0;
ui->Re_Byte->setText(QString::number(ReceByte));
ui->Se_Byte->setText(QString::number(SendByte));
}
```