Qt串口助手的设计(有bug不完整)

 参考up主:社长_嵌入式

Day1 界面的完成

一:学到的重点

1 this->setLayout(ui->gridLayoutGlobal);

使ui界面里面的内容全部有伸缩性

2 QList <QSerialPortInfo> serial=QSerialPortInfo::availablePorts();

得到串口列表存储到QList列表里面存放QSerialInfo类型

 //设置串口名称
    //得到串口列表存储到QList列表里面存放QSerialInfo类型
    QList <QSerialPortInfo> serial=QSerialPortInfo::availablePorts();
    for(QSerialPortInfo serial_info :serial){
        qDebug()<<serial_info.portName();
        //设置名称
        ui->comboBox_6->addItem(serial_info.portName());
    }

3 QString byte=ui->textEditRec->toPlainText();

QString byte = ui->textEditRec->toPlainText(); 这行代码的作用是获取 ui->textEditRec(一个 QTextEdit 类型的控件)中显示的纯文本内容,并将其存储到一个 QString 类型的变量 byte 中。

得到textEidt里面的字节

QString text = ui->textEditRec->toPlainText();
QByteArray byteArray = text.toLocal8Bit();
int byteCount = byteArray.size();

4 Strcmp函数

strcmp是 C 语言中的一个标准库函数,用于比较两个字符串的大小关系,其函数原型为int strcmp(const char *s1, const char *s2);,具体作用及返回值情况如下:

  • 如果str1str2相等,函数返回 0。例如,strcmp("hello", "hello")的返回值为 0。
  • 如果str1大于str2,函数返回一个大于 0 的整数。这里的 “大于” 是指在字典序(按照字符的 ASCII 码值顺序)中str1排在str2后面。比如strcmp("hello", "apple"),因为 'h' 的 ASCII 码值大于 'a' 的 ASCII 码值,所以返回值大于 0。
  • 如果str1小于str2,函数返回一个小于 0 的整数。例如strcmp("apple", "banana"),由于 'a' 的 ASCII 码值小于 'b' 的 ASCII 码值,所以返回值小于 0。

4 QStringList historyList

historyList.contains(cStr)判断列表里面是否含有cStr字符串 含有返回一 可以利用该发送解决历史记录去重问题

    // 检查历史记录中是否已经存在该字符串
    if (!historyList.contains(sendStr)) {
        historyList.append(sendStr);
        ui->textEditRecord->append(sendStr);
    }

5 除了ui的方式第二种找到ui界面上的控件的名称

QString btnName=QString("pushButton_%1").arg(i);

QPushButton * btn =findChild<QPushButton*>(btnName);

6 btn->setProperty("buttonId",i);

给btn设置序号

7 int num=btn->property("buttonId").toInt();

得到点击的第几个按钮从而获取对应的第几个LineEdit

二:完成界面设计:

改善界面并把得到的串口显示到界面上

 //设置串口名称
    //得到串口列表存储到QList列表里面存放QSerialInfo类型
    QList <QSerialPortInfo> serial=QSerialPortInfo::availablePorts();
    for(QSerialPortInfo serial_info :serial){
        qDebug()<<serial_info.portName();
        //设置名称
        ui->comboBox_6->addItem(serial_info.portName());
    }

三 配置串口

1 配置串口的参数

// 配置串口的通用函数
void Widget::configureSerialPort(QSerialPort *port)
{
    // 配置波特率
    port->setBaudRate(ui->comboBox_5->currentText().toInt());
    // 配置数据位
    port->setDataBits(QSerialPort::DataBits(ui->comboBox->currentText().toInt()));
    // 配置校验位
    switch (ui->comboBox_2->currentIndex()) {
    case 0:
        port->setParity(QSerialPort::NoParity);
        break;
    case 1:
        port->setParity(QSerialPort::EvenParity);
        break;
    case 2:
        port->setParity(QSerialPort::MarkParity);
        break;
    case 3:
        port->setParity(QSerialPort::OddParity);
        break;
    case 4:
        port->setParity(QSerialPort::SpaceParity);
        break;
    case 5:
        port->setParity(QSerialPort::UnknownParity);
        break;
    }

    // 配置停止位
    QString stopBitsText = ui->comboBox_3->currentText();
    if (stopBitsText == "One") {
        port->setStopBits(QSerialPort::OneStop);
    } else if (stopBitsText == "OneAndHalf") {
        port->setStopBits(QSerialPort::OneAndHalfStop);
    } else if (stopBitsText == "Two") {
        port->setStopBits(QSerialPort::TwoStop);
    } else {
        port->setStopBits(QSerialPort::OneStop);  // 默认值
    }
    // 流控
    QString flowControl = ui->comboBox_4->currentText();
    if (flowControl == "No") {
        port->setFlowControl(QSerialPort::NoFlowControl);
    } else if (flowControl == "Soft") {
        port->setFlowControl(QSerialPort::SoftwareControl);
    } else if (flowControl == "Hard") {
        port->setFlowControl(QSerialPort::HardwareControl);
    }
}

2 完善打开串口的功能

这里需要创建俩个串口一个发送一个接收 一个串口不行

// 打开串口按钮
void Widget::on_pushButton_12_clicked()
{
    // 配置串口1
    serialPort1->setPortName(ui->comboBox_6->currentText());
    configureSerialPort(serialPort1);

    // 配置串口2,假设你手动选择另一个串口
    // 这里简单假设你选择的是列表中的下一个串口,如果列表只有一个串口会有问题,实际使用时需要处理这种情况
    int nextIndex = (ui->comboBox_6->currentIndex() + 1) % ui->comboBox_6->count();
    serialPort2->setPortName(ui->comboBox_6->itemText(nextIndex));
    configureSerialPort(serialPort2);

    // 打开串口1
    if(serialPort1->open(QIODevice::ReadWrite))
    {
        serialPort1->setDataTerminalReady(true);
        qDebug() << "Serial port 1 opened successfully and DTR set to true";
    }
    else
    {
        qDebug() << "Failed to open serial port 1:" << serialPort1->errorString();
    }

    // 打开串口2
    if(serialPort2->open(QIODevice::ReadWrite))
    {
        serialPort2->setDataTerminalReady(true);
        qDebug() << "Serial port 2 opened successfully and DTR set to true";
    }
    else
    {
        qDebug() << "Failed to open serial port 2:" << serialPort2->errorString();
    }
}

3 完善发送的功能

当点击发送的时候进行发送数据 qint64 bytesWritten1 = serialPort1->write(cStr);写入的时候自动发送

&QSerialPort::readyRead信号

// 发送按钮
void Widget::on_pushButton_sent_clicked()
{
    if (!serialPort1->isOpen() || !serialPort2->isOpen()) {
        qDebug() << "串口未全部打开";
        return;
    }
    std::string str = ui->lineEdit_9->text().toStdString();
    const char* cStr = str.c_str();
    qDebug() << cStr;

    // 向串口1发送数据
    qint64 bytesWritten1 = serialPort1->write(cStr);
    if (bytesWritten1 == -1) {
        qDebug() << "写入串口1失败";
    } else {
        qDebug() << "成功向串口1写入" << bytesWritten1 << "字节";
    }

    // 向串口2发送数据
    qint64 bytesWritten2 = serialPort2->write(cStr);
    
//    if (bytesWritten2 == -1) {
//        qDebug() << "写入串口2失败";
//    } else {
//        qDebug() << "成功向串口2写入" << bytesWritten2 << "字节";
//    }
}

4 进行连接

qint64 bytesWritten1 = serialPort1->write(cStr);写入的时候自动发送&QSerialPort::readyRead信号

 connect(serialPort1, &QSerialPort::readyRead, this, &Widget::on_receive1);

on_receive1函数

void Widget::on_receive1()
{
    qDebug() << "Entering on_receive1 function";
    if (serialPort1->bytesAvailable() > 0) {
        qDebug() << "Bytes available on serialPort1:" << serialPort1->bytesAvailable();
        QString str = serialPort1->readAll();
        qDebug() << "Received data on serialPort1:" << str;
        // 追加数据到 textEditRec 中
        ui->textEditRec->append(str);
    } else {
        qDebug() << "No data available on serialPort1";
    }
}

5 发送的结果

6 历史记录去重

7 界面优化

实现打开串口都时候串口配置不可以选择 关闭串口的时候才可以选择

打开串口

rec_serial是一个标志位默认为假 第一次打开按钮的时候进入if语句设置rec_serial为true第二次点击按钮进入else语句中

关闭串口

7 定时器实现定时发送

头文件中定义定时器

//定义定时器来完成定时发送    
QTimer *timer;

widget构造函数中初始化定时器

    //初始化定时器
    timer=new QTimer(this);
    connect(timer,&QTimer::timeout,[=](){
        //开始发送
        on_pushButton_sent_clicked();

    });

给定时发送按钮设置信号和槽点击为true 在点击为false

void Widget::on_checkBox_13_clicked(bool checked)
{
    if(checked){
        //开启定时器
        timer->start(ui->lineEdit_10->text().toInt());
        //发送,发送内容按钮设置为假
        ui->pushButton_sent->setEnabled(false);
        ui->lineEdit_9->setEnabled(false);
    }
    else{
        //关闭定时器
        timer->stop();
        //发送,发送内容按钮设置为真
        ui->pushButton_sent->setEnabled(true);
        ui->lineEdit_9->setEnabled(true);
    }
}

8 保存接收


void Widget::on_pushButton_14_clicked()
{
    QString FileName=QFileDialog::getSaveFileName(this,"Save File","C:\\Users\\50192\\Desktop","Text (*.txt)");
    if(FileName!=nullptr){
        //打开文件
        QFile File(FileName);
        if(!File.open(QIODevice::WriteOnly|QIODevice::Text)){
            return;
        }
        else{
            QTextStream out(&File);
            //写入数据到文件中
            out<<ui->textEditRec->toPlainText();
        }

    }
}

9 显示时间功能

在状态栏下显示时间

    //状态栏设置当前时间
    QTimer *myTimer=new QTimer(this);
    //一秒刷新一下正好对应时间
    myTimer->start(1000);
    connect(myTimer,&QTimer::timeout,[=](){
        QDateTime currentTime=QDateTime::currentDateTime();
        time=currentTime.toString("yyyy-MM-dd hh:mm:ss");
        ui->label_15->setText(time);

    });

点击显示时间接收方接收数据显示时间

//文本框显示时间
void Widget::on_checkBox_10_clicked(bool checked)
{
        flag=checked;
}
// 追加数据到 textEditRec 中
//flag为真显示时间
if(flag){
   ui->textEditRec->append(time+" "+str);
}
        //flag为假不显示时间
 else {
    ui->textEditRec->append(str);
}

10 hex显示

//hex(16进制)显示
void Widget::on_checkBox_11_clicked(bool checked)
{
    if(checked){


    //读取textEdit的内容
    QString tmp=ui->textEditRec->toPlainText();
    //把QString转化为字节
    QByteArray qtemp=tmp.toUtf8();
    //字节转化为hex
    qtemp=qtemp.toHex();
    //把hex转化为QString
    ui->textEditRec->setText(QString::fromUtf8(qtemp));
    }
    else{
        //读取textEdit的内容
        QString tmp=ui->textEditRec->toPlainText();
         //把QString转换为字节
        QByteArray qtemp=tmp.toUtf8();
        //fromHex() 是 QByteArray 类的一个静态函数,其作用是将十六进制编码的字符串转换为对应的二进制数据
        qtemp=QByteArray::fromHex(qtemp);
        ui->textEditRec->setText(QString::fromUtf8(qtemp));

    }
}

11 改善hex显示当定时发送的时候转换为hex

void Widget::on_receive1()
{
    if (serialPort1->bytesAvailable() > 0) {

        QString str = serialPort1->readAll();
        if(ui->checkBox_11->isChecked()){
            //读取以前的内容
            QString tep=ui->textEditRec->toPlainText();
            //读取新的内容转换为16进制
            QByteArray byt=str.toUtf8().toHex();
            byt=tep.toUtf8()+byt;
            ui->textEditRec->setText(QString::fromUtf8(byt));
        }
        else{

            // 追加数据到 textEditRec 中
            //flag为真显示时间
            if(flag){
                ui->textEditRec->append(time+" "+str);
            }
            //flag为假不显示时间
            else {
                ui->textEditRec->append(str);
            }

            rec_by=rec_by+str.size();

            ui->label_13->setText("Receive:"+QString::number(rec_by));


        }
    }
    else {
        qDebug() << "No data available on serialPort1";
    }
}

12 发送的时候点击hex发送

hex_flag是判断是否加入历史记录里面

  //判断hex是否选中
    if(ui->checkBox_15->isChecked()){
        hex_flag=false;
        QString tmp=ui->lineEdit_9->text();
        QByteArray tmpArray=tmp.toUtf8();
        //判断是否为偶数
        if(tmpArray.size()%2!=0){
            hex_flag=true;
            ui->label_12->setText("Send: Error");
            return;
        }
        //判断是否为16进制
        for(char c : tmpArray){
            //std::isdigit(c)判断是否符合16进制
            if(!std::isdigit(c)){
                hex_flag=true;
                ui->label_12->setText("Send: Error");
                return;
            }

        }

        //转换为16进制
       tmpArray=QByteArray::fromHex(tmpArray);
       bytesWritten1 = serialPort1->write(tmpArray);
    }

13 优化hex显示

转化的数据要有间隔 并要大写

tmp.mid(i,2)+“ ” 从第i个开始读取2个并在后面加个空格

BUG:hex发送的数据在点击hex显示转化为ASCII码了

14 换行功能的实现

// insertPlainText 发送的时候不进行换行

ui->textEditRec->insertPlainText(time + " " + str);

void Widget::on_receive1()
{
    if (serialPort1->bytesAvailable() > 0) {
        QByteArray data = serialPort1->readAll();

        // 自动换行
        if(ui->checkBox_12->isChecked()){
            data.append("\r\n");
        }
        if( rn_flag){
            data.append("\r\n");
        }
        //hex显示 每俩个字符之间加俩个空格
        if(ui->checkBox_11->isChecked()){
            // 读取以前的内容
            QString prevText = ui->textEditRec->toPlainText();
            // 读取新的内容转换为16进制
            QByteArray hexData = data.toHex().toUpper();

            // 格式化十六进制数据,每两个字符加一个空格
            QString formattedHex;
            for (int i = 0; i < hexData.size(); i += 2) {
                formattedHex += hexData.mid(i, 2) + " ";
            }

            // 拼接旧内容和新的十六进制内容
            QString newText = prevText + formattedHex;
            ui->textEditRec->setText(newText);
        }
        //一般显示的时候
        else {
            QString str = QString::fromUtf8(data);
            // flag为真显示时间
            if(flag){
                // insertPlainText 发送的时候不进行换行
                ui->textEditRec->insertPlainText(time + " " + str);
            }
            // flag为假不显示时间
            else {
                ui->textEditRec->insertPlainText(str);
            }

            rec_by = rec_by + str.size();
            ui->label_13->setText("Receive:" + QString::number(rec_by));
        }
    }
    else {
        qDebug() << "No data available on serialPort1";
    }
}

15 隐藏面板,历史

才有伸缩性

才会出现俩种点击状态

//隐藏面板
void Widget::on_pushButton_16_clicked(bool checked)
{
    if(checked){
       
        ui->pushButton_16->setText("打开面板");
        ui->groupBoxText->hide();

    }
    else{
       
        ui->pushButton_16->setText("隐藏面板");
        ui->groupBoxText->show();
    }
}

//隐藏历史
void Widget::on_pushButton_18_clicked(bool checked)
{
    if(checked){
      
        ui->pushButton_18->setText("打开历史");
        ui->groupBoxrecord->hide();

    }
    else{
        
        ui->pushButton_18->setText("隐藏历史");
        ui->groupBoxrecord->show();
    }
}

16 自定义控件实现串口的刷新

完善文件

完善代码

交给父类处理很重要 如果没有将会丢了原有的功能

连接

完成槽函数

17 实现多文本功能(多个按钮共同实现功能)

    //完成多文本功能
    //创建list列表存储QPushButton*的数据
    QList <QPushButton *> buttons;
    for(int i=1;i<=9;i++){
        QString btnName=QString("pushButton_%1").arg(i);
        //除了ui的方式第二种找到ui界面上的控件的名称
        QPushButton * btn =findChild<QPushButton*>(btnName);
        if(btn){
            //给btn设置序号
            btn->setProperty("buttonId",i);
            //添加到QList列表中
            buttons.append(btn);
            //连接信号和槽
            connect(btn,&QPushButton::clicked,this,&Widget::on_Many_Text);
        }

    }
void Widget::on_Many_Text()
{
    //找到那个控件发送了信号
    QPushButton*btn=qobject_cast<QPushButton*>(sender());
    if(btn){
        //得到点击的第几个按钮从而获取对应的第几个LineEdit
        int num=btn->property("buttonId").toInt();
        QString lineName=QString("lineEdit_%1").arg(num);
         //找到ui界面上的控件
        QLineEdit *lineEdit=findChild<QLineEdit*>(lineName);
        if(lineEdit){
            //多文本写入的内容发送时候对应的LineEdit内容
            ui->lineEdit_9->setText(lineEdit->text());
        }
         //得到点击的第几个按钮从而获取对应的第几个checkBoxName
        QString checkBoxName=QString("checkBox_%1").arg(num);
        //找到ui界面对应的控件
        QCheckBox *checkBox=findChild<QCheckBox*>(checkBoxName);
        if(checkBox){
            //如果checkBox->isChecked()true则hex发送也为true
            ui->checkBox_15->setChecked(checkBox->isChecked());
        }
        //调用发送按钮
        on_pushButton_sent_clicked();

    }
}

18 初步实现循环发送

有缺点循环的时候不能点击其他事件页面会卡

//初步循环发送
void Widget::on_checkBox_9_clicked(bool checked)
{
    if(checked){
        for(int i=0;i<this->buttons.size()-1;i++){
            QPushButton *btn=buttons[i];
            //发送点击信号
            emit btn->clicked();
            //延迟发送
            QThread::msleep(ui->spinBox->value());
        }
    }
}

19 定时器实现循环发送

//初始化循环定时器
    cycle_timer=new QTimer(this);
    //连接
    connect(cycle_timer,&QTimer::timeout,this,&Widget::button_handler);

//循环发送函数
void Widget::button_handler()
{
    //不能用for循环 如果for循环一次性输出全部
    if(cycle_index<buttons.size()){
        QPushButton *btn=buttons[cycle_index];
        //发送点击信号
        emit btn->clicked();
        cycle_index=cycle_index+1;

    }
    else{
        cycle_index=0;
    }


}

//初步循环发送
void Widget::on_checkBox_9_clicked(bool checked)
{
    if(checked){
        //启动定时器
        cycle_timer->start(ui->spinBox->value());

    }
    else{
        //关闭定时器
        cycle_timer->stop();
    }
}

20 多线程实现循环发送

21 重置

//重置按钮实现
void Widget::on_pushButton_re_clicked()
{

    QMessageBox mesBox;
    //设置窗口名
    mesBox.setWindowTitle("提示 ");
    //设置图标
    mesBox.setIcon(QMessageBox::Question);
    //设置提示的内容
    mesBox.setText("重置列表不可逆,确认是否重置? ");
    //设置按钮 yes和no
    QPushButton *yesBtn=mesBox.addButton("Y是Y",QMessageBox::YesRole);
    QPushButton *noBtn=mesBox.addButton("N否N",QMessageBox::NoRole);
    //显示窗口进行阻塞
    mesBox.exec();

    if(mesBox.clickedButton()==yesBtn){
    for(int i=0;i<lineEdits.size();i++){
        //清空数据
        lineEdits[i]->clear();
        //取消打勾
        checkBoxs[i]->setChecked(false);
    }
}
    if(mesBox.clickedButton()==noBtn)
    {

    }
}

21 多文本保存和载入

//保存按钮
void Widget::on_pushButton_save_clicked()
{
    QString FileName=QFileDialog::getSaveFileName(this,"Save File","C:\\Users\\50192\\Desktop","Text(*.txt)");
    QFile File(FileName);
    if(!File.open(QIODevice::WriteOnly|QIODevice::Text)){
        return;
    }
    else{
        QTextStream out(&File);
        for(int i=0;i<8;i++){
            out<<checkBoxs[i]->isChecked()<<","<<lineEdits[i]->text()<<"\n";
        }
    }

}

//载入按钮
void Widget::on_pushButton_zai_clicked()
{
    int i=0;
    QString FileName=QFileDialog::getOpenFileName(this,"Open File","C:\\Users\\50192\\Desktop","Text(*.txt)");
    QFile file(FileName);
    if(!file.open(QIODevice::ReadOnly|QIODevice::Text)){
        return;
    }
    else{
        QTextStream in(&file);
        while(!in.atEnd()&&i<8){
            QString line=in.readLine();
            QStringList strList=line.split(",");
            if(strList.count()==2){
                checkBoxs[i]->setChecked(strList.at(0).toInt());
                lineEdits[i]->setText(strList.at(1));
                i++;
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值