当前位置: 首页 > news >正文

QT:串口上位机

创建工程

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

布局UI界面

在这里插入图片描述
设置名称

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

设置数据

设置波特率
在这里插入图片描述
波特率默认9600
在这里插入图片描述

设置数据位
在这里插入图片描述
数据位默认8
在这里插入图片描述

设置停止位
在这里插入图片描述

设置校验位
在这里插入图片描述
调整串口设置、接收设置、发送设置为Group Box

在这里插入图片描述

修改配置

QT += core gui serialport 

代码详解

mianwindow.h

首先在mianwindow.h当中定义一个串口指针

public:
QSerialPort *serialPort;//定义串口指针

并且添加头文件

#include <QMainWindow>
#include <QSerialPort>
#include <QString>
#include <QSerialPortInfo>
#include <QMessageBox>
#include <QTimer>
#include <QPainter>

QMainWindow:是 Qt 中主窗口的基类,提供了主窗口的基本功能,如菜单栏、工具栏等。
QSerialPort:用于串口通信的类,可实现与串口设备的数据交互。
QString:Qt 中用于处理字符串的类,提供了丰富的字符串操作方法。
QSerialPortInfo:用于获取系统中可用串口的信息,如串口名称、描述等。
QMessageBox:用于显示消息框,可用于提示用户信息、警告或错误。
QTimer:用于实现定时器功能,可在指定时间间隔后触发特定操作。
QPainter:用于在窗口或其他绘图设备上进行绘图操作。

private:// 发送、接收字节计数long sendNum, recvNum;QLabel *lblSendNum;QLabel *lblRecvNum;QLabel *lblPortState;void setNumOnLabel(QLabel *lbl, QString strS, long num);// 定时发送-定时器QTimer *timSend;

Ui::MainWindow *ui;:指向由 Qt Designer 生成的用户界面类的指针,用于访问和操作界面元素。
long sendNum, recvNum;:用于记录发送和接收的字节数。
QLabel *lblSendNum;、QLabel *lblRecvNum;、QLabel *lblPortState;:分别指向用于显示发送字节数、接收字节数和串口状态的 QLabel 控件。
void setNumOnLabel(QLabel *lbl, QString strS, long num);:私有成员函数,用于将指定的数字显示在 QLabel 控件上。
QTimer *timSend;:指向 QTimer 对象的指针,用于实现定时发送功能。

private slots:/*手动连接槽函数*/void manual_serialPortReadyRead();/*以下为mainwindow.ui文件中点击“转到槽”自动生成的函数*/void on_openBt_clicked();void on_sendBt_clicked();void on_clearBt_clicked();void on_btnClearSend_clicked();void on_chkTimSend_stateChanged(int arg1);void on_btnSerialCheck_clicked();

void manual_serialPortReadyRead();:手动连接的槽函数,当串口有数据可读时触发。
void on_openBt_clicked();:当 openBt 按钮被点击时触发的槽函数,通常用于打开串口。
void on_sendBt_clicked();:当 sendBt 按钮被点击时触发的槽函数,通常用于发送数据。
void on_clearBt_clicked();:当 clearBt 按钮被点击时触发的槽函数,通常用于清除接收区的数据。
void on_btnClearSend_clicked();:当 btnClearSend 按钮被点击时触发的槽函数,通常用于清除发送区的数据。
void on_chkTimSend_stateChanged(int arg1);:当 chkTimSend 复选框的状态改变时触发的槽函数,用于处理定时发送的开启和关闭。
void on_btnSerialCheck_clicked();:当 btnSerialCheck 按钮被点击时触发的槽函数,通常用于检查系统中可用的串口。

mianwindow.cpp

MainWindow::MainWindow(QWidget *parent)

    serialPort = new QSerialPort(this);connect(serialPort,SIGNAL(readyRead()),this,SLOT(manual_serialPortReadyRead()));

将串口的 readyRead() 信号与自定义的槽函数 manual_serialPortReadyRead() 进行连接。

QMetaObject::Connection QObject::connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type = Qt::AutoConnection);

sender:发送信号的对象,这里是 serialPort,即 QSerialPort 对象。
signal:发送的信号,使用 SIGNAL 宏将信号名称转换为字符串。readyRead() 是 QSerialPort 类的一个信号,当串口接收到新的数据时会自动发出该信号。
receiver:接收信号的对象,这里是 this,即 MainWindow 对象本身。
method:接收信号后要执行的槽函数,使用 SLOT 宏将槽函数名称转换为字符串。manual_serialPortReadyRead() 是在 MainWindow 类中定义的一个私有槽函数,用于处理串口接收到的数据。
type:连接类型,默认为 Qt::AutoConnection,表示根据发送者和接收者所在的线程自动选择合适的连接方式。

    ui->serailCb->clear();//通过QSerialPortInfo查找可用串口foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts()){ui->serailCb->addItem(info.portName());}

ui->serailCb->clear();:
ui 是一个指向 Ui::MainWindow 类对象的指针,Ui::MainWindow 类通常是由 Qt Designer 生成的,用于管理主窗口的用户界面元素。
serailCb 是用户界面中的一个下拉列表控件(可能是 QComboBox 类型)。
clear() 是 QComboBox 类的一个成员函数,用于清除下拉列表中的所有现有选项。这一步是为了确保在添加新的串口选项之前,下拉列表中没有其他无关的选项。
foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts()):
foreach 是 Qt 提供的一个用于遍历容器的宏。在这里,它用于遍历 QSerialPortInfo::availablePorts() 返回的可用串口信息列表。
QSerialPortInfo 是 Qt 中用于获取串口设备信息的类,例如串口名称、描述、制造商等。
availablePorts() 是 QSerialPortInfo 类的一个静态成员函数,它返回一个包含系统中所有可用串口信息的 QList 列表。
const QSerialPortInfo &info 声明了一个常量引用 info,用于在每次迭代中存储当前遍历到的串口信息对象。通过引用的方式,可以避免不必要的对象拷贝,提高效率。
ui->serailCb->addItem(info.portName());:
对于 foreach 循环中的每一个串口信息对象 info,调用 portName() 成员函数获取该串口的名称。
然后使用 ui->serailCb->addItem() 将获取到的串口名称作为一个新的选项添加到下拉列表 serailCb 中。这样,用户就可以在下拉列表中选择系统中可用的串口设备了。

    // 发送、接收计数清零sendNum = 0;recvNum = 0;// 状态栏QStatusBar *sBar = statusBar();// 状态栏的收、发计数标签lblSendNum = new QLabel(this);lblRecvNum = new QLabel(this);lblPortState = new QLabel(this);lblPortState->setText("Connected");//设置串口状态标签为绿色 表示已连接状态lblPortState->setStyleSheet("color:red");

sendNum 和 recvNum 是在 MainWindow 类中定义的用于记录发送和接收字节数的变量。

statusBar() 是 QMainWindow 类的一个成员函数,用于获取主窗口的状态栏对象。sBar 是一个指向 QStatusBar 对象的指针,通过这个指针可以对状态栏进行操作,比如添加控件、设置文本等。

lblSendNum、lblRecvNum 和 lblPortState 是在 MainWindow 类中定义的指向 QLabel 对象的指针。
new QLabel(this) 动态创建了三个 QLabel 控件,分别用于显示发送字节数、接收字节数和串口连接状态。this 作为参数传递给 QLabel 的构造函数,表示将当前 MainWindow 对象作为这些 QLabel 控件的父对象,这样当 MainWindow 对象被销毁时,这些 QLabel 控件也会被自动销毁,避免内存泄漏。

setText() 是 QLabel 类的一个成员函数,用于设置标签上显示的文本内容。将 lblPortState 标签的文本设置为 “Connected”,表示串口已经成功连接。

    // 设置标签最小大小lblSendNum->setMinimumSize(100, 20);lblRecvNum->setMinimumSize(100, 20);lblPortState->setMinimumSize(550, 20);setNumOnLabel(lblSendNum, "S: ", sendNum);setNumOnLabel(lblRecvNum, "R: ", recvNum);// 从右往左依次添加sBar->addPermanentWidget(lblPortState);sBar->addPermanentWidget(lblSendNum);sBar->addPermanentWidget(lblRecvNum);

lblSendNum、lblRecvNum 和 lblPortState 是之前创建的 QLabel 控件指针,分别用于显示发送字节数、接收字节数和串口连接状态。
setMinimumSize(int width, int height) 是 QLabel 类从 QWidget 继承而来的一个成员函数,用于设置控件的最小宽度和高度。这里将 lblSendNum 和 lblRecvNum 的最小大小设置为宽 100 像素、高 20 像素,将 lblPortState 的最小大小设置为宽 550 像素、高 20 像素。这样做可以确保在界面布局变化时,这些标签不会被压缩到小于指定的大小,保证显示内容的完整性。

setNumOnLabel 是 MainWindow 类中定义的一个私有成员函数,用于将指定的字符串和数字组合后显示在 QLabel 控件上。
对于 lblSendNum,传递的参数 "S: " 作为前缀,sendNum 是之前清零后的发送字节数计数,函数会将它们组合成一个字符串并显示在 lblSendNum 标签上,用于提示用户发送数据的字节数。
同理,对于 lblRecvNum,传递的参数 "R: " 作为前缀,recvNum 是接收字节数计数,函数会将组合后的字符串显示在 lblRecvNum 标签上,用于提示用户接收数据的字节数。
sBar 是之前通过 statusBar() 函数获取的主窗口状态栏指针。
addPermanentWidget(QWidget * widget) 是 QStatusBar 类的一个成员函数,用于将一个 QWidget 类型的控件(这里是 QLabel 控件)永久添加到状态栏中。状态栏中的控件通常按照添加的顺序从左到右排列,但由于这里注释提到 “从右往左依次添加”,实际效果是 lblPortState 在最右边,然后是 lblSendNum,最后是 lblRecvNum 在最左边。这样在状态栏中就可以依次显示串口连接状态、发送字节数和接收字节数,方便用户查看相关信息。

    // 定时发送-定时器timSend = new QTimer;timSend->setInterval(1000);// 设置默认定时时长1000msconnect(timSend, &QTimer::timeout, this, [=](){on_sendBt_clicked();});

timSend 是 MainWindow 类中定义的一个指向 QTimer 对象的指针。
new QTimer 使用 new 运算符在堆上动态创建一个 QTimer 对象,该对象用于实现定时功能。创建后,timSend 指针指向这个新创建的 QTimer 对象。
setInterval(int msec) 是 QTimer 类的一个成员函数,用于设置定时器的时间间隔,单位是毫秒(ms)。
这里将定时器的时间间隔设置为 1000 毫秒,也就是 1 秒。意味着定时器每隔 1 秒就会触发一次超时信号 timeout()。
connect 是 Qt 中用于连接信号和槽的函数,它建立了信号发送者、信号、信号接收者和槽函数之间的关联。
timSend:信号的发送者,即刚刚创建的 QTimer 对象。
&QTimer::timeout:发送的信号,timeout() 是 QTimer 类的一个信号,当定时器超时时会自动发出该信号。
this:信号的接收者,这里是 MainWindow 对象本身。
={ on_sendBt_clicked(); }:一个 Lambda 表达式,作为槽函数。[=] 表示以值捕获的方式捕获 Lambda 表达式所在作用域中的所有变量,这样 Lambda 表达式内部就可以访问这些变量。on_sendBt_clicked() 是 MainWindow 类中定义的一个槽函数,通常用于处理发送按钮被点击时的操作,比如发送数据。当定时器超时发出 timeout() 信号时,这个 Lambda 表达式会被执行,进而调用 on_sendBt_clicked() 函数,实现定时发送数据的功能。

void MainWindow::setNumOnLabel(QLabel *lbl, QString strS, long num)

void MainWindow::setNumOnLabel(QLabel *lbl, QString strS, long num)
{// 标签显示// QString strN;// strN.sprintf("%ld", num);// QString strN = strFormat.arg(num);QString strN = QString::number(num);QString str = strS + strN;lbl->setText(str);
}

函数名称:setNumOnLabel,这是 MainWindow 类的一个成员函数,用于将一个字符串前缀和一个长整型数字组合成一个新的字符串,并将其显示在指定的 QLabel 控件上。
参数:
QLabel *lbl:一个指向 QLabel 控件的指针,该函数会将组合后的字符串显示在这个 QLabel 控件上。
QString strS:一个 QString 类型的字符串,作为组合字符串的前缀。
long num:一个长整型数字,将被转换为字符串并与前缀组合。
返回值:void,表示该函数不返回任何值。

QString::number() 是 QString 类的一个静态成员函数,用于将各种数值类型(如 int、long、double 等)转换为 QString 类型的字符串。这里将传入的长整型数字 num 转换为对应的字符串,并存储在 strN 变量中。

void MainWindow::on_sendBt_clicked()

/*发送数据*/
void MainWindow::on_sendBt_clicked()
{QByteArray array;//Hex复选框if(ui->chk_send_hex->checkState() == Qt::Checked){//array = QString2Hex(data);  //HEX 16进制array = QByteArray::fromHex(ui->sendEdit->toPlainText().toUtf8()).data();}else{//array = data.toLatin1();    //ASCIIarray = ui->sendEdit->toPlainText().toLocal8Bit().data();}if(ui->chk_send_line->checkState() == Qt::Checked){array.append("\r\n");}// 如发送成功,会返回发送的字节长度。失败,返回-1。int a = serialPort->write(array);// 发送字节计数并显示if(a > 0){// 发送字节计数sendNum += a;// 状态栏显示计数值setNumOnLabel(lblSendNum, "S: ", sendNum);}
}

QByteArray 是 Qt 中用于处理二进制数据的类,这里定义了一个 QByteArray 类型的对象 array,用于存储要发送的数据。
ui->chk_send_hex 是界面上的一个复选框,用于表示是否以十六进制格式发送数据。
如果该复选框被选中(checkState() == Qt::Checked),则将发送编辑框(ui->sendEdit)中的文本内容先转换为 UTF - 8 编码的 QByteArray,再使用 QByteArray::fromHex() 方法将其解析为十六进制数据,存储到 array 中。
如果该复选框未被选中,则将发送编辑框中的文本内容转换为本地编码(toLocal8Bit())的 QByteArray 并存储到 array 中。

ui->chk_send_line 是界面上的另一个复选框,用于表示是否在发送数据末尾添加换行符(\r\n)。
如果该复选框被选中,则使用 append() 方法将换行符添加到 array 末尾。

serialPort 是 MainWindow 类中定义的 QSerialPort 指针,用于串口通信。
write(const QByteArray &data) 是 QSerialPort 类的成员函数,用于向串口发送数据。该函数返回实际发送的字节数,如果发送失败则返回 -1。这里将发送的字节数存储在变量 a 中。

如果发送成功(a > 0),则将实际发送的字节数 a 累加到 sendNum 变量中,sendNum 用于记录总的发送字节数。
调用 setNumOnLabel() 函数将更新后的发送字节数显示在状态栏的 lblSendNum 标签上,标签前缀为 "S: "。

void MainWindow::on_openBt_clicked()

QSerialPort::BaudRate baudRate;
QSerialPort::DataBits dataBits;
QSerialPort::StopBits stopBits;
QSerialPort::Parity checkBits;

定义了四个变量,分别用于存储串口的波特率、数据位、停止位和奇偶校验位的设置。它们的类型是 QSerialPort 类中定义的枚举类型,用于准确表示串口通信的不同参数设置。

if(ui->baundrateCb->currentText()=="1200")baudRate=QSerialPort::Baud1200;
// 其他波特率判断代码...
else if(ui->baundrateCb->currentText()=="115200")baudRate=QSerialPort::Baud115200;

通过检查界面上波特率下拉框(ui->baundrateCb)当前选中的文本内容,来确定对应的波特率枚举值并赋值给 baudRate 变量。根据不同的文本内容,设置相应的波特率枚举值,如 Baud1200、Baud2400 等。

if(ui->databitCb->currentText()=="5")dataBits=QSerialPort::Data5;
// 其他数据位判断代码...
else if(ui->databitCb->currentText()=="8")dataBits=QSerialPort::Data8;

通过检查数据位下拉框(ui->databitCb)的当前文本内容,确定对应的串口数据位枚举值并赋值给 dataBits 变量,如 Data5、Data6 等。

if(ui->stopbitCb->currentText()=="1")stopBits=QSerialPort::OneStop;
// 其他停止位判断代码...
else if(ui->stopbitCb->currentText()=="2")stopBits=QSerialPort::TwoStop;

过检查停止位下拉框(ui->stopbitCb)的当前文本内容,确定对应的串口停止位枚举值并赋值给 stopBits 变量,如 OneStop、OneAndHalfStop 等。

if(ui->checkbitCb->currentText() == "none"){checkBits = QSerialPort::NoParity;
}// 其他奇偶校验位判断代码...
else if(ui->checkbitCb->currentText() == "偶校验"){checkBits = QSerialPort::EvenParity;
}

通过检查奇偶校验位下拉框(ui->checkbitCb)的当前文本内容,确定对应的串口奇偶校验位枚举值并赋值给 checkBits 变量,如 NoParity、OddParity 等。

serialPort->setPortName(ui->serailCb->currentText());
serialPort->setBaudRate(baudRate);
serialPort->setDataBits(dataBits);
serialPort->setStopBits(stopBits);
serialPort->setParity(checkBits);

使用之前获取到的串口参数,设置 serialPort 对象的属性。包括设置串口端口号(从端口号下拉框 ui->serailCb 获取)、波特率、数据位、停止位和奇偶校验位。

if(ui->openBt->text() == "打开串口"){if(serialPort->open(QIODevice::ReadWrite) == true){ui->openBt->setText("关闭串口");ui->serailCb->setEnabled(false);}else{QMessageBox::critical(this, "错误提示", "串口打开失败!!!\r\n该串口可能被占用\r\n请选择正确的串口");}// 状态栏显示端口状态代码...lblPortState->setText(status);lblPortState->setStyleSheet("color:green");
}else{serialPort->close();ui->openBt->setText("打开串口");ui->serailCb->setEnabled(true);// 状态栏显示端口状态代码...lblPortState->setText(status);lblPortState->setStyleSheet("color:red");
}

根据打开按钮(ui->openBt)当前的文本内容判断是要打开还是关闭串口:
如果按钮文本是 “打开串口”,则尝试以读写模式(QIODevice::ReadWrite)打开串口。如果打开成功,将按钮文本改为 “关闭串口”,并禁用端口号下拉框(ui->serailCb),同时在状态栏(lblPortState)显示串口已打开的状态信息,且设置状态栏文本颜色为绿色。如果打开失败,弹出一个错误提示框,显示串口打开失败的原因。
如果按钮文本是 “关闭串口”,则关闭串口,将按钮文本改回 “打开串口”,启用端口号下拉框,并在状态栏显示串口已关闭的状态信息,设置状态栏文本颜色为红色。

void MainWindow::on_clearBt_clicked()

/*清空接收*/
void MainWindow::on_clearBt_clicked()
{ui->recvEdit->clear();// 清除发送、接收字节计数sendNum = 0;recvNum = 0;// 状态栏显示计数值setNumOnLabel(lblSendNum, "S: ", sendNum);setNumOnLabel(lblRecvNum, "R: ", recvNum);
}

setNumOnLabel 是 MainWindow 类中定义的一个私有成员函数,用于将指定的前缀字符串和计数值组合成一个新的字符串,并将其显示在指定的 QLabel 控件上。
lblSendNum 和 lblRecvNum 是指向 QLabel 控件的指针,分别用于在状态栏上显示发送和接收字节的计数信息。
"S: " 和 "R: " 是前缀字符串,分别表示 “发送” 和 “接收”。
sendNum 和 recvNum 是当前的发送和接收字节计数

on_clearBt_clicked 函数的主要作用是为用户提供一种清除接收数据和重置计数信息的方式。当用户点击相应的清除按钮时,该函数会清空接收编辑框中的内容,将发送和接收字节的计数归零,并更新状态栏上的计数显示,以便用户重新开始统计和查看数据。

void MainWindow::on_btnClearSend_clicked()

void MainWindow::on_btnClearSend_clicked()
{ui->sendEdit->clear();// 清除发送字节计数sendNum = 0;// 状态栏显示计数值setNumOnLabel(lblSendNum, "S: ", sendNum);
}

void MainWindow::on_chkTimSend_stateChanged(int arg1)

// 定时发送开关 选择复选框
void MainWindow::on_chkTimSend_stateChanged(int arg1)
{// 获取复选框状态,未选为0,选中为2if(arg1 == 0){timSend->stop();// 时间输入框恢复可选ui->txtSendMs->setEnabled(true);}else{// 对输入的值做限幅,小于10ms会弹出对话框提示if(ui->txtSendMs->text().toInt() >= 10){timSend->start(ui->txtSendMs->text().toInt());// 设置定时时长,重新计数// 让时间输入框不可选,避免误操作(输入功能不可用,控件背景为灰色)ui->txtSendMs->setEnabled(false);}else{ui->chkTimSend->setCheckState(Qt::Unchecked);QMessageBox::critical(this, "错误提示", "定时发送的最小间隔为 10ms\r\n请确保输入的值 >=10");}}
}

arg1 == 0 表示复选框处于未选中状态。
timSend 是 QTimer 类型的对象指针,用于实现定时发送功能。timSend->stop() 会停止定时器,即停止定时发送的操作。
ui->txtSendMs 是界面上用于输入定时时间(毫秒)的文本框。setEnabled(true) 方法将该文本框设置为可编辑状态,允许用户修改定时时间。
当 arg1 不等于 0 时,表示复选框被选中。
ui->txtSendMs->text().toInt() 会将文本框中输入的文本转换为整数,代表用户设置的定时时间(毫秒)。
如果该值大于等于 10 毫秒,timSend->start(ui->txtSendMs->text().toInt()) 会启动定时器,并将定时时间设置为用户输入的值,开始重新计数。同时,ui->txtSendMs->setEnabled(false) 会将文本框设置为不可编辑状态,防止用户在定时发送功能开启后误修改定时时间。
如果该值小于 10 毫秒,ui->chkTimSend->setCheckState(Qt::Unchecked) 会将复选框重新设置为未选中状态,QMessageBox::critical 会弹出一个错误提示框,告知用户定时发送的最小间隔为 10 毫秒,并提醒用户确保输入的值大于等于 10。

void MainWindow::manual_serialPortReadyRead()

QByteArray recBuf = serialPort->readAll();
QString str_rev;// 接收字节计数
recvNum += recBuf.size();
// 状态栏显示计数值
setNumOnLabel(lblRecvNum, "R: ", recvNum);

serialPort->readAll() 会读取串口缓冲区中的所有数据,并将其存储在 QByteArray 类型的 recBuf 中。
recvNum 是一个用于记录接收字节总数的变量,recBuf.size() 表示本次接收到的数据字节数,将其累加到 recvNum 中。
setNumOnLabel 函数用于将更新后的接收字节数显示在状态栏的 lblRecvNum 标签上。

if(ui->chk_rev_hex->checkState() == false){if(ui->chk_rev_time->checkState() == Qt::Checked){QDateTime nowtime = QDateTime::currentDateTime();str_rev = "[" + nowtime.toString("yyyy-MM-dd hh:mm:ss") + "] ";str_rev += QString(recBuf).append("\r\n");}else{if(ui->chk_rev_line->checkState() == Qt::Checked){str_rev = QString(recBuf).append("\r\n");}else{str_rev = QString(recBuf);}}
}

ui->chk_rev_hex 是一个复选框,用于控制是否以十六进制显示接收到的数据。如果该复选框未被选中(checkState() == false),则按非十六进制方式处理数据。
若 ui->chk_rev_time 复选框被选中,会获取当前时间并格式化为 yyyy-MM-dd hh:mm:ss 的字符串,添加到 str_rev 中,然后将接收到的数据转换为 QString 类型并添加换行符后追加到 str_rev 中。
若 ui->chk_rev_time 未被选中,再根据 ui->chk_rev_line 复选框的状态决定是否添加换行符。

else{// 16进制显示,并转换为大写QString str1 = recBuf.toHex().toUpper();// 添加空格QString str2;for(int i = 0; i<str1.length (); i+=2){str2 += str1.mid (i,2);str2 += " ";}if(ui->chk_rev_time->checkState() == Qt::Checked){QDateTime nowtime = QDateTime::currentDateTime();str_rev = "[" + nowtime.toString("yyyy-MM-dd hh:mm:ss") + "] ";str_rev += str2.append("\r\n");}else{if(ui->chk_rev_line->checkState() == Qt::Checked)str_rev += str2.append("\r\n");elsestr_rev = str2;}
}

若 ui->chk_rev_hex 复选框被选中,则按十六进制方式处理数据。
recBuf.toHex().toUpper() 将接收到的数据转换为十六进制字符串并转换为大写。
通过循环在每两个十六进制字符之间添加一个空格。
同样根据 ui->chk_rev_time 和 ui->chk_rev_line 复选框的状态决定是否添加时间戳和换行符。

ui->recvEdit->insertPlainText(str_rev);
ui->recvEdit->moveCursor(QTextCursor::End);

ui->recvEdit 是接收编辑框,insertPlainText(str_rev) 将处理后的字符串 str_rev 插入到编辑框中。
moveCursor(QTextCursor::End) 将编辑框的光标移动到文本末尾,确保新接收到的数据能及时显示在界面上,避免界面不滚动的问题。

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include <QSerialPort>
#include <QString>
#include <QSerialPortInfo>
#include <QMessageBox>
#include <QTimer>
#include <QPainter>QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();QSerialPort *serialPort;//定义串口指针private slots:/*手动连接槽函数*/void manual_serialPortReadyRead();/*以下为mainwindow.ui文件中点击“转到槽”自动生成的函数*/void on_openBt_clicked();void on_sendBt_clicked();void on_clearBt_clicked();void on_btnClearSend_clicked();void on_chkTimSend_stateChanged(int arg1);void on_btnSerialCheck_clicked();private:Ui::MainWindow *ui;// 发送、接收字节计数long sendNum, recvNum;QLabel *lblSendNum;QLabel *lblRecvNum;QLabel *lblPortState;void setNumOnLabel(QLabel *lbl, QString strS, long num);// 定时发送-定时器QTimer *timSend;//QTimer *timCheckPort;
};
#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "QSerialPortInfo"
#include <QSerialPort>
#include <QMessageBox>
#include <QDateTime>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);QStringList serialNamePort;serialPort = new QSerialPort(this);//当串口接收到新的数据时,QSerialPort 对象会发出 readyRead() 信号,MainWindow 对象会接收到该信号并调用 manual_serialPortReadyRead() 槽函数来处理接收到的数据。connect(serialPort,SIGNAL(readyRead()),this,SLOT(manual_serialPortReadyRead()));/*手动连接槽函数*/ui->serailCb->clear();//清除下拉列表中的所有现有选项//通过QSerialPortInfo查找可用串口//foreach 用于遍历 QSerialPortInfo foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts()){//将遍历到info的名称添加到serailCbui->serailCb->addItem(info.portName());}// 发送、接收计数清零//sendNum 和 recvNum 是在 MainWindow 类中定义的用于记录发送和接收字节数的变量。sendNum = 0;recvNum = 0;// 状态栏QStatusBar *sBar = statusBar();// 状态栏的收、发计数标签lblSendNum = new QLabel(this);lblRecvNum = new QLabel(this);lblPortState = new QLabel(this);lblPortState->setText("Connected");//设置串口状态标签为红色 表示未连接状态lblPortState->setStyleSheet("color:red");// 设置标签最小大小lblSendNum->setMinimumSize(100, 20);lblRecvNum->setMinimumSize(100, 20);lblPortState->setMinimumSize(550, 20);setNumOnLabel(lblSendNum, "S: ", sendNum);setNumOnLabel(lblRecvNum, "R: ", recvNum);// 从右往左依次添加sBar->addPermanentWidget(lblPortState);sBar->addPermanentWidget(lblSendNum);sBar->addPermanentWidget(lblRecvNum);// 定时发送-定时器timSend = new QTimer;//设置定时器的时间间隔,单位是毫秒(ms)。timSend->setInterval(1000);// 设置默认定时时长1000msconnect(timSend, &QTimer::timeout, this, [=](){on_sendBt_clicked();});
}MainWindow::~MainWindow()
{delete ui;
}//检测通讯端口槽函数
void MainWindow::on_btnSerialCheck_clicked()
{ui->serailCb->clear();//通过QSerialPortInfo查找可用串口foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts()){ui->serailCb->addItem(info.portName());}
}/*手动实现接收数据函数*/
void MainWindow::manual_serialPortReadyRead()
{QByteArray recBuf = serialPort->readAll();;QString str_rev;// 打印接收到的原始数据qDebug() << "Received raw data:" << recBuf;// 接收字节计数recvNum += recBuf.size();// 状态栏显示计数值setNumOnLabel(lblRecvNum, "R: ", recvNum);if(ui->chk_rev_hex->checkState() == false){if(ui->chk_rev_time->checkState() == Qt::Checked){QDateTime nowtime = QDateTime::currentDateTime();str_rev = "[" + nowtime.toString("yyyy-MM-dd hh:mm:ss") + "] ";str_rev += QString(recBuf).append("\r\n");}else{// 在当前位置插入文本,不会发生换行。如果没有移动光标到文件结尾,会导致文件超出当前界面显示范围,界面也不会向下滚动。//ui->recvEdit->appendPlainText(buf);if(ui->chk_rev_line->checkState() == Qt::Checked){str_rev = QString(recBuf).append("\r\n");}else{str_rev = QString(recBuf);}}}else{// 16进制显示,并转换为大写QString str1 = recBuf.toHex().toUpper();//.data();// 添加空格QString str2;for(int i = 0; i<str1.length (); i+=2){str2 += str1.mid (i,2);str2 += " ";}if(ui->chk_rev_time->checkState() == Qt::Checked){QDateTime nowtime = QDateTime::currentDateTime();str_rev = "[" + nowtime.toString("yyyy-MM-dd hh:mm:ss") + "] ";str_rev += str2.append("\r\n");}else{if(ui->chk_rev_line->checkState() == Qt::Checked)str_rev += str2.append("\r\n");elsestr_rev = str2;}}ui->recvEdit->insertPlainText(str_rev);ui->recvEdit->moveCursor(QTextCursor::End);// 打印处理后的数据qDebug() << "Processed data:" << str_rev;
}/*打开串口*/
void MainWindow::on_openBt_clicked()
{/*串口初始化*/QSerialPort::BaudRate baudRate;QSerialPort::DataBits dataBits;QSerialPort::StopBits stopBits;QSerialPort::Parity checkBits;// 获取串口波特率// baudRate = ui->baundrateCb->currentText().toInt();直接字符串转换为 int 的方法if(ui->baundrateCb->currentText()=="1200")baudRate=QSerialPort::Baud1200;else if(ui->baundrateCb->currentText()=="2400")baudRate=QSerialPort::Baud2400;else if(ui->baundrateCb->currentText()=="4800")baudRate=QSerialPort::Baud4800;else if(ui->baundrateCb->currentText()=="9600")baudRate=QSerialPort::Baud9600;else if(ui->baundrateCb->currentText()=="19200")baudRate=QSerialPort::Baud19200;else if(ui->baundrateCb->currentText()=="38400")baudRate=QSerialPort::Baud38400;else if(ui->baundrateCb->currentText()=="57600")baudRate=QSerialPort::Baud57600;else if(ui->baundrateCb->currentText()=="115200")baudRate=QSerialPort::Baud115200;// 获取串口数据位if(ui->databitCb->currentText()=="5")dataBits=QSerialPort::Data5;else if(ui->databitCb->currentText()=="6")dataBits=QSerialPort::Data6;else if(ui->databitCb->currentText()=="7")dataBits=QSerialPort::Data7;else if(ui->databitCb->currentText()=="8")dataBits=QSerialPort::Data8;// 获取串口停止位if(ui->stopbitCb->currentText()=="1")stopBits=QSerialPort::OneStop;else if(ui->stopbitCb->currentText()=="1.5")stopBits=QSerialPort::OneAndHalfStop;else if(ui->stopbitCb->currentText()=="2")stopBits=QSerialPort::TwoStop;// 获取串口奇偶校验位if(ui->checkbitCb->currentText() == "none"){checkBits = QSerialPort::NoParity;}else if(ui->checkbitCb->currentText() == "奇校验"){checkBits = QSerialPort::OddParity;}else if(ui->checkbitCb->currentText() == "偶校验"){checkBits = QSerialPort::EvenParity;}else{}// 初始化串口属性,设置 端口号、波特率、数据位、停止位、奇偶校验位数serialPort->setPortName(ui->serailCb->currentText());serialPort->setBaudRate(baudRate);serialPort->setDataBits(dataBits);serialPort->setStopBits(stopBits);serialPort->setParity(checkBits);// 根据初始化好的串口属性,打开串口// 如果打开成功,反转打开按钮显示和功能。打开失败,无变化,并且弹出错误对话框。if(ui->openBt->text() == "打开串口"){if(serialPort->open(QIODevice::ReadWrite) == true){//QMessageBox::ui->openBt->setText("关闭串口");// 让端口号下拉框不可选,避免误操作(选择功能不可用,控件背景为灰色)ui->serailCb->setEnabled(false);}else{QMessageBox::critical(this, "错误提示", "串口打开失败!!!\r\n该串口可能被占用\r\n请选择正确的串口");}//statusBar 状态栏显示端口状态QString sm = "%1 OPENED, %2, 8, NONE, 1";QString status = sm.arg(serialPort->portName()).arg(serialPort->baudRate());lblPortState->setText(status);lblPortState->setStyleSheet("color:green");}else{serialPort->close();ui->openBt->setText("打开串口");// 端口号下拉框恢复可选,避免误操作ui->serailCb->setEnabled(true);//statusBar 状态栏显示端口状态QString sm = "%1 CLOSED";QString status = sm.arg(serialPort->portName());lblPortState->setText(status);lblPortState->setStyleSheet("color:red");}}/*发送数据*/
void MainWindow::on_sendBt_clicked()
{QByteArray array;//Hex复选框if(ui->chk_send_hex->checkState() == Qt::Checked){//array = QString2Hex(data);  //HEX 16进制array = QByteArray::fromHex(ui->sendEdit->toPlainText().toUtf8()).data();}else{//array = data.toLatin1();    //ASCIIarray = ui->sendEdit->toPlainText().toLocal8Bit().data();}if(ui->chk_send_line->checkState() == Qt::Checked){array.append("\r\n");}// 打印需要发送的数据qDebug() << "Data to be sent:" << array;// 如发送成功,会返回发送的字节长度。失败,返回-1。int a = serialPort->write(array);// 发送字节计数并显示if(a > 0){// 发送字节计数sendNum += a;// 状态栏显示计数值setNumOnLabel(lblSendNum, "S: ", sendNum);}
}
// 状态栏标签显示计数值
void MainWindow::setNumOnLabel(QLabel *lbl, QString strS, long num)
{// 标签显示// QString strN;// strN.sprintf("%ld", num);// QString strN = strFormat.arg(num);QString strN = QString::number(num);QString str = strS + strN;lbl->setText(str);
}
/*清空接收*/
void MainWindow::on_clearBt_clicked()
{ui->recvEdit->clear();// 清除发送、接收字节计数sendNum = 0;recvNum = 0;// 状态栏显示计数值setNumOnLabel(lblSendNum, "S: ", sendNum);setNumOnLabel(lblRecvNum, "R: ", recvNum);
}void MainWindow::on_btnClearSend_clicked()
{ui->sendEdit->clear();// 清除发送字节计数sendNum = 0;// 状态栏显示计数值setNumOnLabel(lblSendNum, "S: ", sendNum);
}
// 定时发送开关 选择复选框
void MainWindow::on_chkTimSend_stateChanged(int arg1)
{// 获取复选框状态,未选为0,选中为2if(arg1 == 0){timSend->stop();// 时间输入框恢复可选ui->txtSendMs->setEnabled(true);}else{// 对输入的值做限幅,小于10ms会弹出对话框提示if(ui->txtSendMs->text().toInt() >= 10){timSend->start(ui->txtSendMs->text().toInt());// 设置定时时长,重新计数// 让时间输入框不可选,避免误操作(输入功能不可用,控件背景为灰色)ui->txtSendMs->setEnabled(false);}else{ui->chkTimSend->setCheckState(Qt::Unchecked);QMessageBox::critical(this, "错误提示", "定时发送的最小间隔为 10ms\r\n请确保输入的值 >=10");}}
}

参考

https://blog.csdn.net/weixin_44788542/article/details/130508621

相关文章:

QT:串口上位机

创建工程 布局UI界面 设置名称 设置数据 设置波特率 波特率默认9600 设置数据位 数据位默认8 设置停止位 设置校验位 调整串口设置、接收设置、发送设置为Group Box 修改配置 QT core gui serialport 代码详解 mianwindow.h 首先在mianwindow.h当中定义一个串口指…...

f QT测试

# 添加 Qt Test 模块&#xff0c;用于支持单元测试功能 QT testlib# 添加 Qt 的核心模块和 GUI 模块&#xff0c;这是构建 Qt 应用程序的基础模块 QT core gui# 如果 Qt 的主版本号大于 4&#xff0c;则添加 widgets 模块。 # 这是因为 Qt Widgets 模块是从 Qt 5 开始引…...

vue3在ts中动态添加DOM(1、使用render函数,2、使用tsx)

1、使用render函数和h函数 h函数创建虚拟节点&#xff08;VNode&#xff09;&#xff0c;render函数实现虚拟节点生成真实DOM元素 实现添加一个el-button按钮 <script setup lang"ts"> import { ElButton } from "element-plus"; //需要在页面中引…...

C++基础(VScode环境安装)

MinGW Distro - nuwen.net 安装完成之后我们打开刚刚的安装路径&#xff0c;找到并打开MinGW -> bin,进入bin文件夹之后点一下这里&#xff0c;右键复制路径 之后我们进入设置&#xff0c;搜索“环境变量”&#xff0c;选择“编辑系统环境变量” 按WinR,输入cmd&#xff0…...

MySQL:SQL优化实际案例解析(持续更新)

文章目录 一、MySQL&#xff1a;SQL优化1、时间格式化问题&#xff08;字符串&#xff09;2、in/inner join的问题 一、MySQL&#xff1a;SQL优化 1、时间格式化问题&#xff08;字符串&#xff09; -- 优化前 SELECT * FROM test_table WHERE date_format( begin_time, %Y-%…...

代理(Delegate)、闭包(Closure)、Notification(通知中心) 和 swift_event_bus适用场景和工作方式

在 Swift 开发中&#xff0c;在 Swift 开发中&#xff0c;代理&#xff08;Delegate&#xff09;、闭包&#xff08;Closure&#xff09;、Notification&#xff08;通知中心&#xff09; 和 swift_event_bus 主要用于 组件之间的通信&#xff0c;但它们的适用场景和工作方式有…...

力扣第585题

with t as (select *, count(tiv_2015) over(partition by tiv_2015) cnt1 , count(*) over(partition by lat,lon) cnt2 from insurance) select round(sum(tiv_2016),2) tiv_2016 from t where cnt1>1 and cnt21; 以上代码的思路&#xff1a; ①明确查询需求&#xff1a…...

C++学习——顺序表(四)

文章目录 前言一、最大连续1的个数二、差的绝对值为K的数对数目三、数组中两元素的最大乘积四、数组元素和与数字和的绝对值的差五、K个元素的最大和六、等差三元组的数目七、移除元素 前言 本文为《C学习》的第14篇文章&#xff0c;今天通过Leetcode的几道题来熟悉顺序表的大…...

java虚拟机(JVM)以及各种参数详解

Java 虚拟机&#xff08;JVM&#xff09;提供了许多参数来调整其行为和性能&#xff0c;以便更好地适应不同的应用场景。理解和使用这些参数对于优化 Java 应用程序的性能非常重要。以下是一些常用的 JVM 参数及其详细说明&#xff1a; 1. 内存管理参数 -Xms<size>&…...

Android电量与流量优化

Android电量与流量优化 一、电量优化基础 1.1 电量消耗原理 Android设备的电量消耗主要来源于以下几个方面: 屏幕显示:屏幕是耗电量最大的硬件之一,尤其是高亮度和高刷新率的屏幕。CPU处理:CPU执行计算任务时会消耗大量电量,尤其是高负载运算。网络通信:移动数据、Wi-…...

机器人运动学与动力学

在当今科技飞速发展的时代&#xff0c;机器人已逐渐渗透到我们生活的方方面面&#xff0c;从工业生产线上的高效作业&#xff0c;到医疗领域的精准辅助&#xff0c;再到家庭服务的贴心陪伴&#xff0c;机器人技术的广泛应用正深刻改变着我们的生活和工作方式。而在机器人技术的…...

【web前端开发】HTML排版标签、HTML语义化标签、常用的文本标签

1、HTML排版标签 标签名 标签含义 单/双标签 h1~h6 …...

Linux的TTY子系统(TTY框架)的重要结构体termios的`c_iflag`字段的BRKINT选项和IGNBRK选项的含义【详解串口的BREAK信号】

引言 要搞清楚结构体termios的c_iflag字段的BRKINT选项和IGNBRK选项的含义&#xff0c;首先要搞清楚BREAK信号的含义。其实当你搞清楚BREAK信号后&#xff0c;结构体termios的c_iflag字段的BRKINT选项和IGNBRK选项的含义你也就自然知道了。 1. 什么是 BREAK 信号&#xff1f;…...

YashanDB认证,YCA证书认证教程,免费证书,内含真题考试题库及答案——五分钟速成

目录 一.账号及平台注册登录流程 二.登录进行设备调试核验 三.考试&#xff08;考完获取分数&#xff09; 四.获取证书 五.题库及答案 一.账号及平台注册登录流程 1-点击这里进行账号注册&#xff08;首次学习必须先注册&#xff0c;有账号之后可以直接在2号链接登录&#…...

网络爬虫-1:发送请求+维持会话+代理设置/超时设置

1.基于get发送请求 2.基于post发送请求 3.维持会话 4.代理设置/超时设置 一.基于get发送请求 1.获取网页源码1 使用json库中的json.loads(),将json格式的字符串变为Python的字典形式 以下通过http://httpbin.org/get网址进行基本练习操作 import requests import json urlh…...

VSCode 配置优化指南:打造极致高效的前端开发环境

VSCode 配置优化指南&#xff1a;打造极致高效的前端开发环境 一、基础环境配置&#xff1a;让开发更流畅 1. 性能优化设置 // settings.json {"files.autoSave": "afterDelay", // 自动保存&#xff08;延迟1秒&#xff09;"files.exclud…...

【实战-解决方案】Webpack 打包后很多js方法报错:not defined

问题分析 在不打包的情况下&#xff0c;方法&#xff08;如 checkLoginStatus、filterSites、initProgressBar 等&#xff09;可以正常运行&#xff0c;而经过 Webpack 打包后报 is not defined 错误&#xff0c;通常有以下几个可能的原因&#xff1a; 全局变量丢失 在 Webpac…...

第16届计算智能与软件工程国际研讨会(CISE 2026)

第16届计算智能与软件工程国际研讨会(CISE 2026) The 16th Intl Conference on Computational Intelligence and Software Engineering(CISE 2026) 时间&#xff1a;2026年1月9-11日 地点&#xff1a;中国 三亚 邮箱投稿&#xff1a;editor1academicx.org 检索&#xff1…...

laravel中 添加公共/通用 方法/函数

一&#xff0c;现在app 下面创建Common目录&#xff0c;然后在创建Common.php 文件 二&#xff0c;修改composer.json文件 添加这个到autoload 中 "files": ["app/Common/Common.php"]"autoload": {"psr-4": {"App\\": &quo…...

Android 自定义View之底部导航栏

文章目录 Android 自定义View之底部导航栏概述代码定义TabIndex定义Tab定义TabView定义NavigationBarFragmentSwitchHelper管理类使用 源码下载 Android 自定义View之底部导航栏 概述 封装一个通用的底部导航栏控件。 代码 定义TabIndex Retention(AnnotationRetention.SOU…...

[Kubernetes] 7控制平面组件

1. 调度 kube- scheduler what 负责分配调度pod到集群节点监听kube-apiserver,查询未分配node的pod根据调度策略分配这些pod&#xff08;更新pod的nodename&#xff09;需要考虑的因素&#xff1a; 公平调度&#xff0c;资源有效利用&#xff0c;QoS&#xff0c;affinity, an…...

定时器Tim输出比较(output compare)

输出比较OC(Output Compare) 输出比较可以通过比较CNT与CCR寄存器值的关系&#xff0c;来对输出电平进行置1、置0或翻转的操作&#xff0c;用于输出一定频率和占空比的PWM波形 每个高级定时器和通用定时器都拥有4个输出比较通道&#xff0c;高级定时器的前3个通道额外拥有死区生…...

Linux Shell 脚本编程极简入门指南

一、学习前提准备 ✅ 环境要求&#xff1a; Linux系统&#xff08;Ubuntu/CentOS等&#xff09;或 WSL (Windows用户) 任意文本编辑器&#xff08;推荐VSCode/Vim&#xff09; 基础命令行操作能力 &#x1f50d; 验证环境&#xff1a; # 查看系统默认Shell echo $SHELL #…...

C++:二分习题

1. 借教室 503. 借教室 - AcWing题库 在大学期间&#xff0c;经常需要租借教室。 大到院系举办活动&#xff0c;小到学习小组自习讨论&#xff0c;都需要向学校申请借教室。 教室的大小功能不同&#xff0c;借教室人的身份不同&#xff0c;借教室的手续也不一样。  面对海…...

【AIGC】计算机视觉-YOLO系列家族

YOLO系列家族 &#xff08;1&#xff09;YOLO发展史&#xff08;2&#xff09; YOLOX&#xff08;3&#xff09; YOLOv6&#xff08;4&#xff09; YOLOv7&#xff08;5&#xff09; YOLOv8&#xff08;6&#xff09; YOLOv9&#xff08;7&#xff09;YOLOv10&#xff08;8&…...

浅谈SSE爬虫

什么是SSE SSE(Server-Sent Events,服务器推送事件)是一种用于在Web应用程序中实现单向实时数据传输的技术。它允许服务器通过HTTP连接向客户端(通常是浏览器)推送更新的数据,而无需客户端主动请求。 目前主流的大模型 就是采用的 SSE,想deepseek、chatgpt、通以千问。…...

Goland如何玩依赖注入——基于gone@v2创建一个service

经过多天的工作&#xff0c;终于把gone2的beta版本发布出去了。在v2版本中&#xff0c;做了很多更新&#xff0c;最大的改进是将一些不必要的概念给隐藏起来了&#xff0c;提供了Provider机制…… 文章目录 1. 安装**gonectr**2.创建项目2.1 项目结构 2.2 简单说明3. 启动项目…...

rpmlib(SetVersions) is needed by can-uilts-v2019.00.0-alt1.aarch64

在我在Linux中安装离线CAN工具时&#xff0c;出现了一个问题&#xff0c; rootwanghuo:~# rpm -ivh can-uilts-v2019.00.0-alt1.aarch64.rpm error: Failed dependencies:rpmlib(SetVersions) is needed by can-uilts-v2019.00.0-alt1.aarch64 意思是尝试安装 can-uilts-v20…...

处理Java中的异常

处理Java中的异常 在 Java 中&#xff0c;异常处理是通过 try-catch-finally 语句来实现的。Java 提供了一种强大的机制&#xff0c;用于捕捉和处理程序运行中的各种错误和异常。通过这种方式&#xff0c;你可以有效地捕捉到可能导致程序崩溃的错误&#xff0c;并做出相应的处…...

mac 苍穹外卖 前端环境配置

博主的 mac 是 m2。 结合以下两篇&#xff0c;成功配置前端环境。 macOS 配置苍穹外卖前端环境_macbook怎么nginx下载外卖-CSDN博客 苍穹外卖-Mac配置前端开发环境_sudo 启动 nginx 有什么区别-CSDN博客 一、安装nginx 我使用的是 homebrew&#xff0c;homebrew 的安装请自…...

前端系统测试(单元、集成、数据|性能|回归)

有关前端测试的面试题 系统测试 首先,功能测试部分。根据资料,单元测试是验证最小可测试单元的正确性,比如函数或组件。都提到了单元测试的重要性,强调其在开发早期发现问题,并通过自动化提高效率。需要整合我搜索到的资料中的观点,比如单元测试的方法(接口测试、路径覆…...

Python:函数式编程

函数式编程&#xff08;Functional Programming, FP&#xff09;是一种编程范式&#xff0c;强调通过纯函数、不可变数据和声明式风格来构建程序。Python 虽然不是纯函数式语言&#xff0c;但提供了丰富的函数式编程工具。(简单来说是&#xff0c;函数约等于模块功能&#xff0…...

Spring Boot中@Valid 与 @Validated 注解的详解

Spring Boot中Valid 与 Validated 注解的详解 引言 在Spring Boot应用中&#xff0c;参数校验是确保数据完整性和一致性的重要手段。Valid和Validated注解是Spring Boot中用于参数校验的两个核心注解。本文将详细介绍这两个注解的用法、区别以及代码样例。 Valid注解 功能介…...

[动手学习深度学习]12.权重衰退

1.介绍 权重衰退是常见的处理过拟合的方法 控制模型容量方法 把模型控制的比较小&#xff0c;即里面参数比较少使参数选择范围小 约束就是正则项 每个特征的权重都大会导致模型复杂&#xff0c;从而导致过拟合。 控制权重矩阵范数可以使得减少一些特征的权重&#xff0c;甚至…...

JVM内存结构笔记04-字符串常量池

文章目录 定义字符串常量池的位置JDK 1.7 为什么要将字符串常量池移动到堆中&#xff1f; StringTable案例1案例2案例3 String.intern()案例4案例5案例6总结 StringTable 垃圾回收案例1.创建100个字符串(不会触发垃圾回收)2.创建10000个字符串(触发垃圾回收) StringTable 性能调…...

STM32 HAL库实战:高效整合DMA与ADC开发指南

STM32 HAL库实战&#xff1a;高效整合DMA与ADC开发指南 一、DMA与ADC基础介绍 1. DMA&#xff1a;解放CPU的“数据搬运工” DMA&#xff08;Direct Memory Access&#xff09; 是STM32中用于在外设与内存之间直接传输数据的硬件模块。其核心优势在于无需CPU干预&#xff0c;…...

c语言闯算法--常用技巧

双指针 类别&#xff1a; 同向快慢指针 异常情况&#xff0c;慢指针才动 双向指针 视情况&#xff0c;左右指针动 最长无重复子串 int max(int a, int b){if(a < b){return b;}else{return a;} } int lengthOfLongestSubstring(char* s) {int count[300];for(int i 0; i …...

docker启动jenkins,jenkins中调用docker

在jenkins中执行docker 思路 jenkins中安装docker客户端&#xff0c;使用第三方的docker(需要付费)。jenkins中安装docker客户端&#xff0c;另一个容器中安装docker服务&#xff0c; docker-in-docker&#xff0c;需要特权模式&#xff0c;或者第三方的工具。jenkins中什么都…...

【设计模式】设计模式介绍

一、设计模式概述 设计模式分很多种&#xff0c;每种一般都用于解决某个软件开发过程中的问题。许多人认为设 计模式有23种&#xff0c;其实&#xff0c;对于这个数字也没必要那么教条&#xff0c;当然还有更多的设计模式种类&#xff0c;只 不过是这23种比较经典而已。甚至可…...

图形学面试题总结

图形学面试题总结 文章目录 图形学面试题总结Opengl 与 Vulkan1、OpenGL的渲染管线有哪些主要阶段&#xff1f;分别做什么&#xff1f;2、OpenGL中的VAO、VBO和EBO分别是什么&#xff1f;为什么需要它们&#xff1f;3、细分着色器与几何着色器是什么4、Vulkan与Opengl的区别是什…...

Spring Cloud Alibaba 实战:Sentinel 保障微服务的高可用性与流量防护

1.1 Sentinel 作用 Sentinel 是阿里巴巴开源的一款 流量控制和熔断降级 框架&#xff0c;主要用于&#xff1a; 流量控制&#xff1a;限制 QPS&#xff0c;防止流量暴增导致系统崩溃熔断降级&#xff1a;当某个服务不可用时自动降级&#xff0c;避免故障扩散热点参数限流&…...

Comfyui 与 SDwebui

ComfyUI和SD WebUI是基于Stable Diffusion模型的两种不同用户界面工具&#xff0c;它们在功能、用户体验和适用场景上各有优劣。 1. 功能与灵活性 ComfyUI&#xff1a;ComfyUI以其节点式工作流设计为核心&#xff0c;强调用户自定义和灵活性。用户可以通过连接不同的模块&…...

面试之《前端常见的设计模式》

前端开发中运用多种设计模式可以提高代码的可维护性、可扩展性和可复用性。以下是一些常见的前端设计模式&#xff1a; 创建型模式 1. 单例模式 定义&#xff1a;确保一个类只有一个实例&#xff0c;并提供一个全局访问点。应用场景&#xff1a;在前端中&#xff0c;像全局状…...

PostgreSQL异常:An IO error occurred while sending to the backend

在使用PostgreSQL数据库批量写入数据的时候&#xff0c;遇到了一个问题&#xff0c;异常内容如下&#xff1a; Cause: org.postgresql.util.PSQLException: An I/O error occurred while sending to the backend.报错内容 报错提示1 Caused by: org.postgresql.util.PSQLExc…...

嵌入式八股C语言---面向对象篇

面向对象与面向过程 面向过程 就是把整个业务逻辑分成多个步骤,每步或每一个功能都可以使用一个函数来实现面向对象 对象是类的实例化,此时一个类就内部有属性和相应的方法 封装 在C语言里实现封装就是实现一个结构体,里面包括的成员变量和函数指针,然后在构造函数中,为结构体…...

一周学会Flask3 Python Web开发-使用SQLAlchemy动态创建数据库表

锋哥原创的Flask3 Python Web开发 Flask3视频教程&#xff1a; 2025版 Flask3 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili 前面我们定义了模型&#xff0c;我们可以通过sqlalchemy对象提供的create_all()方法来映射和动态创建数据库表。 因为我们用到…...

【spring】springAOP

1.基本概念 AOP即面向切面编程&#xff0c;它利用的是一种横切技术&#xff0c;解剖开封装的对象内部&#xff0c;并将那些影响多个类的公共行为封装到一个可重 用模块&#xff0c;这就是所谓的Aspect方面/切面。所谓的切面&#xff0c;简单点所说&#xff0c;就是将哪些与业务…...

解决VMware虚拟机CentOS 7 忘记登陆密码问题

1. 重启虚拟机&#xff0c;在重启时不停按E键进入初始化脚本编辑界面 2.在初始化脚本编辑界面&#xff0c;按↓键向下拉到最后&#xff0c;找到LANG/zh_CN.UTF-8那里&#xff0c;输入空格&#xff0c;接着添加 "init/bin/sh" 。然后按ctrlX键进入下一步。 3. 在界面中…...

如何在 Windows 10 启用卓越性能模式及不同电源计划对比

在使用 powercfg -duplicatescheme 命令启用 “卓越性能模式”&#xff08;即 Ultimate Performance 模式&#xff09;之前&#xff0c;有几个前提条件需要注意&#xff1a; 前提条件&#xff1a; 系统版本要求&#xff1a;卓越性能模式 仅在 Windows 10 专业版 或更高版本&a…...

基于 GEE 利用 Sentinel-2 数据反演叶绿素与冠层水分含量

目录 1 数据加载与预处理 2 叶绿素含量反演 3 冠层水分反演 4 数据可视化与导出 5 完整代码 6 运行结果 在生态学和环境科学领域&#xff0c;植被的健康状况是评估生态系统稳定性和功能的关键指标之一。而叶绿素含量和冠层水分含量作为反映植被生理状态的重要参数&#x…...