QT 篇 QT上位机串口编程

QT应用篇

一、QT上位机串口编程
二、QML用Image组件实现Progress Bar 的效果
三、QML自定义显示SpinBox的加减按键图片及显示值效果
四、window编译LibModbus库并用QT编写一个Modbus主机
五、手把手教学用QT编写TCP上位机并显示温湿度


QT 篇 一、QT上位机串口编程

最近因为项目需要,需要用到上位机,通过串口与上位机进行通讯,来上传和下发一些数据以及控制指令,所以用QT写了一个上位机,并记录下来,免得到时候要用又到处翻资料。

QT版本:QT Creater 4.80
硬件:stm32 + 串口转ttl模块

2023-12-28 更新
可以通过安装虚拟串口来模拟串口通信的情况

软件: Virtual Serial Port Driver 7.2
可以生成虚拟串口 无需实际硬件串口就可以实现同一台电脑上串口模拟通信 方便调试串口助手

链接:https://pan.baidu.com/s/1GuQ8UoojWZk-YjsnDhqurg?pwd=2023
提取码:2023

–来自百度网盘超级会员V5的分享

安装好了之后打开

虚拟串口软件界面

点击Add pair
生成虚拟串口
生成一对虚拟串口 COM1 和COM2
生成结果
虚拟串口测试

虚拟串口测试
后续可以使用虚拟串口来调试,这样就不需要ch430来才能调试了

默认安装好QT了

1.新建工程

选择Qt Widgets

然后下一步
新建工程
自己填一个项目名字和项目路径
命名
我只安装了这一个,我就选了这个
选择编译器

这里主要是一些基类的选择
这里我选择QMainWindow

类名,文件名什么的,你们看看要不要改名

类信息
项目管理这里版本控制选择无
版本管理
然后就完成了创建了

2.添加类和库文件

QT5自带有串口的封装库 QSerialPort ,我们要用的相关的函数,所以要在.pro文件里面添加一样代码,在QT += core gui的基础上添加serialport

QT       += core gui serialport

在mainwindo.h里添加串口的一些库

#include <QSerialPort>			//访问串口的库
#include <QSerialPortInfo>		//查询串口信息的库
#include <QDebug>				//用于调试打印输出的库
#include <QTimer>				//定时器的库
#include <QTime>				//时间的库
#include <QDate>				//日期的库
#include <QMessageBox>			//一个小的弹窗库

其实上面这些这需要添加最顶上的了两个就够了,其余的是我有其他的用处就加了进去

3.设计上位机页面

这是我自己设计好的上位机

在这里插入图片描述
布局上参考了一下正点原子的XCOM串口软件

在这里插入图片描述

上位机页面
先设置好窗口的大小固定位800x480
窗口最大和最小都是800x480 这样一来就没办法拉伸了,就不会影响美观

设置窗口大小
然后可以按照我的设计页面来摆放一些控件

当然你们也可以不用这么多控件,因为实际上来说,需要修改的串口参数其实就只有名称和波特率而已,其余的是可以固定不做改变的

看需求

对象的名称最好改一下,不然到时候编写代码的时候你会不记得哪个代表哪一个部件,我的部件的名称

请添加图片描述
对象名称
在这里插入图片描述
摆放好这些部件后
分别添加波特率
停止位
数据位
奇偶校验等等

在这里插入图片描述
然后设置Combox的初始值

我把串口的波特率设置为115200是初始值
其余的你们看着来
CurrentIndex的索引和数组一样,从0开始
在这里插入图片描述

4.添加函数 扫描串口和初始化串口设置

在mainwindow.h里的
private:

    //定时器
    QTimer *timer;
    // 串口对象
    QSerialPort *serialport;
    //扫描串口
    void scanSerialPort();
    //初始化
    void serialPortInit();

public

    int btn_on_off = 0;

    int btn_state = 0;

mainwindow.cpp文件


MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
	//对象实例化
    serialport = new QSerialPort(this);
	
    timer = new QTimer(this);
	
    scanSerialPort();

}

void MainWindow::scanSerialPort()
{
	//查询可用的串口信息
    foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
    {
        {
        	//添加串口到下拉菜单
             ui->cbx_setPortName->addItem(info.portName());
        }
        qDebug()<<"已发现串口:"<<ui->cbx_setPortName->currentText();
    }
}



void MainWindow::serialPortInit()
{
    //设置串口名称
    serialport->setPortName(ui->cbx_setPortName->currentText());
   qDebug()<<"串口名称:"<<serialport->portName();

   if (!serialport->open(QIODevice::ReadWrite))
   {
		qDebug()<<"错误,串口无法打开,可能被占用!";
		QMessageBox::about(this,"错误","串口无法打开,可能被占用!");
		serialport->close();
		return ;
   }

    //波特率
    serialport->setBaudRate(ui->cbx_setBaudRate->currentText().toInt());
    qDebug()<<"波特率:"<<ui->cbx_setBaudRate->currentText().toInt();
    //停止位
    switch (ui->cbx_setStopBits->currentText().toInt())
    {
    case 1 :  serialport->setStopBits(QSerialPort::OneStop); break;
    case 2 :  serialport->setStopBits(QSerialPort::TwoStop); break;
        default: break;
    }
    qDebug()<<"停止位:"<<serialport->stopBits();
    //数据位
    switch (ui->cbx_setDataBits->currentText().toInt())
    {
    case 5 :  serialport->setDataBits(QSerialPort::Data5); break;
    case 6 :  serialport->setDataBits(QSerialPort::Data6); break;
    case 7 :  serialport->setDataBits(QSerialPort::Data7); break;
    case 8 :  serialport->setDataBits(QSerialPort::Data8); break;
        default: break;
    }
    //奇偶位
     switch (ui->cbx_setParity->currentIndex())
    {
    case 0 :  serialport->setParity(QSerialPort::NoParity); break;
    case 1 :  serialport->setParity(QSerialPort::OddParity); break;
    case 2 :  serialport->setParity(QSerialPort::EvenParity); break;
        default: break;
    }
    qDebug()<<"奇偶位:"<<serialport->parity();

    serialport->setFlowControl(QSerialPort::NoFlowControl) ;


}

然后打开ui文件

找到打开串口这个PushButton

转到槽函数

就会自动帮你生成信号函数和槽函数

请添加图片描述
打开串口的槽函数

void MainWindow::on_btn_open_close_clicked()
{
         if (btn_on_off == 0)
         {

             ui->cbx_setPortName->setEnabled(false);
             ui->cbx_setBaudRate->setEnabled(false);
             ui->cbx_setDataBits->setEnabled(false);
             ui->cbx_setStopBits->setEnabled(false);
             ui->cbx_setParity->setEnabled(false);
             ui->btn_open_close->setText("关闭串口");
             qDebug()<<"打开串口:";
             serialPortInit();
         }

        if (btn_on_off == 1)
        {

            serialport->close();
            ui->cbx_setPortName->setEnabled(true);
            ui->cbx_setBaudRate->setEnabled(true);
            ui->cbx_setDataBits->setEnabled(true);
            ui->cbx_setStopBits->setEnabled(true);
            ui->cbx_setParity->setEnabled(true);
            ui->btn_open_close->setText("打开串口");
        }
        btn_on_off = !btn_on_off;
}

到这里基本上就可以成功打开串口了
请添加图片描述

5. 读串口函数 serialport->readAll();

在mainwindow.h 的private slots: 添加

    void serialPortReadyRead();

    void serialPortWrite();

对应的槽函数

void MainWindow::serialPortReadyRead()
{
    QByteArray temp = serialport->readAll();  
     QString str = ui->textEdit_rx->toPlainText();
     str =  QString::fromLocal8Bit(temp);//显示中文
      ui->textEdit_rx->append(str);
}
    

此时要手动链接信号函数和槽函数
mainwindow.cpp的MainWindow::MainWindow(QWidget *parent) :添加

    connect(serialport,SIGNAL(readyRead()),this,
                              SLOT(serialPortReadyRead()));
                              
     //SIGNAL 是信号函数,QT的串口自带了
     //SLOT是自己定义的槽函数
                          

按着ctrl点击readyRead(),就可以跳转到这里:

在这里插入图片描述

6.写串口函数 serialport->write(buff);

void MainWindow::serialPortWrite()
{
    QByteArray buff;
	//判断是否非空
    if(!ui->textEdit_tx->toPlainText().isEmpty())
    {
        buff = ui->textEdit_tx->toPlainText().toLocal8Bit();//可以写中文
        serialport->write(buff);
    }
}

把serialPortWrite()关联到发送的槽函数下
顺便把清空接收和清空发送也关联起来

void MainWindow::on_btn_clear_rx_clicked()
{
    ui->textEdit_rx->clear();
}

void MainWindow::on_btn_clear_tx_clicked()
{
    ui->textEdit_tx->clear();
}

void MainWindow::on_btn_sent_clicked()
{
    serialPortWrite();
}

接下来就是测试结果

第一个是stm32打印的上来的串口信息

第二个是自发自收(usb转串口的tx和rx短接)

读写

分割线:=======================================================================================
2022-11-04新增修订

评论区有小伙伴提出没有自刷新串口的功能,以及str += QString::fromLocal8Bit(temp);

现在去掉“+”号,变成str = QString::fromLocal8Bit(temp);

在原有的基础上

增加一个函数

mainwindows.cpp

void MainWindow::reflash_com()
{

    ui->cbx_setPortName->clear();//清除选择串口下拉栏添加的所有项目
    foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
    {
        {
            ui->cbx_setPortName->addItem(info.portName());
        }
    }
    ui->cbx_setPortName->setCurrentIndex(choose_index);
    qDebug()<<"choose_index:"<<choose_index;
}

此外增加一个变量choose_index 用于记录上次选择串口的项目index

函数和变量记得在对应的.h文件增加声明

同时把reflash_com()放到500ms定时器里面

void MainWindow::timer_500ms()
{
    QTime time = QTime::currentTime();
    QDate date = QDate::currentDate();
    ui->label_Date_Time->setText(date.toString("yyyy-MM-dd") +" "+ time.toString("hh:mm:ss"));
    ui->textEdit_rx->setFontPointSize(ui->cbx_setFontPointSize->currentText().toInt());
    
    if (btn_on_off == 0)//判断串口处于未打开状态
    {
      choose_index = ui->cbx_setPortName->currentIndex();
      reflash_com();
    }
}

效果:
在这里插入图片描述

  • 79
    点赞
  • 576
    收藏
    觉得还不错? 一键收藏
  • 45
    评论
评论 45
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值