网络知识 娱乐 QT 篇 QT上位机串口编程

QT 篇 QT上位机串口编程

QT 篇 QT上位机串口编程

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

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

默认安装好QT了

1.新建工程

选择Qt Widgets

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

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

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

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

2.添加类和库文件

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

QT       += core gui serialport

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

#include 			//访问串口的库
#include 		//查询串口信息的库
#include 				//用于调试打印输出的库
#include 				//定时器的库
#include 				//时间的库
#include 				//日期的库
#include 			//一个小的弹窗库

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

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短接)

读写