QT串口通讯上位机_数据超时接收功能及定时发送功能设计

news2024/11/22 16:55:20

目录

  • 1.概述
  • 2.本次内容最终实现
  • 3.代码部分
  • 4.完整工程文件下载

1.概述

基于《串口开发基础》
在该基础上增加超时时间接收功能,加入定时器循环;
例如,接收数据开始后,在100ms内未接收到任何数据,视作本次数据接收结束,立刻进入数据处理阶段。
同时,在定时器循环基础上增加数据定时发送功能。

2.本次内容最终实现

发送间隔小于超时时间,视为一条数据:

在这里插入图片描述
单次发送不受影响:

在这里插入图片描述
定时发送:定时器用的不是很精确的,误差有点大,功能倒是没问题
在这里插入图片描述

3.代码部分

Pro工程代码

QT       += core gui
QT       += serialport

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++11

# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    main.cpp \
    widget.cpp

HEADERS += \
    widget.h

FORMS += \
    widget.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

头文件 widget.h代码

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QDebug>
#include <QtSerialPort/QSerialPort>         // 提供访问串口的功能
#include <QtSerialPort/QSerialPortInfo>     // 提供系统中存在的串口信息



QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);

    void serial_recv_del();

    void this_timer_out();

    ~Widget();

private slots:
    void on_pushButton_2_clicked();

    void on_pushButton_clicked();

    void on_pushButton_4_clicked();

    void on_pushButton_5_clicked();

    void on_pushButton_3_clicked();

    void on_checkBox_2_stateChanged(int arg1);

private:
    Ui::Widget *ui;
};
#endif // WIDGET_H

cpp - widget.cpp代码

#include "widget.h"
#include "ui_widget.h"
#include<QDebug>
#include <QtSerialPort/QSerialPort>         // 提供访问串口的功能
#include <QtSerialPort/QSerialPortInfo>     // 提供系统中存在的串口信息
#include <QTimer>
#include "qmessagebox.h"


/*串口实例化*/
QSerialPort serial;
/*定时器实例化*/
QTimer timer;
/*串口接收数组*/
QByteArray serial_array;
/*接收数据总长度*/
static qint64 recv_data_len;
/*老的接收的串口数据长度*/
int old_serial_cnt;
/*接收数据长度相等后计数*/
static qint8 serial_recv_cnt = 0;
/*连续发送开关*/
static bool continusSend_sw = false;
/*连续发送定时器计数*/
static int continusSend_cnt = 0;


Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    /*开启按钮使能,禁用关闭按钮*/
    ui->pushButton_2->setDisabled(true);
    /*遍历COM口*/
    foreach (const QSerialPortInfo&info, QSerialPortInfo::availablePorts())
    {
        ui->comboBox->addItem(info.portName());
    }
    /*添加波特率*/
    ui->comboBox_2->addItem("9600", "9600");
    ui->comboBox_2->addItem("38400", "38400");
    ui->comboBox_2->addItem("115200", "115200");

    //连接这个定时器的信号和槽,利用定时器的timeout(),this_timer_out()槽函数
    connect(&timer, &QTimer::timeout, this, &Widget::this_timer_out);
    /*添加定时发送时间*/
    ui->comboBox_3->addItem("100", "100");
    ui->comboBox_3->addItem("200", "200");
    ui->comboBox_3->addItem("300", "300");
    ui->comboBox_3->addItem("400", "400");
    ui->comboBox_3->addItem("500", "500");
    ui->comboBox_3->addItem("600", "600");
    ui->comboBox_3->addItem("700", "700");
    ui->comboBox_3->addItem("800", "800");
    ui->comboBox_3->addItem("900", "900");
    ui->comboBox_3->addItem("1000", "1000");
    /*开启定时器ms*/
    timer.start(20);
}

Widget::~Widget()
{
    delete ui;
}

/*关闭串口按钮*/
void Widget::on_pushButton_2_clicked()
{
    serial.close();
    if(serial.isOpen())
    {
        QMessageBox::about(NULL, " 警告", "<font color='red'>串口关闭异常</font>");
    }
    else
    {
        ui->pushButton_2->setDisabled(true);
        ui->pushButton->setDisabled(false);
        ui->pushButton_2->setStyleSheet("QPushButton { background-color: white; }");
    }
}


/*串口接收处理函数*/
void Widget::serial_recv_del()
{
    serial_array += serial.readAll();
}


void Widget::on_pushButton_clicked()
{
    /*设置端口名称*/
    serial.setPortName(ui->comboBox->currentText());
    /*设置波特率*/
    serial.setBaudRate(ui->comboBox_2->currentText().toInt());
    /*打开串口*/
    serial.open(QIODevice::ReadWrite);
    /*串口打开成功*/
    if(serial.isOpen())
    {
        /*改变开启串口失能*/
        ui->pushButton_2->setDisabled(false);
        ui->pushButton->setDisabled(true);
        ui->pushButton_2->setStyleSheet("QPushButton { background-color: green; }");
        connect(&serial, &QSerialPort::readyRead, this, &Widget::serial_recv_del);
    }
    else
    {
         QMessageBox::about(NULL, " 警告", "<font color='red'>串口开启异常</font>");
    }
}

/*清除接收*/
void Widget::on_pushButton_4_clicked()
{
    ui->textBrowser->clear();
    /*清除接收数据长度*/
    ui->lineEdit->setText("0");
    recv_data_len = 0;
    serial_array.clear();
}

/*清除发送*/
void Widget::on_pushButton_5_clicked()
{
    ui->plainTextEdit->clear();
}

/*发送数据*/
void Widget::on_pushButton_3_clicked()
{
    if(ui->checkBox_2->isChecked()) //连续发送
    {
        continusSend_sw = true;
    }
    else //不连续发送
    {
        continusSend_sw = false;
        /*textBrowser中的数据放到qbyte中*/
        QByteArray array_send = ui->plainTextEdit->toPlainText().toUtf8();
        /*发送数据*/
        serial.write(array_send);
        /*若选中checkbox发送回车换行*/
        if(ui->checkBox->isChecked())
        {
            serial.write("\r\n");
        }
    }
}

/*定时器中断*/
void Widget::this_timer_out()
{
    /*接收数据*/
    if(serial_array.count() > 0) //接收到数据
    {
        if(old_serial_cnt == serial_array.count()) //判断是否接受到新数据
        {
            serial_recv_cnt++;
            if(serial_recv_cnt > 6) //数据接收完成
            {
                old_serial_cnt = 0;
                /*接收完成后清空*/
                serial_recv_cnt = 0;
                /*更新文本框*/
                recv_data_len += serial_array.count();
                ui->lineEdit->setText(QString::number(recv_data_len));
                ui->textBrowser->insertPlainText(serial_array);
                serial_array.clear();
            }
        }
        else
        {
            old_serial_cnt =  serial_array.count();
            serial_recv_cnt = 0;
        }
    }
    /*发送数据*/
    if(continusSend_sw)
    {
        continusSend_cnt += 20;
        if(continusSend_cnt >= ui->comboBox_3->currentText().toInt())
        {
            /*textBrowser中的数据放到qbyte中*/
            QByteArray array_send = ui->plainTextEdit->toPlainText().toUtf8();
            /*发送数据*/
            serial.write(array_send);
            /*若选中checkbox发送回车换行*/
            if(ui->checkBox->isChecked())
            {
                serial.write("\r\n");
            }
            /*clear*/
            continusSend_cnt = 0;
        }
    }
}

void Widget::on_checkBox_2_stateChanged(int arg1)
{
    if(arg1) //选中
    {

    }
    else  //未选中
    {
      continusSend_sw = false;
    }
}

4.完整工程文件下载

完整工程下载地址: 点击下载

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1457908.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据结构第3章 串

名人说&#xff1a;莫道桑榆晚&#xff0c;为霞尚满天。——刘禹锡&#xff08;刘梦得&#xff0c;诗豪&#xff09; 本篇笔记整理&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 0、思维导图1、基本概念1&#xff09;主…

Java+SpringBoot:农业疾病防治新选择

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…

NBlog个人博客部署维护过程记录 -- 后端springboot + 前端vue

项目是fork的Naccl大佬NBlog项目&#xff0c;页面做的相当漂亮&#xff0c;所以选择了这个。可以参考2.3的效果图 惭愧&#xff0c;工作两年了也没个自己的博客系统&#xff0c;趁着过年时间&#xff0c;开始搭建一下. NBlog原项目的github链接&#xff1a;Naccl/NBlog: &#…

leetcode(动态规划)53.最大子数组和(C++详细解释)DAY12

文章目录 1.题目示例提示 2.解答思路3.实现代码结果 4.总结 1.题目 给你一个整数数组 nums &#xff0c;请你找出一个具有最大和的连续子数组&#xff08;子数组最少包含一个元素&#xff09;&#xff0c;返回其最大和。 子数组 是数组中的一个连续部分。 示例 提示 2.解答思…

Sora一出 哪里又要裁员了?

上班前夕迎来大新闻&#xff0c;那就是Sora了&#xff0c;Sora是什么&#xff0c;有什么牛逼之处&#xff0c;怎么实现的&#xff0c;我们跟着官方文档透露出来的一点点信息&#xff0c;简单的捋一捋。 一、Sora是什么 官方给出的定义是&#xff1a;世界模拟器。这很明显有夸大…

数据结构:动态内存分配+内存分区+宏+结构体

一、作业 1.定义一个学生结构体&#xff0c;包含结构体成员&#xff1a;身高&#xff0c;姓名&#xff0c;成绩&#xff1b;定义一个结构体数组有7个成员&#xff0c;要求终端输入结构体成员的值&#xff0c;根据学生成绩&#xff0c;进行冒泡排序。 #include <stdio.h>…

Qt C++春晚刘谦魔术约瑟夫环问题的模拟程序

什么是约瑟夫环问题&#xff1f; 约瑟夫问题是个有名的问题&#xff1a;N个人围成一圈&#xff0c;从第一个开始报数&#xff0c;第M个将被杀掉&#xff0c;最后剩下一个&#xff0c;其余人都将被杀掉。例如N6&#xff0c;M5&#xff0c;被杀掉的顺序是&#xff1a;5&#xff…

如何利用Idea创建一个Servlet项目(新手向)

&#x1f495;"Echo"&#x1f495; 作者&#xff1a;Mylvzi 文章主要内容&#xff1a;如何利用Idea创建一个Servlet项目(新手向) Servlet是tomcat的api,利用Servlet进行webapp开发很方便,本文将介绍如何通过Idea创建一个Servlet项目(一共分为七步,这可能是我们写过的…

备战蓝桥杯---动态规划(应用1)

话不多说&#xff0c;直接看题&#xff1a; 首先我们考虑暴力&#xff0c;用二维前缀和即可&#xff0c;复杂度为o(n^4). 其实&#xff0c;我们不妨枚举任意2行&#xff0c;枚举以这个为边界的最大矩阵。 我们把其中的每一列前缀和维护出来&#xff0c;相当于把一个矩阵压缩成…

观察者模式和发布订阅模式的区别

从下图中可以看出&#xff0c;观察者模式中观察者和目标直接进行交互&#xff0c;而发布订阅模式中统一由调度中心进行处理&#xff0c;订阅者和发布者互不干扰。这样一方面实现了解耦&#xff0c;还有就是可以实现更细粒度的一些控制。比如发布者发布了很多消息&#xff0c;但…

【Vue3】搭建Pinia环境及其基本使用

下载 npm i pinia引入并注册 App.vue import { createApp } from vue import { createPinia } from pinia import App from ./App.vue // 1. 引入 import { createPinia } from piniaconst app createApp(App) // 2. 创建 const pinia createPinia() // 3. 注册 app.use(p…

python----面向对象

这里写目录标题 面向对象思想类类的定义类名的定义类的构造函数的定义类的属性类的方法定义 继承语法关于构造函数问题 文件操作绝对路径相对路径pycharm获取绝对路径和相对路径文件读写读文件open&#xff08;&#xff09;read&#xff08;&#xff09;readline&#xff08;&a…

2021年CSP-J认证 CCF信息学奥赛中小学初级组 第一轮真题-单项选择题解析

2021年 中小学信息学奥赛CSP-J真题解析 1、以下不属于面向对象程序设计语言的是 A、c B、python C、java D、c 答案&#xff1a;D 考点分析&#xff1a;主要考查编程语言&#xff0c;ABC都是面向对象语言&#xff0c;D选项c语言是面向过程语言&#xff0c;答案D 2、以下奖…

202427读书笔记|《猫的自信:治愈系生活哲学绘本》——吸猫指南书,感受猫咪的柔软慵懒与治愈

202427读书笔记|《猫的自信&#xff1a;治愈系生活哲学绘本》——吸猫指南书&#xff0c;感受猫咪的柔软慵懒与治愈 《猫的自信&#xff1a;治愈系生活哲学绘本》作者林行瑞&#xff0c;治愈系小漫画绘本&#xff0c;10分钟可以读完的一本书&#xff0c;线条明媚&#xff0c;自…

SQL注入工具之SQLmap入门操作

了解SQLmap 基础操作 SQLmap是一款自动化的SQL注入工具&#xff0c;可以用于检测和利用SQL注入漏洞。 以下是SQLmap的入门操作步骤&#xff1a; 1.下载SQLmap&#xff1a;可以从官方网站&#xff08;https://sqlmap.org/&#xff09;下载最新版本的SQLmap。 2.打开终端&#…

CDP和Chrome

CDP和Chrome CDP和WebDriver Protocol WebDriver和 Chrome DevTools Protocol&#xff08;CDP&#xff09; 是用于自动化浏览器的两个主要协议&#xff0c;大多数的浏览器自动化工具都是基于上述其中之一来实现的。可以通过这两种形式来和浏览器交互&#xff0c;通过代码来控…

使用maven集成spring在测试的时候报出了如下的异常:version 60

使用maven集成spring在测试的时候报出了如下的异常&#xff1a; Caused by: java.lang.IllegalArgumentException: Unsupported class file major version 60 解决&#xff1a;

MAC M1安装vmware和centos7虚拟机并配置静态ip

一、下载vmware和centos7镜像 1、VMWare Fusion 官网的下载地址是&#xff1a;下载地址 下载好之后注册需要秘钥&#xff0c;在官网注册后使用免费的个人秘钥 2、centos7 下载地址&#xff1a; https://biosyxh.cn:5001/sharing/pAlcCGNJf 二、虚拟机安装 直接将下…

比特币正在蚕食黄金

号外&#xff1a;教链内参2.19《内参&#xff1a;蹭热点、骗流量、割韭菜》 众所周知&#xff0c;自从美国SEC批准比特币现货ETF登陆美股市场之后&#xff0c;打开了美国金融市场泛滥的流动性向比特币流入的大门。只用了短短的30个交易日&#xff0c;比特币ETF就从零膨胀到了近…

基于RBAC的权限管理的理论实现和权限管理的实现

权限管理的理论 首先需要两个页面支持&#xff0c;分别是角色管理和员工管理&#xff0c;其中角色管理对应的是角色和权限的配合&#xff0c;员工管理则是将登录的员工账号和员工所处的角色进行对应&#xff0c;即通过新增角色这个概念&#xff0c;让权限和员工并不直接关联&a…