超级好用的Qt5串口蓝牙调试助手
开发工具: qt-opensource-windows-x86-5.14.2 (编程语言C++)
目录
前言
一、软件概要:
二、软件界面:
1.App动态演示
---- ◇♣♡♠ ----
2.其他扩展App展示
三、mainwindow.cpp源码
四、获取 >> 源码以及Git记录:
总结
前言
串口蓝牙调试助手支持常用的50bps - 10Mbps波特率,能设置校验、数据位和停止位,能以ASCII码或十六进制接收或发送任何数据或字符,可以任意设定自动发送周期,并能将接收数据实时保存成文本文件,能发送任意大小的数据或字符。支持蓝牙功能 !
备注: QT串口蓝牙调试助手(初级篇)是从缤果串口网络蓝牙调试助手(高级篇)分离出来的简单应用
英文名:Serial_Bluetooth_Debug_Assistant_V1.0
支持:常用的50bps ~ 10Mbps波特率
类型:串口蓝牙调试助手
软件大小:12M
软件版本:V1.0
软件下载&更新:百度网盘链接_提取码 6666
一、软件概要:
一款强大而稳定的Qt串口升级工具,支持常用的110-921600bps波特率及自定义波特率,波特率最高可支持8000000(串口硬件有关),可适应于非标准波特率。支持动态修改串口和波特率,历史发送以及实时保存日志。
二、软件界面:
1.App动态演示
2.其他扩展App展示
三、mainwindow.cpp源码
#include "mainwindow.h"
#include "ui_mainwindow.h"#if defined __Serial__ || defined __Bluetooth__
CommProType_Enum CommProType = Serial_Comm;
#endif//Qt5.14.2(MinGW 7.3.0 64-bit) 区分32bit和64bit工程 ; 切换目录命令 cd /d 目录
//打包命令: windeployqt 项目名.exe 程序打包:Enigma Virtual Box 注意: 打包别压缩,否则打开exe文件会久一些
MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);QString WindowTitle = "Serial Bluetooth Debug Assistant V1.0";setWindowTitle(WindowTitle);#ifdef __Serial__//连接信号和槽StatusBarInit();TimerInit();NewFile();connect(&serial, SIGNAL(readyRead()), this, SLOT(serialPort_readyRead()));//波特率默认选择下拉:921600ui->baudrateBox->setCurrentIndex(21);on_searchButton_clicked();LoadSerialPortConfigParameters();#endif
}MainWindow::~MainWindow()
{delete ui;
}#ifdef __Serial__void MainWindow::NewFile()
{//新建文件夹QDir *dir = new QDir;bool exist = dir->exists(NewFolder_SerialPort_Config);if(!exist){//qDebug() << "new file";dir->mkdir(NewFolder_SerialPort_Config);}else{//qDebug() << "file exist";}exist = dir->exists(NewFolder_SerialPort_Log);if(!exist){dir->mkdir(NewFolder_SerialPort_Log);}
}void MainWindow::LoadSerialPortConfigParameters()
{//-------------------------------------------------------------------------------------------------------------//读取ini文件//com配置QSettings *configIniRead = new QSettings(FileName_SerialPort_Config_ini_Path, QSettings::IniFormat);configIniRead->setIniCodec(QTextCodec::codecForName("GB18030"));//将读取到的ini文件保存在QString中,先取值,然后通过toString()函数转换成QString类型int portNameIndex = configIniRead->value("MainWindow_SerialComPara/portNameIndex").toInt();int baudRateIndex = configIniRead->value("MainWindow_SerialComPara/baudRateIndex").toInt();int dataBitsIndex = configIniRead->value("MainWindow_SerialComPara/dataBitsIndex").toInt();int ParityIndex = configIniRead->value("MainWindow_SerialComPara/ParityIndex").toInt();int stopBitsIndex = configIniRead->value("MainWindow_SerialComPara/stopBitsIndex").toInt();int flowControlIndex = configIniRead->value("MainWindow_SerialComPara/flowControlIndex").toInt();customBaudRate = configIniRead->value("MainWindow_SerialComPara/customBaudRate").toInt();if(customBaudRate!=0) ui->baudrateBox->setItemText(0,QString::number(customBaudRate));//TRACE_2(portNameIndex,SerialPortNum);if(portNameIndex >= SerialPortNum) portNameIndex = 0; //修复串口减少时,串口软件打不开的问题ui->portNameBox->setCurrentIndex(portNameIndex);ui->baudrateBox->setCurrentIndex(baudRateIndex);ui->dataBitsBox->setCurrentIndex(dataBitsIndex);ui->ParityBox->setCurrentIndex(ParityIndex);ui->stopBitsBox->setCurrentIndex(stopBitsIndex);ui->flowControlBox->setCurrentIndex(flowControlIndex);//默认if(0==baudRateIndex && 0==dataBitsIndex){ui->baudrateBox->setCurrentIndex(6);ui->dataBitsBox->setCurrentIndex(3);}//接收设置int hexReceive = configIniRead->value("MainWindow_SerialReceivePara/hexReceive").toInt();if(hexReceive) ui->checkBox_hexReceive->setChecked(1);else ui->checkBox_hexReceive->setChecked(0);#if 0int AutoLineBreak = configIniRead->value("MainWindow_SerialReceivePara/AutoLineBreak").toInt();if(AutoLineBreak) ui->checkBox_AutoLineBreak->setChecked(1);else ui->checkBox_AutoLineBreak->setChecked(0);//ui->checkBox_AutoLineBreak->setChecked(1); //默认1int displaySend = configIniRead->value("MainWindow_SerialReceivePara/displaySend").toInt();if(displaySend) ui->checkBox_displaySend->setChecked(1);else ui->checkBox_displaySend->setChecked(0);int displayTime = configIniRead->value("MainWindow_SerialReceivePara/displayTime").toInt();if(displayTime) ui->checkBox_displayTime->setChecked(1);else ui->checkBox_displayTime->setChecked(0);#endif//发送设置int hexSend = configIniRead->value("MainWindow_SerialSendPara/hexSend").toInt();if(hexSend) ui->checkBox_hexSend->setChecked(1);else ui->checkBox_hexSend->setChecked(0);int Send_CR_LF = configIniRead->value("MainWindow_SerialSendPara/Send_CR_LF").toInt();if(Send_CR_LF) ui->checkBox_CR_LF->setChecked(1);else ui->checkBox_CR_LF->setChecked(0);if(customBaudRate!=0) ui->baudrateBox->setItemText(0,QString::number(customBaudRate)); //加载语言后会修改为Custom//读取完成后删除指针delete configIniRead;//-------------------------------------------------------------------------------------------------------------//历史发送数据读取//读取ini文件QSettings *SendHistoryDataIniRead = new QSettings(FileName_SerialPort_SendHistoryData_ini_Path, QSettings::IniFormat);SendHistoryDataIniRead->setIniCodec(QTextCodec::codecForName("GB18030"));QString SendText = SendHistoryDataIniRead->value("MainWindow_SerialSendData/SendText").toString();ui->sendTextEdit->setText(SendText);int count = SendHistoryDataIniRead->value("MainWindow_SerialSendHistoryData/ItemTotalNum").toInt();//qDebug() << "count:" << count;if(count){ui->comboBox_sendHistory->clear();for(int i=0; i<count; i++){QString ItemNum = "MainWindow_SerialSendHistoryData/";ItemNum += QString("%1").arg(i,3,10,QLatin1Char('0'));QString dataStr = SendHistoryDataIniRead->value(ItemNum).toString();ui->comboBox_sendHistory->addItem(dataStr);}}//读取完成后删除指针delete SendHistoryDataIniRead;
}void MainWindow::SaveSerialPortConfigParameters()
{//*************************************************************************************************************//Qt中使用QSettings类读写ini文件//QSettings构造函数的第一个参数是ini文件的路径,第二个参数表示针对ini文件,第三个参数可以缺省QSettings *configIniWrite = new QSettings(FileName_SerialPort_Config_ini_Path, QSettings::IniFormat);configIniWrite->setIniCodec(QTextCodec::codecForName("GB18030"));//向ini文件的第二个节写入内容,MainWindow 节下的第5个参数if(ui->baudrateBox->currentIndex()==0 && ui->baudrateBox->currentText()!="Custom"){configIniWrite->setValue("MainWindow_SerialComPara/customBaudRate", ui->baudrateBox->currentText()); //如果是字符,读出来是0}//------------------------------------------------------------------------------------------------------configIniWrite->setValue("MainWindow_SerialComPara/portNameIndex", ui->portNameBox->currentIndex()); //向ini文件的第一个节写入内容,COM 节下的第一个参数configIniWrite->setValue("MainWindow_SerialComPara/baudRateIndex", ui->baudrateBox->currentIndex()); //向ini文件的第一个节写入内容,COM 节下的第二个参数configIniWrite->setValue("MainWindow_SerialComPara/dataBitsIndex", ui->dataBitsBox->currentIndex());configIniWrite->setValue("MainWindow_SerialComPara/ParityIndex", ui->ParityBox->currentIndex());configIniWrite->setValue("MainWindow_SerialComPara/stopBitsIndex", ui->stopBitsBox->currentIndex());configIniWrite->setValue("MainWindow_SerialComPara/flowControlIndex", ui->flowControlBox->currentIndex());//------------------------------------------------------------------------------------------------------//向ini文件的第3个节写入内容,MainWindow 节下的第1个参数if(ui->checkBox_hexReceive->isChecked()) configIniWrite->setValue("MainWindow_SerialReceivePara/hexReceive", 1);else configIniWrite->setValue("MainWindow_SerialReceivePara/hexReceive", 0);//向ini文件的第3个节写入内容,MainWindow 节下的第1个参数if(ui->checkBox_AutoLineBreak->isChecked()) configIniWrite->setValue("MainWindow_SerialReceivePara/AutoLineBreak", 1);else configIniWrite->setValue("MainWindow_SerialReceivePara/AutoLineBreak", 0);//向ini文件的第3个节写入内容,MainWindow 节下的第1个参数if(ui->checkBox_displaySend->isChecked()) configIniWrite->setValue("MainWindow_SerialReceivePara/displaySend", 1);else configIniWrite->setValue("MainWindow_SerialReceivePara/displaySend", 0);//向ini文件的第3个节写入内容,MainWindow 节下的第1个参数if(ui->checkBox_displayTime->isChecked()) configIniWrite->setValue("MainWindow_SerialReceivePara/displayTime", 1);else configIniWrite->setValue("MainWindow_SerialReceivePara/displayTime", 0);//------------------------------------------------------------------------------------------------------//向ini文件的第3个节写入内容,MainWindow 节下的第1个参数if(ui->checkBox_hexSend->isChecked()) configIniWrite->setValue("MainWindow_SerialSendPara/hexSend", 1);else configIniWrite->setValue("MainWindow_SerialSendPara/hexSend", 0);//向ini文件的第3个节写入内容,MainWindow 节下的第1个参数if(ui->checkBox_CR_LF->isChecked()) configIniWrite->setValue("MainWindow_SerialSendPara/Send_CR_LF", 1);else configIniWrite->setValue("MainWindow_SerialSendPara/Send_CR_LF", 0);//写入完成后删除指针delete configIniWrite;//*************************************************************************************************************//Qt中使用QSettings类读写ini文件//QSettings构造函数的第一个参数是ini文件的路径,第二个参数表示针对ini文件,第三个参数可以缺省QSettings *SendHistoryDataIniWrite = new QSettings(FileName_SerialPort_SendHistoryData_ini_Path, QSettings::IniFormat);//向ini文件中写入内容,setValue函数的两个参数是键值对//历史发送数据保存SendHistoryDataIniWrite->setIniCodec(QTextCodec::codecForName("GB18030")); //中文保存QString SendText = ui->sendTextEdit->toPlainText();SendHistoryDataIniWrite->setValue("MainWindow_SerialSendData/SendText", SendText);int count = ui->comboBox_sendHistory->count();SendHistoryDataIniWrite->setValue("MainWindow_SerialSendHistoryData/ItemTotalNum", count);for(int i=0; i<count; i++){QString StrItem = ui->comboBox_sendHistory->itemText(i);//QString Utf8_StrItem = QString::fromLocal8Bit(StrItem.toLatin1().constData()); //生成UTF-8编码字符串QString ItemNum = "MainWindow_SerialSendHistoryData/";ItemNum += QString("%1").arg(i,3,10,QLatin1Char('0'));SendHistoryDataIniWrite->setValue(ItemNum, StrItem);}//写入完成后删除指针delete SendHistoryDataIniWrite;
}//----------------------------------------串口----------------------------------------
void MainWindow::StatusBarInit()
{statusBarLabelSerial = new QLabel(this); //新建一个标签statusBarLabelBluetooth = new QLabel(this); //新建一个标签statusBarLabelTx = new QLabel(this); //新建一个标签statusBarLabelRx = new QLabel(this); //新建一个标签//状态栏显示打开关闭COM信息QString StatusInfo = " ";StatusInfo += "COM Ready!";statusBarLabelSerial->setStyleSheet("color:black");statusBarLabelSerial->setText(StatusInfo); //设置标签的名字QString BtStatusInfo = " ";BtStatusInfo += "Bluetooth Ready!";statusBarLabelBluetooth->setStyleSheet("color:blue");statusBarLabelBluetooth->setText(BtStatusInfo); //设置标签的名字statusBarLabelRx->setText("Rx: 0 Bytes"); //设置标签的名字statusBarLabelTx->setText("Tx: 0 Bytes"); //设置标签的名字statusBarLabelSerial->setFixedWidth(260);statusBarLabelBluetooth->setFixedWidth(260);statusBarLabelTx->setFixedWidth(150);statusBarLabelRx->setFixedWidth(200);ui->statusBar->addWidget(statusBarLabelSerial);//将标签添加到状态栏ui->statusBar->addWidget(statusBarLabelBluetooth);//将标签添加到状态栏ui->statusBar->addWidget(statusBarLabelRx);//将标签添加到状态栏ui->statusBar->addWidget(statusBarLabelTx);//将标签添加到状态栏
}void MainWindow::TimerInit()
{//自动重发fTimer = new QTimer(this);fTimer->stop();AutoSendTimeMs = ui->spinBox_AutoSendTime->text().toInt();fTimer->setInterval (AutoSendTimeMs) ;//设置定时周期,单位:毫秒connect(fTimer,SIGNAL(timeout()),this,SLOT(slot_timer_timeout()));
}void MainWindow::slot_timer_timeout()
{//定时器中断响//QTime curTime = QTime::currentTime(); //获取当前时间//qDebug() << curTime.second(); //显示s//动态变化时修改定时周期static int CurAutoSendTimeMs = AutoSendTimeMs;if(AutoSendTimeMs != CurAutoSendTimeMs){//qDebug() << AutoSendTimeMs;fTimer->setInterval (AutoSendTimeMs) ;//设置定时周期,单位:毫秒}CurAutoSendTimeMs = AutoSendTimeMs;if(CommProType == Serial_Comm) on_sendButton_clicked(); //第2~n次...#ifdef __Bluetooth__else on_sendButton_bt_clicked();#endif
}void MainWindow::on_spinBox_AutoSendTime_valueChanged(int arg1)
{AutoSendTimeMs = arg1;
}void MainWindow::on_searchButton_clicked()
{ui->portNameBox->clear();SerialPortNum = 0;//通过QSerialPortInfo查找可用串口foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts()){SerialPortNum++;ui->portNameBox->addItem(info.portName());}if(SerialPortNum > 0){ui->portNameBox->addItem("Refresh Port"); //刷新串口if(refresh_serialport_flag && SerialPortNum > 1){ui->portNameBox->setCurrentIndex(SerialPortNum-1); //显示刷新后新增的最后一个COM口}else{ui->portNameBox->setCurrentIndex(0); //显示第一个COM}//TRACE_1(SerialPortNum);}else{refresh_serialport_null_flag = true;ui->portNameBox->addItem("Refresh Port"); //刷新串口ui->portNameBox->setCurrentIndex(0); //显示第一个COM}
}void MainWindow::on_portNameBox_activated(int index)
{Q_UNUSED(index);//qDebug() << "on_portNameBox_activated index:" << index;//qDebug() << "refresh_serialport_null_flag index:" << refresh_serialport_null_flag;if(refresh_serialport_null_flag){refresh_serialport_null_flag = false;on_searchButton_clicked();refresh_serialport_flag = false;}
}void MainWindow::on_portNameBox_currentIndexChanged(int index)
{int Last_Com_ID = Com_ID;Com_ID = index;//TRACE_3(Last_Com_ID,Com_ID,SerialPortNum);if(SerialPortNum == 0 || Com_ID == -1 || Last_Com_ID == -1){return;}if(Com_ID == SerialPortNum) //刷新串口{refresh_serialport_flag = true;on_searchButton_clicked();refresh_serialport_flag = false;return;}if(Last_Com_ID != Com_ID){if(ui->btn_open_close_serial->text()==ClosePortStatus) //串口已经打开{//qDebug() << "串口打开时,动态切换串口";//关闭串口serial.close();Serial_Close_Status_Display();//状态栏显示打开关闭COM信息QString SerialComInfo = " ";SerialComInfo += ui->portNameBox->currentText() + " CLOSED";statusBarLabelSerial->setStyleSheet("color:red");statusBarLabelSerial->setText(SerialComInfo);on_btn_open_close_serial_clicked();}}
}void MainWindow::on_baudrateBox_currentIndexChanged(int index)
{int Last_BaudRateID = BaudRateID;BaudRateID = index;if(Last_BaudRateID != BaudRateID){if(ui->btn_open_close_serial->text()==ClosePortStatus) //串口已经打开{//qDebug() << "串口打开时,动态切换串口";//关闭串口serial.close();Serial_Close_Status_Display();//状态栏显示打开关闭COM信息QString SerialComInfo = " ";SerialComInfo += ui->portNameBox->currentText() + " CLOSED";statusBarLabelSerial->setStyleSheet("color:red");statusBarLabelSerial->setText(SerialComInfo);if(BaudRateID == 0) //custom{//qDebug() << "Custom";return;}on_btn_open_close_serial_clicked();}else{//qDebug() << "串口未打开时,不动态切换串口";ui->baudrateBox->setItemText(ui->baudrateBox->currentIndex(),ui->baudrateBox->currentText());}}else{ui->baudrateBox->setItemText(ui->baudrateBox->currentIndex(),ui->baudrateBox->currentText());}
}void MainWindow::on_btn_open_close_serial_clicked()
{open_close_serial_port();
}void MainWindow::Serial_Close_Status_Display()
{ui->checkBox_AutoSend->setChecked(0);fTimer->stop(); //定时器停止//下拉菜单控件使能ui->portNameBox->setEditable(true);ui->baudrateBox->setEditable(true);ui->dataBitsBox->setEnabled(true);ui->ParityBox->setEnabled(true);ui->stopBitsBox->setEnabled(true);ui->flowControlBox->setEnabled(true);ui->btn_open_close_serial->setText(OpenPortStatus);
}void MainWindow::open_close_serial_port()
{//qDebug() << "baudrateBox" << ui->baudrateBox->currentText();if(ui->btn_open_close_serial->text()==OpenPortStatus){//设置串口名serial.setPortName(ui->portNameBox->currentText());//设置波特率serial.setBaudRate(ui->baudrateBox->currentText().toInt());//设置数据位数//TRACE_1(ui->dataBitsBox->currentIndex());switch(ui->dataBitsBox->currentIndex()){case 0: serial.setDataBits(QSerialPort::Data5); break;case 1: serial.setDataBits(QSerialPort::Data6); break;case 2: serial.setDataBits(QSerialPort::Data7); break;case 3: serial.setDataBits(QSerialPort::Data8); break;default: break;}//设置奇偶校验//TRACE_1(ui->ParityBox->currentIndex());switch(ui->ParityBox->currentIndex()){case 0: serial.setParity(QSerialPort::NoParity); break;case 1: serial.setParity(QSerialPort::EvenParity); break;case 2: serial.setParity(QSerialPort::OddParity); break;case 3: serial.setParity(QSerialPort::SpaceParity); break;case 4: serial.setParity(QSerialPort::MarkParity); break;default: break;}//设置停止位//TRACE_1(ui->stopBitsBox->currentIndex());switch(ui->stopBitsBox->currentIndex()){case 0: serial.setStopBits(QSerialPort::OneStop); break;case 1: serial.setStopBits(QSerialPort::OneAndHalfStop); break;case 2: serial.setStopBits(QSerialPort::TwoStop); break;default: break;}//设置流控制//TRACE_1(ui->flowControlBox->currentIndex());switch(ui->flowControlBox->currentIndex()){case 0: serial.setFlowControl(QSerialPort::NoFlowControl); break;case 1: serial.setFlowControl(QSerialPort::HardwareControl); break;case 2: serial.setFlowControl(QSerialPort::SoftwareControl); break;default: break;}//打开串口if(!serial.open(QIODevice::ReadWrite)){Serial_Close_Status_Display();//状态栏显示打开关闭COM信息QString SerialComInfo = " ";SerialComInfo += ui->portNameBox->currentText() + " 串口打开失败! 错误: 拒绝访问(被占用).";statusBarLabelSerial->setStyleSheet("color:red");statusBarLabelSerial->setText(SerialComInfo);return;}//状态栏显示打开关闭COM信息QString SerialComInfo = " ";SerialComInfo += ui->portNameBox->currentText();SerialComInfo += " OPEND, ";SerialComInfo += ui->baudrateBox->currentText();SerialComInfo += ", ";SerialComInfo += ui->dataBitsBox->currentText();SerialComInfo += ", ";SerialComInfo += ui->ParityBox->currentText();SerialComInfo += ", ";SerialComInfo += ui->stopBitsBox->currentText();SerialComInfo += ", ";SerialComInfo += ui->flowControlBox->currentText();statusBarLabelSerial->setStyleSheet("color:green");statusBarLabelSerial->setText(SerialComInfo);//下拉菜单控件失能//设置不可编辑ui->baudrateBox->setItemText(ui->baudrateBox->currentIndex(),ui->baudrateBox->currentText());ui->portNameBox->setEditable(false);ui->baudrateBox->setEditable(false);ui->dataBitsBox->setEnabled(false);ui->ParityBox->setEnabled(false);ui->stopBitsBox->setEnabled(false);ui->flowControlBox->setEnabled(false);ui->btn_open_close_serial->setText(ClosePortStatus);WriteLogFileInit();}else{//关闭串口serial.close();Serial_Close_Status_Display();//状态栏显示打开关闭COM信息QString SerialComInfo = " ";SerialComInfo += ui->portNameBox->currentText() + " CLOSED";statusBarLabelSerial->setStyleSheet("color:red");statusBarLabelSerial->setText(SerialComInfo);}
}bool MainWindow::SendDatePreJudgment()
{//TRACE_1(CommProType);if(ui->btn_open_close_serial->text()==QString(OpenPortStatus) && (CommProType == Serial_Comm)){QString SerialComInfo;//状态栏显示打开关闭COM信息SerialComInfo = " 请先打开串口";SerialComInfo += ui->portNameBox->currentText() + ",再发送数据!";statusBarLabelSerial->setStyleSheet("color:red");statusBarLabelSerial->setText(SerialComInfo);return false;}else if(ui->btn_open_close_bt->text()==QString(OpenBtStatus) && (CommProType == Bluetooth_Comm)){QString SerialComInfo;//状态栏显示打开关闭COM信息SerialComInfo = " 请打开蓝牙,再发送数据!";statusBarLabelBluetooth->setStyleSheet("color:red");statusBarLabelBluetooth->setText(SerialComInfo);return false;}return true;
}void MainWindow::SetTxRxMsgcolor(QString Mode)
{//TRACE_2(Msgcolor_Configured,Msgcolor_Configured_temp);if(Mode=="TX" || Mode=="TX_BT"){if(Mode=="TX") Msgcolor_Configured = 1;else Msgcolor_Configured = 3;//字体&颜色if(Msgcolor_Configured != Msgcolor_Configured_temp){Msgcolor_Configured_temp = Msgcolor_Configured;if(Mode=="TX"){SendMsgcolor.setRed(0x00);SendMsgcolor.setGreen(0x55);SendMsgcolor.setBlue(0xff);}else{SendMsgcolor.setRed(0xff);SendMsgcolor.setGreen(0x55);SendMsgcolor.setBlue(0xff);}}}else if(Mode=="RX"){Msgcolor_Configured = 2;//字体&颜色if(Msgcolor_Configured != Msgcolor_Configured_temp){Msgcolor_Configured_temp = Msgcolor_Configured;SendMsgcolor.setRed(0x00);SendMsgcolor.setGreen(0xaa);SendMsgcolor.setBlue(0x00);}}TextCharFormat.setForeground(SendMsgcolor);ui->recvTextEdit->setCurrentCharFormat(TextCharFormat);
}void MainWindow::on_sendButton_clicked()
{CommProType = Serial_Comm;SendAddItemFlag = true;if(!SendDatePreJudgment()){return;}if(ui->sendTextEdit->toPlainText().isEmpty()) //else if(ui->sendTextEdit->toPlainText()==QString("")){ui->recvTextEdit->insertPlainText(StrEmpty);ui->recvTextEdit->append("");return;}SetTxRxMsgcolor("TX");QString dataStr = ui->sendTextEdit->toPlainText();//qDebug() << "dataStr:" << dataStr;if(ui->checkBox_hexSend->isChecked()){writeHex(dataStr);}else{writeAscii(dataStr);}if(SendAddItemFlag){//发送数据增加到列表int count = ui->comboBox_sendHistory->count();if((count > 0) && (dataStr == ui->comboBox_sendHistory->itemText(count-1))){//qDebug() << "last item same exit";return;}for(int i=0; i<count; i++){QString StrItem = ui->comboBox_sendHistory->itemText(i);//qDebug() << StrItem;if(StrItem == dataStr){//qDebug() << "have item same exit";SendAddItemFlag = false;break;}}if(SendAddItemFlag){ui->comboBox_sendHistory->addItem(dataStr);}}
}//--------------------------------------------发送数据------------------------------------------------------
//------------------------------------------------------
//30->0 46->F 3046-0F
void MainWindow::StringToHex(QString str, QByteArray &senddata) //字符串转换为十六进制数据0-F
{int hexdata,lowhexdata;int hexdatalen = 0;int len = str.length();senddata.resize(len / 2); //size()是分配容器的内存大小char lstr,hstr;for (int i = 0; i < len; ) // str "012Abc0d"{hstr = str[i].toLatin1(); //'0'if (hstr == ' '){++i;continue; //空格略过,继续下一个循环}++i;if (i >= len){break; //循环退出}lstr = str[i].toLatin1(); //'1'hexdata = ConvertHexChar(hstr);lowhexdata = ConvertHexChar(lstr);if ((hexdata == 16) || (lowhexdata == 16)) //正常(0-15),不会等于16{break;}else{hexdata = hexdata*16 + lowhexdata; //高低位组合}++i;senddata[hexdatalen] = (unsigned char)hexdata; //写入buffer//qDebug("%02X ",(unsigned char)senddata[hexdatalen]);++hexdatalen;}senddata.resize(hexdatalen);
}//3046 -> 33 30 34 36
QString MainWindow::HexToAscii(QByteArray array)
{QString str = "";QString temp = array.toHex();for(int i = 0;i < temp.count();i++){//在str的末尾插入一个元素str.push_back(temp.at(i)); //at()只读,访问速度最快if(i % 2 == 1 && i != 0){str.push_back(' ');}}str = str.toUpper();return str;
}char MainWindow::ConvertHexChar(char ch)
{if ((ch >= '0') && (ch <= '9')){return ch - 0x30; //0-9}else if ((ch >= 'A') && (ch <= 'F')){return ch - 'A' + 10; //10-15}else if ((ch >= 'a') && (ch <= 'f')){return ch - 'a' + 10; //10-15}else{return ch - ch; //0 -> 其他非十六进制字符当作0处理}
}
//------------------------------------------------------QByteArray MainWindow::DisplayTimestamp(QByteArray buffer)
{//显示时间戳:处理方法://1.在输入的字符串前加时间戳,//2.再查找\n,替换为\n+时间戳,//3.根据"自动换行"按钮选择加入\r\n (无自动换行按钮默认加入\r\n)QByteArray data_backup = buffer;//获取当前日期时间,并转换为字符串QDateTime curDateTime = QDateTime::currentDateTime();QString CurRecvTime = curDateTime.toString(ReceiveTimeFormat);QByteArray ByteArrayCurSendTime = CurRecvTime.toLatin1();data_backup = ByteArrayCurSendTime + data_backup;QByteArray ReplaceCurRecvTime = "\n" + ByteArrayCurSendTime;data_backup.replace("\n",ReplaceCurRecvTime);if(ui->checkBox_AutoLineBreak->isChecked()) data_backup += "\r\n";return data_backup;
}void MainWindow::WriteLogFileInit()
{if(!LogFileAlreadyOpen){LogPathFileName = QCoreApplication::applicationDirPath() + "/" + "Serial_Bluetooth_Debug_Assistant_Log" + "/";LogPathFileName.replace("//","/"); //特殊处理盘符根目录下D://情况//LogPathFileName += ui->portNameBox->currentText() + "_";LogPathFileName += "Session_";QDateTime curDateTime=QDateTime::currentDateTime();LogPathFileName += curDateTime.toString("yyyy-MM-dd_hh") + ".txt"; //"[yyyy-MM-dd hh:mm:ss.zzz] "//qDebug() << LogPathFileName;//新建txt文件WriteLogFile = new QFile;WriteLogFile->setFileName(LogPathFileName);bool ok = WriteLogFile->open(QIODevice::WriteOnly|QIODevice::Append);if(ok){QTextStream out(WriteLogFile);//qDebug() << "Log init";//out << ""; //转化成纯文本写入文件LogFileAlreadyOpen = true;//WriteLogFile->close();//delete(WriteLogFile);}else{ui->recvTextEdit->insertPlainText("保存日记失败!");ui->recvTextEdit->append("");}}
}void MainWindow::WriteLogFileInfo(QString data)
{//写日记if(LogFileAlreadyOpen){QString LogPathFileNameTemp = "Session_";QDateTime curDateTime=QDateTime::currentDateTime();LogPathFileNameTemp += curDateTime.toString("yyyy-MM-dd_hh") + ".txt"; //"[yyyy-MM-dd hh:mm:ss.zzz] "int num = LogPathFileName.lastIndexOf("/");QString PathSuffix = LogPathFileName.mid(num+1);if(LogPathFileNameTemp != PathSuffix){LogPathFileName = LogPathFileName.replace(PathSuffix,LogPathFileNameTemp);//qDebug() << "LogPathFileName" << LogPathFileName;WriteLogFile = new QFile;WriteLogFile->setFileName(LogPathFileName);WriteLogFile->open(QIODevice::WriteOnly);}QTextStream out(WriteLogFile);out << data; //转化成纯文本写入文件}
}void MainWindow::displayTxRxCount(const QString String, int Count)
{if(String == "TX"){SendTotailSize += Count;QString Size = "Tx: ";Size += QString::number(SendTotailSize);Size += " Bytes";statusBarLabelTx->setText(Size);}if(String == "RX"){ReceiveTotailSize += Count;QString Size = "Rx: ";Size += QString::number(ReceiveTotailSize);Size += " Bytes";statusBarLabelRx->setText(Size);}}void MainWindow::SendDataHandle(QByteArray data)
{//SetTxRxMsgcolor("TX");if(CommProType == Serial_Comm){serial.write(data);}else if(CommProType == Bluetooth_Comm){#ifdef __Bluetooth__//qDebug() << data;socket->write(data, data.size());#endif}
}void MainWindow::writeAscii(QString dataStr)
{QByteArray data = dataStr.toUtf8();if(ui->checkBox_CR_LF->isChecked()){data.append('\r'); //0Ddata.append('\n'); //0A}//显示发送按钮 -- 只有显示发送才会有时间戳if(ui->checkBox_displaySend->isChecked()){if(CommProType == Serial_Comm || CommProType == Bluetooth_Comm){QByteArray DisplayBuffer = data;//显示发送时间戳if(ui->checkBox_displayTime->isChecked() && !SendTimeFormat.isEmpty()){DisplayBuffer = DisplayTimestamp(DisplayBuffer);ui->recvTextEdit->insertPlainText(DisplayBuffer);WriteLogFileInfo(DisplayBuffer);}else{if(ui->checkBox_AutoLineBreak->isChecked()) DisplayBuffer += "\r\n";ui->recvTextEdit->insertPlainText(DisplayBuffer);WriteLogFileInfo(DisplayBuffer);}}}SendDataHandle(data);//状态栏显示发送数据个数displayTxRxCount("TX", data.size());
}void MainWindow::writeHex(QString dataStr)
{//如果发送的数据个数为奇数的,则在前面最后落单的字符前添加一个字符0dataStr = dataStr.replace(" ","");if (dataStr.length() % 2) //dataStr.length()=7{dataStr.insert(dataStr.length()-1, '0'); //012Abcd -> 012Abc0d}QByteArray data;StringToHex(dataStr, data);// qDebug() << "dataStr" << dataStr;
// qDebug() << "data" << data;
//
// for(int i=0;i<data.size();i++)
// {
// qDebug("%02X ",(unsigned char)data[i]);
// }if(ui->checkBox_CR_LF->isChecked()){data.append('\r');data.append('\n');}//显示发送按钮 -- 只有显示发送才会有时间戳if(ui->checkBox_displaySend->isChecked()){//显示用QString str = HexToAscii(data); //1234 ->12 34//qDebug() << "Hex str:" << str;if(CommProType == Serial_Comm || CommProType == Bluetooth_Comm){QByteArray DisplayBuffer = str.toLatin1();;//显示发送时间戳if(ui->checkBox_displayTime->isChecked() && !SendTimeFormat.isEmpty()){DisplayBuffer = DisplayTimestamp(DisplayBuffer);ui->recvTextEdit->insertPlainText(DisplayBuffer);WriteLogFileInfo(DisplayBuffer);}else{if(ui->checkBox_AutoLineBreak->isChecked()) DisplayBuffer += "\r\n";ui->recvTextEdit->insertPlainText(DisplayBuffer);WriteLogFileInfo(DisplayBuffer);}}}SendDataHandle(data);//状态栏显示发送数据个数displayTxRxCount("TX", data.size());
}void MainWindow::serialPort_readyRead()
{//从接收缓冲区中读取数据QByteArray buffer = serial.readAll();static int TotailBufferSize = 0;if(1){//字体&颜色SetTxRxMsgcolor("RX");//状态栏显示接收数据个数displayTxRxCount("RX", buffer.size());TotailBufferSize += buffer.size();//显示接收时间戳if(ui->checkBox_displayTime->isChecked() && !ReceiveTimeFormat.isEmpty()){if(ui->checkBox_hexReceive->isChecked()){QString str = HexToAscii(buffer);QDateTime curDateTime=QDateTime::currentDateTime();QString CurRecvTime = curDateTime.toString(ReceiveTimeFormat);str = CurRecvTime + str;if(ui->checkBox_AutoLineBreak->isChecked()) str += "\r\n";ui->recvTextEdit->insertPlainText(str);WriteLogFileInfo(str);}else{QByteArray DisplayBuffer = DisplayTimestamp(buffer);//显示接收数据ui->recvTextEdit->insertPlainText(DisplayBuffer);WriteLogFileInfo(DisplayBuffer);}}if(TotailBufferSize >= 100*1024*1024) //100M{TotailBufferSize = 0;ui->recvTextEdit->clear();}}
}void MainWindow::on_btn_clear_recevie_clicked()
{ui->recvTextEdit->clear();SendTotailSize = 0;ReceiveTotailSize = 0;statusBarLabelRx->setText("Rx: 0 Bytes"); //设置标签的名字statusBarLabelTx->setText("Tx: 0 Bytes"); //设置标签的名字
}void MainWindow::on_btn_clear_send_clicked()
{ui->sendTextEdit->clear();ui->comboBox_sendHistory->clear();
}//Qt中textEdit文本编辑区设置滚动条自动向下滑落
//https://blog.csdn.net/HHT0506/article/details/100567581
void MainWindow::on_recvTextEdit_textChanged()
{ui->recvTextEdit->moveCursor(QTextCursor::End);
}void MainWindow::on_comboBox_sendHistory_activated(const QString &arg1)
{//qDebug() << arg1;SendAddItemFlag = false; //不增加到列表if(!SendDatePreJudgment()){return;}SetTxRxMsgcolor("TX");#ifdef __Bluetooth__if(CommProType == Bluetooth_Comm)SetTxRxMsgcolor("TX_BT");#endifif(ui->checkBox_hexSend->isChecked()){writeHex(arg1);}else{writeAscii(arg1);}
}void MainWindow::on_checkBox_AutoSend_clicked()
{if(!SendDatePreJudgment()){ui->checkBox_AutoSend->setChecked(0);return;}if(ui->sendTextEdit->toPlainText().isEmpty()) //else if(ui->sendTextEdit->toPlainText()==QString("")){ui->recvTextEdit->insertPlainText(StrEmpty);ui->recvTextEdit->append("");ui->checkBox_AutoSend->setChecked(0);return;}if(ui->checkBox_AutoSend->isChecked()){if(CommProType == Serial_Comm) on_sendButton_clicked();#ifdef __Bluetooth__else on_sendButton_bt_clicked();#endifAutoSendTimeMs = ui->spinBox_AutoSendTime->text().toInt(); //不能带单位,否则toInt变成了0//TRACE_1(AutoSendTimeMs);fTimer->setInterval (AutoSendTimeMs) ;//设置定时周期,单位:毫秒fTimer->start () ;//定时器开始工作 -- slot_timer_timeout}else{fTimer->stop() ; //定时器停止}
}void MainWindow::closeEvent(QCloseEvent *event)
{Q_UNUSED(event);SaveSerialPortConfigParameters();
}#endif//---------------------------------蓝牙----------------------------------------#ifdef __Bluetooth__void MainWindow::BlueTooth_Reset()
{//初始化蓝牙搜索类discoveryAgent = new QBluetoothDeviceDiscoveryAgent();//为本地蓝牙创建描述类localDevice = new QBluetoothLocalDevice();// 给socket分配内存,限定套接字协议socket = new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol);//判断蓝牙是否开启,若开启则不可被选中并扫描周围蓝牙设备// 发现设备时会触发deviceDiscovered信号,转到槽显示蓝牙设备connect(discoveryAgent, SIGNAL(deviceDiscovered(QBluetoothDeviceInfo)), this, SLOT(addBlueToothDevicesToList(QBluetoothDeviceInfo)));connect(discoveryAgent, SIGNAL(finished()), this, SLOT(findFinish()));//双击listwidget的项目,触发连接蓝牙的槽connect(ui->listWidget, SIGNAL(itemActivated(QListWidgetItem *)), this, SLOT(connectBLE(QListWidgetItem *)));connect(socket, SIGNAL(connected()), this, SLOT(connectOK()));connect(socket, SIGNAL(disconnected()), this, SLOT(connectNot()));connect(socket, SIGNAL(readyRead()), this, SLOT(readBluetoothDataEvent()));
}bool MainWindow::BlueTooth_Init()
{BlueTooth_Reset();//qDebug() << "localDevice->hostMode()" << localDevice->hostMode();//localDevice->hostMode() QBluetoothLocalDevice::HostConnectableui->btn_update->setEnabled(false);if (localDevice->hostMode() == QBluetoothLocalDevice::HostPoweredOff){// 开始扫描蓝牙设备//discoveryAgent->start();return false;}else{localDevice->powerOn();ui->listWidget->clear();// 开始扫描蓝牙设备discoveryAgent->start();return true;}
}void MainWindow::open_close_bluetooth()
{if(ui->btn_open_close_bt->text()==OpenBtStatus){if(BlueTooth_Init()){WriteLogFileInit();//状态栏显示打开关闭COM信息QString StatusInfo = " ";StatusInfo += "Bluetooth Scanning...";statusBarLabelBluetooth->setStyleSheet("color:green");statusBarLabelBluetooth->setText(StatusInfo);ui->btn_open_close_bt->setText(CloseBtStatus);}else{ui->btn_open_close_bt->setText(OpenBtStatus);//状态栏显示打开关闭COM信息QString StatusInfo = " ";StatusInfo += "Bluetooth Init Fail!";statusBarLabelBluetooth->setStyleSheet("color:red");statusBarLabelBluetooth->setText(StatusInfo);}}else{discoveryAgent->stop(); //停止搜索设备CloseBluetooth_Status_Display();}
}void MainWindow::CloseBluetooth_Status_Display()
{#ifdef __Serial__ui->checkBox_AutoSend->setChecked(0);fTimer->stop(); //定时器停止#endifui->btn_open_close_bt->setText(OpenBtStatus);bool EnabledFlag = false;ui->btn_update->setEnabled(EnabledFlag);//状态栏显示打开关闭COM信息QString StatusInfo = " ";StatusInfo += "Bluetooth Close!";statusBarLabelBluetooth->setStyleSheet("color:red");statusBarLabelBluetooth->setText(StatusInfo);
}void MainWindow::findFinish()
{ui->btn_update->setEnabled(true);//TRACE_0_STR("");//状态栏显示打开关闭COM信息QString StatusInfo = " ";StatusInfo += "Scan Finish";statusBarLabelBluetooth->setStyleSheet("color:green");statusBarLabelBluetooth->setText(StatusInfo);
}void MainWindow::connectOK()
{discoveryAgent->stop(); //停止搜索设备//QMessageBox::information(this, tr("成功"), tr("连接成功!"));//状态栏显示打开关闭COM信息QString StatusInfo = " ";StatusInfo += "Connected.";statusBarLabelBluetooth->setStyleSheet("color:green");statusBarLabelBluetooth->setText(StatusInfo);
}void MainWindow::connectNot()
{//QMessageBox::information(this, tr("错误"), tr("连接失败!"));//状态栏显示打开关闭COM信息QString StatusInfo = " ";StatusInfo += "Disconnected!";statusBarLabelBluetooth->setStyleSheet("color:red");statusBarLabelBluetooth->setText(StatusInfo);BlueTooth_Reset();
}void MainWindow::readBluetoothDataEvent()
{//从接收缓冲区中读取数据QByteArray buffer = socket->readAll();static int TotailBufferSize = 0;if(1){//字体&颜色SetTxRxMsgcolor("RX");//状态栏显示接收数据个数displayTxRxCount("RX", buffer.size());TotailBufferSize += buffer.size();//显示接收时间戳if(ui->checkBox_displayTime->isChecked() && !ReceiveTimeFormat.isEmpty()){if(ui->checkBox_hexReceive->isChecked()){QString str = HexToAscii(buffer);QDateTime curDateTime=QDateTime::currentDateTime();QString CurRecvTime = curDateTime.toString(ReceiveTimeFormat);str = CurRecvTime + str;if(ui->checkBox_AutoLineBreak->isChecked()) str += "\r\n";ui->recvTextEdit->insertPlainText(str);WriteLogFileInfo(str);}else{QByteArray DisplayBuffer = DisplayTimestamp(buffer);//显示接收数据ui->recvTextEdit->insertPlainText(DisplayBuffer);WriteLogFileInfo(DisplayBuffer);}}if(TotailBufferSize >= 100*1024*1024) //100M{TotailBufferSize = 0;ui->recvTextEdit->clear();}}
}#define BlueToothDevicesDefaultDisplay
void MainWindow::addBlueToothDevicesToList(QBluetoothDeviceInfo info)
{#if defined (BlueToothDevicesDefaultDisplay)QString label= QString("%1 %2").arg(info.address().toString()).arg(info.name());#elseQString label = QString("%1\n%2").arg(info.name()).arg(info.address().toString());#endifQList<QListWidgetItem *> items = ui->listWidget->findItems(label, Qt::MatchExactly);if (items.empty()){QListWidgetItem *item = new QListWidgetItem(label);QBluetoothLocalDevice::Pairing pairingStatus = localDevice->pairingStatus(info.address());//qDebug() << info.name() << info.address() << "pairingStatus:" << pairingStatus;/* 蓝牙状态pairingStatus,Pairing枚举类型0:Unpaired没配对1:Paired配对但没授权2:AuthorizedPaired配对且授权*/if (pairingStatus == QBluetoothLocalDevice::Paired || pairingStatus == QBluetoothLocalDevice::AuthorizedPaired){item->setForeground(QColor(Qt::green));}else{item->setForeground(QColor(Qt::black));}ui->listWidget->addItem(item);}
}void MainWindow::connectBLE(QListWidgetItem *item)
{static const QLatin1String serviceUuid("00001101-0000-1000-8000-00805F9B34FB");//百度来的手机连接单片机用的uuidQString text = item->text(); //蓝牙和地址#if defined (BlueToothDevicesDefaultDisplay)int index = text.indexOf(' ');if(index == -1) return;QBluetoothAddress address(text.left(index));QString name(text.mid(index + 1));#elseint index = text.indexOf('\n');if(index == -1) return;QBluetoothAddress address(text.mid(index + 1));QString name(text.mid(0,index));#endif//状态栏显示打开关闭COM信息QString StatusInfo = " ";if(socket->state()==0) //UnconnectedState{StatusInfo += "Bluetooth is connecting. Please wait...";statusBarLabelBluetooth->setStyleSheet("color:green");statusBarLabelBluetooth->setText(StatusInfo);socket->connectToService(address, QBluetoothUuid(serviceUuid),QIODevice::ReadWrite);}else if(socket->state()==1) // ServiceLookupState{StatusInfo += "Bluetooth is ServiceLookupState.";statusBarLabelBluetooth->setStyleSheet("color:green");statusBarLabelBluetooth->setText(StatusInfo);socket->connectToService(address, QBluetoothUuid(serviceUuid),QIODevice::ReadWrite);}else if(socket->state()==3) // ConnectedState{StatusInfo += "Bluetooth is ConnectedState, Exit.";statusBarLabelBluetooth->setStyleSheet("color:blue");statusBarLabelBluetooth->setText(StatusInfo);}else{StatusInfo += "Bluetooth Connect Erorr.";statusBarLabelBluetooth->setStyleSheet("color:red");statusBarLabelBluetooth->setText(StatusInfo);}
}void MainWindow::on_btn_update_clicked()
{//状态栏显示打开关闭COM信息QString StatusInfo = " ";StatusInfo += "Update Bluetooth List";statusBarLabelBluetooth->setStyleSheet("color:green");statusBarLabelBluetooth->setText(StatusInfo);BlueTooth_Reset();//socket->disconnectFromService();ui->listWidget->clear();discoveryAgent->start();ui->btn_update->setEnabled(false);
}void MainWindow::on_btn_open_close_bt_clicked()
{open_close_bluetooth();
}void MainWindow::on_sendButton_bt_clicked()
{CommProType = Bluetooth_Comm;SendAddItemFlag = true;if(!SendDatePreJudgment()){return;}if(ui->sendTextEdit->toPlainText().isEmpty()) //else if(ui->sendTextEdit->toPlainText()==QString("")){ui->recvTextEdit->insertPlainText(StrEmpty);ui->recvTextEdit->append("");return;}SetTxRxMsgcolor("TX_BT");QString dataStr = ui->sendTextEdit->toPlainText();//qDebug() << "dataStr:" << dataStr;if(ui->checkBox_hexSend->isChecked()){writeHex(dataStr);}else{writeAscii(dataStr);}if(SendAddItemFlag){//发送数据增加到列表int count = ui->comboBox_sendHistory->count();if((count > 0) && (dataStr == ui->comboBox_sendHistory->itemText(count-1))){//qDebug() << "last item same exit";return;}for(int i=0; i<count; i++){QString StrItem = ui->comboBox_sendHistory->itemText(i);//qDebug() << StrItem;if(StrItem == dataStr){//qDebug() << "have item same exit";SendAddItemFlag = false;break;}}if(SendAddItemFlag){ui->comboBox_sendHistory->addItem(dataStr);}}
}#endif
四、获取 >> 源码以及Git记录:
串口蓝牙调试助手_V1.0(初级篇)_源码以及Git记录
总结
欢迎下载&更新使用。