C++语言Qt实现 串口软件 用于嵌入式软件开发上位机通信调试软件
我遇到个需求:目标:开发一个串口上位机软件,用于和单片机等进行串口通信。内部原理:调用串口类,接收到数据进行解析和显示效果:提供了友好的简洁美观界面,下面就是软件的界面:(支持hex十六进制显示和发送)代码简单展示核心代码如下头文件:#ifndef MAINWINDOWUART_H#define MAINWINDOWUART_H#include <QMainWindow>class Q
·
我遇到个需求:
目标:开发一个串口上位机软件,用于和单片机等进行串口通信。
内部原理:调用串口类,接收到数据进行解析和显示
效果:提供了友好的简洁美观界面,下面就是软件的界面:(支持hex十六进制显示和发送)
代码简单展示
核心代码如下
头文件:
#ifndef MAINWINDOWUART_H
#define MAINWINDOWUART_H
#include <QMainWindow>
class QSerialPort;
class QLabel;
namespace Ui/*Uart*/ {
class MainWindowUart;
}
class MainWindowUart : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindowUart(QWidget *parent = 0);
~MainWindowUart();
bool statusPort=false;
QSerialPort *serial;
QLabel *lableStatusBar;
QList<QByteArray> listByte;
int hex2Str(QByteArray buf, QString &hex);
int Str2HexMe(QString str, QByteArray &data);
void deletStrBlank(QString &s);
private slots:
void read32ByteData();
void on_pushButtonFresh_clicked();
void on_pushButtonOpen_clicked();
void on_pushButtonSend_clicked();
void on_pushButtonClearRxd_clicked();
void on_pushButtonClearTxd_clicked();
void on_actionS_triggered();
void on_action_T_triggered();
void on_action_D_triggered();
private:
Ui/*Uart*/::MainWindowUart *ui;
};
#endif // MAINWINDOWUART_H
源文件:
#include "mainwindowuart.h"
#include "ui_mainwindowuart.h"
#include "mainwindow.h"
#include "mainwindowdraw.h"
#include <QTime>
#include <QFileDialog>
#include <QFileInfo>
#include <QTextStream>
#include <QTextCodec>
#include <QMessageBox>
#include <QGraphicsOpacityEffect>
#include <QIcon>
#include <QInputDialog>
#include <QMessageBox>
#include <QDebug>
#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>
#include <QLabel>
#include <QFile>
MainWindowUart::MainWindowUart(QWidget *parent) :
QMainWindow(parent),
ui(new Ui/*Uart*/::MainWindowUart)
{
ui->setupUi(this);
// 设置波特率下拉菜单默认显示第三项
ui->BaudBox->setCurrentIndex(3);
on_pushButtonFresh_clicked();
// 关闭发送按钮的使能
qDebug() << tr("界面设定成功!")<<endl;
lableStatusBar=new QLabel(this);
// 初始化类中定义的这个状态栏标签,由于类里面无法指定其父对象,所以在这个构造函数这里指定
QString port="Not Open";
// 状态栏显示串口未打开信息
lableStatusBar->setText("串口打开状态:"+QObject::tr("<font color=red>%1</font>").arg(port));
lableStatusBar->setFont(QFont("nihao",8));
ui->statusbar->addWidget(lableStatusBar);
}
/**********************************************************************************************
* 读取接收到的数据,注:为了和前面函数名兼容,虽然这个槽函数名字还是读取一字节,但是由于已经
* 改了接收缓冲区为默认值(32B),所以这里不会一字节就读一次
**********************************************************************************************/
void MainWindowUart::read32ByteData()
{
QByteArray buf;
buf = serial->readAll();
if(!buf.isEmpty())
{
// 如果勾选了Hex显示
if(ui->checkBoxHexRxd->isChecked())
{
QString strHex = ui->textEditRxd->toPlainText();
QString str1Hex;
hex2Str(buf,str1Hex);
strHex=strHex+str1Hex;
ui->textEditRxd->clear();
ui->textEditRxd->setText(strHex);
}
else
{
//说明本次刚好接收到换行符的一半,这时先别显示,否则会多一个换行
if(buf.at(buf.size()-1) == '\r')
{
listByte.append(buf);
}
else
{
QString str = ui->textEditRxd->toPlainText();
for (int i = 0; i < listByte.size(); ++i) {
str=str+QString(listByte.at(i));
}
str=str+QString(buf);
listByte.clear();
ui->textEditRxd->clear();
ui->textEditRxd->setText(str);
}
// ui->textEditRxd->append(QString(buf)); //append会自动换行
qDebug()<<QString(buf);
}
}
buf.clear();
}
MainWindowUart::~MainWindowUart()
{
delete ui;
}
void MainWindowUart::on_pushButtonFresh_clicked()
{
ui->PortBox->clear();
foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
{
QSerialPort serial1;
serial1.setPort(info);
ui->PortBox->addItem(serial1.portName());
}
ui->PortBox->setCurrentIndex(ui->PortBox->count()-1);
}
void MainWindowUart::on_pushButtonOpen_clicked()
{
if(statusPort==false)
{
if(ui->PortBox->currentText() == "")
return;
serial = new QSerialPort;
// 设置串口名
serial->setPortName(ui->PortBox->currentText());
// 打开串口,成功才能往下走
if(!serial->open(QIODevice::ReadWrite))
{
if(serial->error() == QSerialPort::PermissionError)
{
QMessageBox::critical(this,"erro","串口打开失败,该串口已被占用");
serial->deleteLater();
return;
}
}
statusPort=true;
QIcon icoButtonOpenPort(":/new/prefix1/openPort.PNG");
ui->pushButtonOpen->setIcon(icoButtonOpenPort);
ui->pushButtonOpen->setIconSize(QSize(71,37));
// 设置波特率
serial->setBaudRate(ui->BaudBox->currentText().toInt());
// 设置数据位数
switch(ui->BitNumBox->currentIndex())
{
case 0: serial->setDataBits(QSerialPort::Data8); break;
default: break;
}
// 设置奇偶校验
switch(ui->ParityBox->currentIndex())
{
case 0: serial->setParity(QSerialPort::NoParity); break;
default: break;
}
// 设置停止位
switch(ui->StopBox->currentIndex())
{
case 0: serial->setStopBits(QSerialPort::OneStop); break;
case 1: serial->setStopBits(QSerialPort::TwoStop); break;
default: break;
}
// 设置流控制
serial->setFlowControl(QSerialPort::NoFlowControl);
QString port=ui->PortBox->currentText()+" 波特率:"+ui->BaudBox->currentText()+" 数据位:"+ui->BitNumBox->currentText()+" 停止位:"+ui->StopBox->currentText();
lableStatusBar->setText("串口打开状态:"+QObject::tr("<font color=green>%1</font>").arg(port));
lableStatusBar->setFont(QFont("nihao",8));
ui->statusbar->addWidget(lableStatusBar);
// 关闭设置菜单使能
ui->PortBox->setEnabled(false);
ui->BaudBox->setEnabled(false);
ui->BitNumBox->setEnabled(false);
ui->ParityBox->setEnabled(false);
ui->StopBox->setEnabled(false);
ui->pushButtonFresh->setEnabled(false);
ui->pushButtonSend->setEnabled(true);
// 连接信号槽
QObject::connect(serial, &QSerialPort::readyRead, this, &MainWindowUart::read32ByteData);
}
else
{
statusPort=false;
QIcon icoButtonOpenPort(":/new/prefix1/closePort.PNG");
ui->pushButtonOpen->setIcon(icoButtonOpenPort);
ui->pushButtonOpen->setIconSize(QSize(71,37));
// 关闭串口
serial->clear();
serial->close();
serial->deleteLater();
// 恢复设置使能
ui->PortBox->setEnabled(true);
ui->BaudBox->setEnabled(true);
ui->BitNumBox->setEnabled(true);
ui->ParityBox->setEnabled(true);
ui->StopBox->setEnabled(true);
ui->pushButtonFresh->setEnabled(true);
ui->pushButtonSend->setEnabled(false);
QString port="Not Open";
lableStatusBar->setText("串口打开状态:"+QObject::tr("<font color=red>%1</font>").arg(port));
lableStatusBar->setFont(QFont("nihao",8));
ui->statusbar->addWidget(lableStatusBar);
}
}
void MainWindowUart::on_pushButtonSend_clicked()
{
if(statusPort==true)
{
if(ui->checkBoxHexSend->isChecked())
{
QString str=ui->textEditTxd->toPlainText();
QByteArray data; //由于char *类型是有符号型的,只能表示0-127,所以得
//用QByteArray类型,刚好串口write刚好有这个重载函数
int len=Str2HexMe(str,data);
serial->write(data,len); //因为发送的char里面可能含有0x00,所以
}
else
{
QTextCodec *codec=QTextCodec::codecForName("UTF-8");
serial->write(codec->fromUnicode(ui->textEditTxd->toPlainText()));
}
}
}
/**********************************************************************************************
* @brief 把十六进制数转为字符串格式
*
* @param_i buf 输入十六进制数组
* @param_o hex 输出字符串
* @return 输入的十六进制个数
* @note: (1).此函数用于窗口的十六进制显示模式显示接收到的数据
**********************************************************************************************/
int MainWindowUart::hex2Str(QByteArray buf,QString &hex)
{
for (int i = 0; i < buf.size(); ++i)
{
if(buf[i]==0x00)
{
hex=hex+"00";
}
else
{
hex=hex+QString("%1").arg((unsigned char)buf[i],2,16,QChar('0')).toUpper();
}
hex=hex+" ";
}
return buf.size();
}
/**********************************************************************************************
* @brief 把字符串转为十六进制数格式
*
* @param_i str 输入十六进制字符串
* @param_o data 输出十六进制数
* @return 输出的十六进制个数
* @note: (1).此函数用于窗口的十六进制发送模式发送数据
**********************************************************************************************/
int MainWindowUart::Str2HexMe(QString str,QByteArray &data)
{
deletStrBlank(str);
int len=str.length();
bool ok;
for (int i = 0; i < len/2; ++i) {
data[i]=str.mid(2*i,2).toInt(&ok,16);
}
return len/2;
}
/**********************************************************************************************
* @brief 删除字符串中空格
*
* @param_i s 输入字符串
* @note: (1).此函数用于把一个字符串中的空格都删除掉,使得我们更容易处理数据
**********************************************************************************************/
void MainWindowUart::deletStrBlank(QString &s)
{
int len=s.length();
int j=0;
for (int i = 0; i < len; ++i) {
if(!s.at(i).isSpace())
{
s[j]=s[i];
++j;
}
}
s.remove(j,s.length()-j); //经过计算和验证这是完全正确的
}
void MainWindowUart::on_pushButtonClearRxd_clicked()
{
ui->textEditRxd->clear();
}
void MainWindowUart::on_pushButtonClearTxd_clicked()
{
ui->textEditTxd->clear();
}
void MainWindowUart::on_actionS_triggered()
{
// 获取系统时间
QDateTime time=QDateTime::currentDateTime();
QString strTime=time.toString("yy-MM-dd&&hh-mm-ss");
// 打开文件选择对话框
QString fileName = QFileDialog::getSaveFileName(this,
tr("保存串口接收数据"), "串口接收数据"+strTime, tr("文本文档 (*.txt)"));
if(!fileName.isNull())
// 如果确实选取了目标保存文件路径,就保存,否则就是不保存
{
// 以只写方式打开,如果文件不存在,那么会创建该文件
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
qDebug() << file.errorString();
QTextStream out(&file);
out<<ui->textEditRxd->toPlainText();
file.close();
}
}
void MainWindowUart::on_action_T_triggered()
{
(new MainWindow())->show();
close();
}
void MainWindowUart::on_action_D_triggered()
{
(new MainWindowDraw())->show();
close();
}
如果有需要学习和使用这个软件源码的,通过我的QQ邮箱:2488890051@qq.com(马上就能回复)联系我,算是对我的劳动成果的鼓励,开发花了大量的时间和精力,作为学生,着实不容易。 (大佬们,记得关注我的博客,且下面评论留言喔,谢谢哈~)
更多推荐
所有评论(0)