最近因为项目需要,需要用到上位机,通过串口与上位机进行通讯,来上传和下发一些数据以及控制指令,所以用QT写了一个上位机,并记录下来,免得到时候要用又到处翻资料。
QT版本:QT Creater 4.80
硬件:stm32 + 串口转ttl模块
默认安装好QT了
选择Qt Widgets
然后下一步
自己填一个项目名字和项目路径
我只安装了这一个,我就选了这个
这里主要是一些基类的选择
这里我选择QMainWindow
类名,文件名什么的,你们看看要不要改名
QT5自带有串口的封装库 QSerialPort ,我们要用的相关的函数,所以要在.pro文件里面添加一样代码,在QT += core gui的基础上添加serialport
QT += core gui serialport
在mainwindo.h里添加串口的一些库
#include //访问串口的库
#include //查询串口信息的库
#include //用于调试打印输出的库
#include //定时器的库
#include //时间的库
#include //日期的库
#include //一个小的弹窗库
其实上面这些这需要添加最顶上的了两个就够了,其余的是我有其他的用处就加了进去
这是我自己设计好的上位机
上位机页面
先设置好窗口的大小固定位800x480
窗口最大和最小都是800x480 这样一来就没办法拉伸了,就不会影响美观
当然你们也可以不用这么多控件,因为实际上来说,需要修改的串口参数其实就只有名称和波特率而已,其余的是可以固定不做改变的
看需求
对象的名称最好改一下,不然到时候编写代码的时候你会不记得哪个代表哪一个部件,我的部件的名称
对象名称
摆放好这些部件后
分别添加波特率
停止位
数据位
奇偶校验等等
我把串口的波特率设置为115200是初始值
其余的你们看着来
CurrentIndex的索引和数组一样,从0开始
在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;
}
在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(),就可以跳转到这里:
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短接)