干货|手把手教你写一个串口调试助手「建议收藏」

干货|手把手教你写一个串口调试助手「建议收藏」摘要:前段时间发布了一个用QT写的串口调试助手,很多小伙伴在后台留言要源码。其实网上有很多免费开源的用QT的上位机,大家搜一下就能找到,为了大家方便学习QT以及如何写一个上位机,今天推荐一下学习资源,顺带带大家写一个非常简单的串口调试助手。相信很多小伙伴还没有接触过QT,如果想用QT写一个调试助手,首先是会一点C++语法。了解即可,也就是看得懂C++的代码。只要能看懂简单的C+++语法,就能很快的写一个串口调试助手。先推荐两个视频教程,感兴趣可以看看!1、B站Jomse工看完你基本知道串口调试助手

大家好,又见面了,我是你们的朋友全栈君。

摘要:前段时间发布了一个用QT写的串口调试助手,很多小伙伴在后台留言要源码。其实网上有很多免费开源的用QT的上位机,大家搜一下就能找到,为了大家方便学习QT以及如何写一个上位机,今天推荐一下学习资源,顺带带大家写一个非常简单的串口调试助手。

相信很多小伙伴还没有接触过QT,如果想用QT写一个调试助手,首先是会一点C++语法。了解即可,也就是看得懂C++的代码。只要能看懂简单的C+++语法,就能很快的写一个串口调试助手。

先推荐两个视频教程,感兴趣可以看看!

1、B站Jomse工

B站Jomse工

看完你基本知道串口调试助手大概是个啥样了,有了大致的了解然后再去看和修改别人的代码。

2、B站lililanglang

B站lililanglang

把这两个视频看完后,基本你就能够自己写一个串口调试助手了,视频很短没有废话,全程都是干货。而且别人也给出了源码。

为了大家方便理解,果子哥还是写一篇手把手教你学QT串口调试助手吧!

3、新建工程

1、首先你要安装QT的开发工具Qt Creator。安装过程我这里就不在重复说了,大家可以看我的CSDN博客号前面发的一些文章,有介绍的。

干货|手把手教你写一个串口调试助手「建议收藏」

打开QtCreator新建一个项目

干货|手把手教你写一个串口调试助手「建议收藏」

项目名称根据需求自己指定即可,在指定项目的存储路径的时候, 路径中不能包含中文, 不能包含中文, 不能包含中文

干货|手把手教你写一个串口调试助手「建议收藏」

直接写一步

干货|手把手教你写一个串口调试助手「建议收藏」

Class name可以随便写一个,一般默认不变

Base nameQMainWindowQWidgetQDialog随便选一个即可

干货|手把手教你写一个串口调试助手「建议收藏」

编译套件用于项目文件的编译, 如果安装了多个编译套件, 在这里选择其中一个就可以了

干货|手把手教你写一个串口调试助手「建议收藏」

版本控制工具没有的话可以不选,主要用于团队开发,点击完成

干货|手把手教你写一个串口调试助手「建议收藏」

这样我们就新建好了一个项目工程

干货|手把手教你写一个串口调试助手「建议收藏」

双击ui文件即可进入设计模式,进入界面设计器Qt Designer编辑状态,开始进行设计器( Qt Designer )编程。

干货|手把手教你写一个串口调试助手「建议收藏」

在这个界面我们可以拖动左边的常用界面的空间到编辑窗口,然后生成可视化的界面。

样式1

样式2

可以看到通过拖动控件与修改控件属性就可以做出上面这样的界面,我个人觉得还是非常的美观nice的。这里只是给大家一个参考的界面和模板,排版和配色大家按照自己喜欢的就可以了!

一、导入库

1、在项目.pro文件中加入serialport

QT       += core gui
QT       += serialport

2、引入qt中串口通信需要的头文件

#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>

二、配置串口初始化

1、查找可用的串口。

通过创建一个comobox,将可用串口的列表展示出来,并用于配置时选择要连接的串口

//查找可用串口,刷新串口信息
void MainWindow::GetAveriablePort()
{ 
   
     ui->uartReadPlain->insertPlainText("串口初始化:\r\n");
 
     //先清除所有串口列表
      ui->portBox->clear();
 
    foreach(const QSerialPortInfo &info,QSerialPortInfo::availablePorts())
    { 
   
        QSerialPort serial;
        serial.setPort(info);
 
        if(serial.open(QIODevice::ReadWrite))
        { 
   
            ui->uartReadPlain->insertPlainText("可用:"+serial.portName()+"\r\n");
            ui->portBox->addItem(serial.portName());
            serial.close();
        }
        else
        { 
   
            ui->uartReadPlain->insertPlainText("不可用:"+serial.portName()+"\r\n");
        }
    }
}

2、配置串口。

(1)串口的配置至少应当包含串口号、波特率、数据位、停止位、奇偶校验位、流控,这些都可以通过串口实例调用函数配置。可以加入几个comobox或者文本框来选择,也可以默认初始化时就配好。

//配置串口初始化
void MainWindow::PortConfigureInit()
{ 
   
    //填入串口选项
    ui->rateBox->addItem("115200","115200");
    ui->rateBox->addItem("38400","38400");
    ui->rateBox->addItem("19200","19200");
    ui->rateBox->addItem("9600","9600");
 
    ui->dataBox->addItem("8",8);
    ui->dataBox->addItem("7",7);
 
    ui->checkBox->addItem("无校验",0);
 
    ui->stopBox->addItem("1位",1);
    ui->stopBox->addItem("2位",2); 
}

(2)加入一个打开关闭串口的按钮,文本显示“打开串口”时,点击可以关闭串口。文本显示“关闭串口“则相反。

(3)打开串口时,把配置的项的box都disable,使其不可修改,关闭时恢复

//串口开关按钮
void MainWindow::on_openSerialButton_clicked()
{ 
   
    //尝试打开串口
    if(ui->openSerialButton->text() == tr("打开串口"))
    { 
   
        if(ui->portBox->currentText() == "" )
        { 
   
            QMessageBox::warning(NULL, "警告", "无可开启串口!\r\n\r\n");
            return;
        }
 
        serial = new QSerialPort;
        //设置串口名
        serial->setPortName(ui->portBox->currentText());
        //打开串口
        serial->open(QIODevice::ReadWrite);
        //设置波特率
        serial->setBaudRate(ui->rateBox->currentText().toInt());
        //设置数据位
        switch (ui->dataBox->currentData().toInt())
        { 
   
            case 8:
                serial->setDataBits(QSerialPort::Data8);
                break;
            case 7:
                serial->setDataBits(QSerialPort::Data7);
                break;
            default:
                break;
        }
        //设置校验位
        switch (ui->checkBox->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); //设置为无流控制
 
        //关闭设置菜单使能
        ui->portBox->setEnabled(false);
        ui->dataBox->setEnabled(false);
        ui->checkBox->setEnabled(false);
        ui->stopBox->setEnabled(false);
        ui->rateBox->setEnabled(false);
        ui->openSerialButton->setText("关闭串口");
 
        fTimeCounter.restart();  //计时器重新计数
 
        //连接信号和槽函数,串口有数据可读时,调用ReadData()函数读取数据并处理。
        QObject::connect(serial,&QSerialPort::readyRead,this,&MainWindow::ReadData);
    }
    else
    { 
   
        uartRecDataTimer->stop () ; //定时器停止
 
        if(serial->isOpen())       //原先串口打开,则关闭串口
        { 
   
            serial->close();
        }
 
        //释放串口
        delete serial;
        serial = NULL;
 
        //恢复使能
        ui->portBox->setEnabled(true);
        ui->rateBox->setEnabled(true);
        ui->dataBox->setEnabled(true);
        ui->checkBox->setEnabled(true);
        ui->stopBox->setEnabled(true);
        ui->openSerialButton->setText("打开串口");
    }
}

三、读取串口数据

1、为了读取数据,要创建一个定时器和一个计时器。因为要解决2个问题,一是我们需要一个超时间隔,用于在串口一定时间收不到数据时,判断一次接收完成,处理数据并清空buff。二是需要一个计数,统计串口已经连续接收了多久,即使数据一直不断,我们也要在一个固定时时间点强制判断一次接收完成,处理数据并清空buff,否则可能会导致数据永远得不到处理。

1、初始化定时器

    //设置uart接收缓冲超时定时器
    uartRecDataTimer = new QTimer(this);
    uartRecDataTimer->stop();
    uartRecDataTimer->setInterval(uartRecOvertimeCount*1000);                     //设置定时周期,单位:毫秒
    uartRecDataTimer->setSingleShot(true);                                        //设置为单次触发
    connect(uartRecDataTimer,SIGNAL(timeout()),this,SLOT(uartRec_timeout()));     //设置槽

2、实现ReadData

在计时器超出一个指定间隔后,强制处理已经接收完的buff缓冲,其余时间则是把数据放进缓冲中,重启定时器

//读取串口接收消息
void MainWindow::ReadData()
{ 
   
    //串口可读数据长度
    int byteLen = serial->bytesAvailable();
    if(byteLen < 0)
    { 
   
        return;
    }
 
    rec_buf_len += byteLen;
    uart_rec_ss.append(serial->readAll());  //读取数据
 
    //计时器超过最大间隔仍未填入数据,强制填入
    if(fTimeCounter.elapsed() >2000 && uart_rec_ss.size()>0)
    { 
   
        ui->uartReadPlain->moveCursor(QTextCursor::End);        //光标移动到结尾
        ui->uartReadPlain->insertPlainText(uart_rec_ss);
        ui->uartReadPlain->moveCursor(QTextCursor::End);        //光标移动到结尾
        uart_rec_ss.clear();
    }
 
    //定时器开始工作、定时器重启
    uartRecDataTimer->start();
}

3、数据内容做填充

定时器接收完成处理(一段时间没有数据接收,定时器超时)根据时间戳是否被选择,将数据内容做填充,插入到存放数据的文本框里。

//定时器触发打印串口数据
void MainWindow::uartRec_timeout()
{ 
   
    if(!uart_rec_ss.isEmpty())
    { 
   
        curDateTime = QDateTime::currentDateTime();
        ui->uartReadPlain->moveCursor(QTextCursor::End);            //光标移动到结尾
 
        if(ui->timeZoneCheckBox->isChecked())
        { 
   
            ui->uartReadPlain->insertPlainText("\r\n"+curDateTime.toString("[yyyy-MM-dd hh:mm:ss]")+"R:");
            ui->uartReadPlain->moveCursor(QTextCursor::End);        //光标移动到结尾
            ui->uartReadPlain->insertPlainText(uart_rec_ss);
        }
        else
        { 
   
            ui->uartReadPlain->insertPlainText(uart_rec_ss);
        }
        ui->uartReadPlain->moveCursor(QTextCursor::End);            //光标移动到结尾
        uart_rec_ss.clear();
        fTimeCounter.restart();
        ui->RXLenLabel->setText(QString::number(rec_buf_len)+"bytes");
    }
}

4、配置超时间隔的选项

(1)初始化时加入一个配置框

//设置时间输入框只允许使用数字
ui->overTimeRecEdit->setValidator(new QRegExpValidator(QRegExp("^([0-9]{1,4}(.[0-9]{1,3})?)$")));
ui->overTimeRecEdit->setText(QString::number(uartRecOvertimeCount));

(2)运行中配置超时间隔

//超时间隔设置
void MainWindow::on_overTimeRecEdit_returnPressed()
{ 
   
    if(ui->overTimeRecEdit->text().toFloat()>60)
    { 
   
        QMessageBox::warning(NULL,"警告","超时时间不要超过1分钟");
        ui->overTimeRecEdit->setText("0.1");
        return;
    }
    uartRecOvertimeCount = ui->overTimeRecEdit->text().toFloat();
    ui->uartReadPlain->insertPlainText("设置超时时间为:"+QString::number(uartRecOvertimeCount*1000)+"ms");
    uartRecDataTimer->setInterval(uartRecOvertimeCount*1000);                       //设置定时周期,单位:毫秒
 
    fTimeCounter.restart();
    uartRecDataTimer->start();
}

四、发送数据

简单的发送数据没有什么要额外配置的,调用write函数就可以了,可以根据自己的实际情况做一些配置或是校验处理。比如加回车换行什么的

//发送串口数据
void MainWindow::on_sendDataButton_clicked()
{ 
   
    //未打开串口则不准发送
    if(ui->openSerialButton->text() == "打开串口")
    { 
   
        QMessageBox::warning(NULL, "警告", "未打开可用串口,无法发送数据!\r\n\r\n");
        return;
    } 
    //获取发送的命令,并选择在结尾加上换行,AT的命令结尾必须有回车换行
    QString command = ui->uartWritePlain->toPlainText();
    if(ui->changeLineCheckBox->isChecked())
    { 
   
        command += "\r\n";
    } 
    if(ui->timeZoneCheckBox->isChecked())
    { 
   
         curDateTime = QDateTime::currentDateTime();
         ui->uartReadPlain->insertPlainText("\r\n"+curDateTime.toString("[yyyy-MM-dd hh:mm:ss]")+"SEND:"+command);
    } 
    send_buf_len += command.length();
    ui->TXLenLabel->setText(QString::number(send_buf_len)+"bytes"); 
    serial->write(command.toLatin1());
}

至此,一个最基本的串口调试工具就完成了,下面就是给它添加功能和优化了。你可以加入一些功能比如修改样式、保存数据等等。

开源代码

最后想说的是用QT写上位机的源码例程很多,初学者可以先借鉴别人的代码参考修改,按照自己的喜好以及编程风格进行排版和布局配色即可!

公众号后台回复:Qcom,即可获取串口调试助手源码。

干货|手把手教你写一个串口调试助手「建议收藏」
干货|手把手教你写一个串口调试助手「建议收藏」

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/141055.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 手把手教你使用YOLOV5训练自己的目标检测模型-口罩检测-视频教程

    手把手教你使用YOLOV5训练自己的目标检测模型大家好,这里是肆十二(dejahu),好几个月没有更新了,这两天看了一下关注量,突然多了1k多个朋友关注,想必都是大作业系列教程来的小伙伴。既然有这么多朋友关注这个大作业系列,并且也差不多到了毕设开题和大作业提交的时间了,那我直接就是一波更新。这期的内容相对于上期的果蔬分类和垃圾识别无论是在内容还是新意上我们都进行了船新的升级,我们这次要使用YOLOV5来训练一个口罩检测模型,比较契合当下的疫情,并且目标检测涉及到的知识点也比较多,这次的内容除了可以作为大家

  • 解决smplayer中文字幕乱码

    解决smplayer中文字幕乱码首先,打开选项->首选项:选择字幕选项卡。找到“默认字符编码”选项,在下拉框中选择“简体中文(cp936)”再打开“字体和颜色”页卡(上边),选择“系统字体”在下拉选框中选择一种简体中文字体转载于:https://www.cnblogs.com/hbxtght/archive/2011/05/18/2049938.html…

  • stm32f103电机控制_proteus仿真直流电机的控制

    stm32f103电机控制_proteus仿真直流电机的控制一、引言电动机作为当前最主要的驱动部件,应用范围已遍及国民经济的各个领域,随着微处理器、电力电子、控制等技术的发展,电机控制技术以电力半导体变流器件的应用为基础,以电动机为控制对象,以自动控制理论为指导,以电子技术和微处理器技术以及计算机辅助技术为手段,结合检测技术和数据通信技术相结合,实现数字化回路的电机控制成为可能。直流电动机以其调速性能好、起动转矩大等优点,在相当长的一段时间内,在电动机调速领域占据着很重要的位置。项目训练电机控制的主控芯片采用意法半导体公司生产的32位微控制器STM32F10

    2022年10月15日
  • java中级项目案例_60个Java练手项目案例,看了让你茅塞顿开~

    java中级项目案例_60个Java练手项目案例,看了让你茅塞顿开~给大家推荐一条由浅入深的JAVA学习路径,首先完成Java基础、JDK、JDBC、正则表达式等基础实验,然后进阶到J2SE和SSH框架学习。最后再通过有趣的练手项目进行巩固。JAVA基础Java编程语言(新版)2.Java进阶之设计模式3.JDK核心API4.MySQL基础课程5.正则表达式基础6.JDBC入门教程J2SE&SSH框架7.Java函数式编…

  • 集群技术概述_集群计算机

    集群技术概述_集群计算机集群技术概述一、集群的起源二、集群的优点1.强扩展能力2.实现方式容易3.高可用性4.易管理性三、集群的类型1.负载均衡集群2.高可用性集群3.高性能集群四、集群的特点1.心跳监测2.漂移IP地址五、集群的应用1.石油地震数据处理2.数值天气预报一、集群的起源        集群并不是一个全新的概念,其实早在七十年代计算机厂商和研究机构就开始了对集群系统的研究和开发。由于主要用于科学工程计算,所以这些系统并不为大家所熟知。直

  • AngularJS简介

    AngularJS简介AngularJS简介AngularJS是一个JavaScript矿建,他是一个JavaSscript编写的库。可以通过&lt;script&gt;标签添加到HTML页面。AngularJS是通过指令扩展了HTML,且通过表达式绑定数据到HTML。地址:&lt;scriptsrc="http://apps.bdimg.com/libs/angular.js/1.4.6/angul…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号