QT学了一点发现学不进去,索性看看能不能直接撸个程序,于是就有了这个简易的串口软件…
这是XCOM串口收发软件,以此为例
目的很明确:
- 串口列表要能显示所有已经接上PC上的COM
- 以我们的配置115200-8-1-N打开串口
- 能收、发
既然用到串口,那么我们就要在.pro里增加串口的库
QT += serialport # 串口库
以及mainwindow.h里添加头文件
#include "qDebug.h" // 调试输出用
#include // 提供访问串口的功能
#include // 提供系统中存在的串口的信息
要注意的是,除了Label,其他的控件都记得命名呀,当然你用默认的也行…
我们要打开的串口,并不希望他是临时变量,我们用到的地方多呢!所以就在头文件先定义一个私有成员变量
QSerialPort *serial;
我们希望他在打开的时候就能加载所有的COM,所以我们在MainWindow里做这一步,创建窗口的时候就初始化COM列表,顺带着我们为serial开辟空间
// 我们在 ui->setupUi(this); 后面加入这些代码即可
// 添加所有串口到comboBox里(串口号的名字叫comboBox_COMx)
foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
{
ui->comboBox_COMx->addItem(info.portName()); //+':'+info.description()
}
serial = new QSerialPort(this);
我们用info去引用一个个的从串口的列表里取出COM的信息,如果有,我们就把他加入到【串口选择】的下拉栏里
这个时候如果我们运行,就会发现【串口选择】里已有了PC上已插入的COM设备。
首先为按钮【打开串口】添加槽,然后在槽函数里编写我们的代码:
打开了 总不能就一直开吧,所以我们做了一个开关,通过按钮上的字来判断是开还是关
// 点击打开串口
if(ui->pushButton_OpenSerial->text()==tr("打开串口"))
{
ui->pushButton_OpenSerial->setText(tr("关闭串口"));
}
else
{
ui->pushButton_OpenSerial->setText(tr("打开串口"));
}
这个时候我们运行,会发现打开串口的按钮已经可以正常工作了,点击打开,会显示关闭按钮。点击关闭,会显示打开按钮。
按钮做完了,接着就要做功能了,如果要关闭,我们就可以调用serial->close();来关闭串口,如果要打开,我们就去打开,不过不知道能不能打开(可能别的程序正在使用),所以加个if判断一下。
// 点击打开串口
if(ui->pushButton_OpenSerial->text()==tr("打开串口"))
{
ui->pushButton_OpenSerial->setText(tr("关闭串口"));
// 设置串口号(以当前显示的COM号为要打开的串口)
serial->setPortName(ui->comboBox_COMx->currentText());
// 以读写方式打开串口
if(serial->open(QIODevice::ReadWrite))
{
qDebug() << "Open OK" << endl;
}
else
{
qDebug() << "Open Failed" << endl;
}
}
else
{
ui->pushButton_OpenSerial->setText(tr("打开串口"));
serial->close();
}
现在我们运行一下,看调试信息知道目前都是正确的。能正确开关串口。
既然打开了串口,那么我们就配置一下串口的参数,因为只是一个简易的,所以就固定死串口为8-1-N,把一下代码放入成功打开串口的if内。
//设置波特率
serial->setBaudRate(115200);
//设置数据位
serial->setDataBits(QSerialPort::Data8);
//设置校验位
serial->setParity(QSerialPort::NoParity);
//设置流控制
serial->setFlowControl(QSerialPort::NoFlowControl);
//设置停止位
serial->setStopBits(QSerialPort::OneStop);
这就完了吗?还没有,我们配置好了串口,如何进行接收呢?我们利用的是QT的信号与槽机制,当串口收到数据,就会发出readyRead()信号,所以我们利用这个信号,建立一个槽用来接收字符。
先在头文件定义private slots函数 void recv_data(void);
然后我们紧接着刚刚配置串口后面写上connect()来连接信号与槽
connect(serial, SIGNAL(readyRead()), this, SLOT(recv_data()));
这样我们点击打开信号与槽后,就会配置串口,激活信号与槽。
现在万事俱备,只欠东风,我们继续写槽函数recv_data()来接收串口的数据
仔细思考一下,平时在用串口软件的时候,有新的数据发来会自动出现在旧的数据后面。
所以我们的做法是,先暂时保存显示的数据,然后把读到的数据加在后面,再清除显示的数据,把合成的数据再显示出来,就达到我们的效果了。
void MainWindow::recv_data(void)
{
qDebug() << "Recv Data" << endl;
QByteArray buf = serial->readAll();
if(!buf.isEmpty())
{
QString str = ui->textEdit_ReceiveMsg->toPlainText();
str+=tr(buf);
ui->textEdit_ReceiveMsg->clear();
ui->textEdit_ReceiveMsg->append(str);
}
}
这个时候我们运行一下,打开串口,用单片机来发数据,实测已经可以正确显示在屏幕上了
对于发送数据,有了刚才的经验就比较简单了。
为UI的【发送】键添加一个槽函数,当我们点击【发送】时,串口就发送我们写入的信息。
所以我们在发送的槽函数内写入:
// 先读取我们写入的文本
QString str = ui->textEdit_SendMsg->toPlainText().toLatin1();
qDebug() << str <<endl;
// 写入
serial->write(str.toLatin1());
串口的write函数的参数有两个
- 第一个是char *类型,所以我们要str转char *,用的.toLatin1()来转换。
- 第二个是传入字符最大数量(我选择不设置所以没填)
此时我们再运行,发现收发都正常了。
附上我的完整代码(不包含UI,看控件的英文名字应该能对上图片)
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include
#include // 提供访问串口的功能
#include // 提供系统中存在的串口的信息
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_pushButton_OpenSerial_clicked();
void recv_data(void);
void on_pushButton_SendMsg_clicked();
void on_pushButton_ClearRecv_clicked();
private:
Ui::MainWindow *ui;
QSerialPort *serial;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "qDebug.h"
#include "QObject"
#include "QTimer"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 初始化
// 添加所有串口到comboBox里(串口号的名字叫comboBox_COMx)
foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
{
ui->comboBox_COMx->addItem(info.portName()); //+':'+info.description()
}
serial = new QSerialPort(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::recv_data(void)
{
qDebug() << "Recv Data" << endl;
QByteArray buf = serial->readAll();
if(!buf.isEmpty())
{
QString str = ui->textEdit_ReceiveMsg->toPlainText();
str+=tr(buf);
ui->textEdit_ReceiveMsg->clear();
ui->textEdit_ReceiveMsg->append(str);
}
}
void MainWindow::on_pushButton_OpenSerial_clicked()
{
// 点击打开串口
if(ui->pushButton_OpenSerial->text()==tr("打开串口"))
{
ui->pushButton_OpenSerial->setText(tr("关闭串口"));
// 开辟空间
//serial = new QSerialPort(this);
// 设置串口号
serial->setPortName(ui->comboBox_COMx->currentText());
// 以读写方式打开串口
if(serial->open(QIODevice::ReadWrite))
{
qDebug() << "Open OK" << endl;
// 此处写死为 8-1-N
//设置波特率
serial->setBaudRate(115200);
//设置数据位
serial->setDataBits(QSerialPort::Data8);
//设置校验位
serial->setParity(QSerialPort::NoParity);
//设置流控制
serial->setFlowControl(QSerialPort::NoFlowControl);
//设置停止位
serial->setStopBits(QSerialPort::OneStop);
connect(serial, SIGNAL(readyRead()), this, SLOT(recv_data()));
}
else
{
qDebug() << "Open Failed" << endl;
}
}
else
{
ui->pushButton_OpenSerial->setText(tr("打开串口"));
serial->close();
}
}
void MainWindow::on_pushButton_SendMsg_clicked()
{
QString str = ui->textEdit_SendMsg->toPlainText().toLatin1();
qDebug() << str <<endl;
serial->write(str.toLatin1());
}
void MainWindow::on_pushButton_ClearRecv_clicked()
{
ui->textEdit_ReceiveMsg->clear();
}
其实还有很多其他的功能可以加进去,我就多做了一个【清除接收】…
甚至还有BUG…就是只有打开软件的时候才加载已有COM口,所以还要加上点击下拉框的时候就扫描更新一遍。
此时的波特率、停止位啥的都是写死的,所以真正要做完的话,还需要把这些控件都做上
还有等等等等…
哈哈 主要功能做出来了,其他的往上添加就好了。
打包exe教程 https://blog.csdn.net/syzdev/article/details/80860619
over…