马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
目录
提示:编程环境与辅助步伐
一、项目新建,步伐完善,代码辨认
1.1项目新建
1.2、完善步伐,步伐属性设置
1.3环境辨认代码,进入舒畅的编程中。
1.4添加串口界面(现实就是添加一个qt类)
二、串口通讯实现
2.1界面控件添加
2.2点击按钮,唤出窗口
2.3 串口通讯界面,串口毗连实现
2.3.1串口添加
2.3.2 其他串口信息添加
2.4主界面信息接收,命令下发。
c++,与Qt学习了一段时间,感觉编写串口通讯软件是比力查验自己是否初步入门qt的一个标志。c++与qt编程学习过程中,感觉知识点繁芜繁琐,很难抓住核心。最开始学习《C++Prier Puls》,重新看起,真的是痛苦。之后在工作中,在现实编程过程中,感觉照旧在现实编程中学习是提拔比力快的方法。在打仗的各种编程实践中,我感觉串口通讯步伐就是一个非常好的实践例子。
首先串口通讯步伐的编写有助于初学者明白C++面临对象编程的一个核心:类,以及qt的一个核心信号与槽。
1、什么是C+的类,类的成员变量、成员函数。private 、public、protected函数之间区别。
2、qt的核心,信号与槽。信号与槽的毗连机制,什么时候毗连,什么时候断开。
而后,在编程过程中需要把握两个十分重要类,用于数据存储,数据啊之间转换的两个重要类QString和QByteArray类的根本使用。学习qt前期,需要了解大量的专有类。qt为很多问题提供了专门的类,例如串口通讯的QSerialPort类,类有封装好的各种函数、信号等能够解决你遇到的9成问题。
提示:编程环境与辅助步伐
qt与c++学习,编写串口通讯步伐,编程环境与辅助步伐。
1、我的用的版本是VS2015,qt5.9.6。
2、编写过程中使用串口通讯助手,来收发串口消息,虚拟串口驱动来创建虚拟串口。
环境配置,网上有很多教程,串口助手、虚拟串口驱动步伐网上也可以找到,后续也会出教程。
一、项目新建,步伐完善,代码辨认
第一步就是新建项目,在使用VS2015+QT组合的时候,由于涉及到串口通讯,在新建项目的时候,需要包罗QSerialPort类,在项目新建的时候需要注意。
1.1项目新建
在VS2015中新建QT窗口项目,这里我定名的是SerialPort,点击确认,后弹出一个qt提示串口,点击Next。
模式选择Debug,Serial Port模块包罗。
这个界面上中,选择Release或者Debug都可以,如果考虑到之后步伐打包,Release模式步伐体积会小很多。但是我这里遇到一个bug,我选择Release模式,点击QtModules,勾选SerialPort之后,回来又酿成Debug模式了。很奇怪,不过没关系,这之后还能修改。
点击确认之后,来到这个界面,这里可以选择步伐基于什么类:Base Class,我这里选择的是QWidget。这个步伐编辑完成之后,可很容易嵌入其他步伐中中,如果选择QMianWidow,就无法嵌入另一个基于QMainWindow创建的步伐,一个步伐只能有一个mainwindow。如果只是单独一个步伐话,两者都可以。
点击Finish,就完成了一个一个项目的创建,如下图所示,双击ui文件,得到一个空缺的ui界面,这时候步伐运行,得到的也是一个空缺界面。
接下来就是项目的属性设置,
1.2、完善步伐,步伐属性设置
你可能注意到上述界面中,在没有运行步伐之前,步伐代码中又红色波浪线,这说明VS没有辨认出这代码。还有几个点需要注意。
1、管理器改为Release模式
2、项目属性设置,在左侧项目名称SerialPort右键单击,出现属性,点击进入属性界面。可以看到这里的配置是Debug模式。
在属性页中切换配置为release,查察两个模式下 Qt Project Settings的Qt Modules,发现release模式下缺少serialport模块,这里需要手动添加,然后生存。到这里步伐的根本设置就完成了,下一步:解决代码红色波浪线问题。
1.3环境辨认代码,进入舒畅的编程中。
照旧项目右键-天生步伐,天生乐成之后——重新扫描步伐,这时候就发当代码中错误提示的红线消散,这时候输入代码,也有了提示。
1.4添加串口界面(现实就是添加一个qt类)
这里有一个问题,现实的步伐中,我们希望界面轻便、有序。特别是一些控制硬件的上位机,需要控制的参数多且杂。所以我们将串口毗连放到另一个界面中,串口毗连与步伐数据表现分开。现实就是将串口毗连类与主界面类分开,两者之间用信号与槽毗连,实现相互通讯。这就需要在项目再添加一个qt类,开始有点儿难了,但是相信我,并不比之前有多少难度,开始!
项目-右键,1添加-Add Qt Class-选择Qt Widgets Class,然后给类定名,点击Add
接下来就是qt的类创建指引,这里基类照旧选择QWidget。创建完成之后就会得到如许一个类。到这里我们还没有写一行代码,都是根本的操纵。
二、串口通讯实现
2.1界面控件添加
现在固然两个界面都添加了,但是他们之间并没有相互训练,步伐运行之后只能看到第一个界面,无法看到第二个界面。这就需要在一个界面叫醒机制。
目标:主界面增加一个按钮,点击按钮,第二个界面表现。
在ui界面左侧通过拖动相应控件到界面上就可以,下图我添加了一些控件用于表现数据。 串口通讯过程中需要知道串口名称、波特率、数据位、停止位、校验位,向ui界面中拖入PushButton,ComBox,和Label控件,并为其定名。如下图所示。
我们的逻辑是,软件运行,打开界面,点击革新后,下拉框出现串口,选择串口后,选择波特率、数据位、停止位、校验位,确定后,点击毗连,实现串口毗连。接下来就是在代码中实现我们预设的逻辑。
2.2点击按钮,唤出窗口
QT中不同类之间的数据通报通过信号与槽毗连。一个类发送信号,另一个类的槽函数接收信号。qt的类中很多自带有信号Signal,这个可以在qt的帮助文件中搜索相应的类来查察。这里QPushButton其中的一个信号就是clicked()。
在qt中通常的做法是使用connnect来毗连信号与槽,但是也有一个方便的机制,就是按名称毗连。比如我们希望点击界面的革新按钮后,能够转到一个槽函数来执行串口的革新操纵。
就可以如许做:在SerialPort类中,h头文件中:
1、首先包罗PortWidgets.h;
2、私有成员中增加一个PortWidgets私有成员。
3、添加private slots:然后添加私有槽函数: void on_pushButton_connect_clicked();这个函数是如许定名的:on_控件名_信号名();如许qt就能自动将QPushButton的clicked()信号与该函数毗连。
接下来在cpp文件中实现该函数。点击按钮,串口界面出现。
首先在构造函数中,将串口类指针初始化。接下俩在槽函数中,第一步是判断串口指针是否为空,为空就新建类,然后表现。这里就涉及到类构造,及公共函数public的使用。portwidgets是类的一个实例,它在类外,只能够使用公共函数,public函数,比如这个showNormal();
- SerialPort::SerialPort(QWidget *parent)
- : QWidget(parent)
- {
- ui.setupUi(this);
- portwidgets = NULL;
- }
- //按钮点击
- void SerialPort::on_pushButton_connect_clicked()
- {
- if (portwidgets == NULL)
- {
- portwidgets = new PortWidgets();
- }
- portwidgets->showNormal();//界面显示
- }
复制代码 统统正常后,运行步伐,点击按钮,第二个界面就会出现。
2.3 串口通讯界面,串口毗连实现
现在实现界面串口界面打开,接下来就是实现串口刷星,波特率、数据位、停止位、校验位,及串口毗连。
2.3.1串口添加
第一步:扫描电脑所有串口。需要用到虚拟串口模拟器:搜索Configure Virtual Serial Port Driver,安装就可以。然后添加一对相互毗连的串口。com1--com2.接下来就是:实现点击按钮实现扫描所有串口功能。槽函数添加方式与之前一样,不再赘述。串口革新需要包罗两个头文件。
#include "qserialport.h"
#include "qserialportinfo.h"
然后在现实编程过程中可以在槽函数中添加一个输出比如cout<<0<<endl,来查验信号与槽函数是否正常毗连。这段代码重要就是扫描电脑当前所有可用串口,获得名称,添加到响应的下拉框中,然后设置下拉框当前表现第一个串口。
- //刷新串口
- void PortWidgets::on_pushButton_refresh_clicked()
- {
- QStringList portNameList;
- QList<QSerialPortInfo> serialPortInfos = QSerialPortInfo::availablePorts();
- ui.comboBox_portlist->clear();
- // 遍历所有可用的串行端口信息
- for (const QSerialPortInfo &info : serialPortInfos)
- {
- portNameList.append(info.portName()); // 添加端口名到列表中
- }
- // 将端口名列表添加到下拉框中
- ui.comboBox_portlist->addItems(portNameList);
- // 默认情况下选择第一个端口
- if (!portNameList.isEmpty())
- {
- ui.comboBox_portlist->setCurrentIndex(0);
- }
- }
复制代码 2.3.2 其他串口信息添加
波特率、数据位、停止位、校验位,这里用了unordered_map文件中的键-值对应方法,如许在类实现中,就能够简化代码。头文件中类代码如下。
1、类中添加了void on_pushButton_portconnect_clicked();点击按钮,转到此函数中,实现串口毗连。
2、代码中,增加了void receive_data();槽函数,用于接收串口传输数据。串口类中有信号,readyread。串口收到信号就转到该槽函数处理。这个就需要手动毗连:
connect(myPort, &QSerialPort::readyRead, this, & ortWidgets::receive_data);
格式:connect(发送指针,&发送类::信号,接收指针,&接收类::接收槽函数)。槽函数实现中,
QByteArray data = myPort->readAll();
emit receivedata(data);
通过myPort读取到所有串口数据,然后有一个emit,是发送信号,这个信号由主界面的槽函数来接收。
- #pragma once
- #include <QWidget>
- #include "ui_PortWidgets.h"
- #include "qserialport.h"
- #include "qserialportinfo.h"
- #include <unordered_map> //非排序图
- #include <iostream>
- #include <qbytearray.h>
- #include <qthread.h>
- using namespace std;
- class PortWidgets : public QWidget
- {
- Q_OBJECT
- public:
- PortWidgets(QWidget *parent = Q_NULLPTR);
- ~PortWidgets();
- signals:
- void receivedata(QByteArray data);
- private slots:
- void on_pushButton_refresh_clicked();
- void on_pushButton_portconnect_clicked();
- void receive_data();
- public:
- void write_data(QByteArray writedata);
- private:
- Ui::PortWidgets ui;
- QSerialPort *myPort;//串口指针
- std::unordered_map<int, QSerialPort::BaudRate> baudRateMap =//波特率
- {
- { 0, QSerialPort::Baud1200 },{ 1, QSerialPort::Baud2400 },{ 2, QSerialPort::Baud4800 },
- { 3, QSerialPort::Baud9600 },{ 4, QSerialPort::Baud19200 },{ 5, QSerialPort::Baud38400 },
- { 6, QSerialPort::Baud57600 },{ 7, QSerialPort::Baud115200 }
- };
- std::unordered_map<int, QSerialPort::DataBits>dataMap =//数据位
- {
- { 0,QSerialPort::Data5 },{ 1,QSerialPort::Data6 },{ 2,QSerialPort::Data7 },{ 3,QSerialPort::Data8 }
- };
- std::unordered_map<int, QSerialPort::Parity>parityMap =//校验位
- {
- { 0,QSerialPort::NoParity },{ 1,QSerialPort::OddParity },{ 2,QSerialPort::EvenParity }
- };
- std::unordered_map<int, QSerialPort::StopBits>stopMap =//停止位
- {
- { 0,QSerialPort::OneStop },{ 1,QSerialPort::OneAndHalfStop },{ 2,QSerialPort::TwoStop }
- };
- };
复制代码 cpp,类实现。
- #include "PortWidgets.h"PortWidgets::PortWidgets(QWidget *parent) : QWidget(parent){ ui.setupUi(this); QStringList baudratelist = { "1200","2400","4800","9600","19200","38400","57600","115200" }; ui.comboBox_BaudRate->addItems(baudratelist); ui.comboBox_BaudRate->setCurrentIndex(3); QStringList datalist = { QString::fromLocal8Bit("5位"),QString::fromLocal8Bit("6位"), QString::fromLocal8Bit("7位"),QString::fromLocal8Bit("8位") }; ui.comboBox_Data->addItems(datalist); ui.comboBox_Data->setCurrentIndex(3); QStringList checklist = { QString::fromLocal8Bit("无校验"),QString::fromLocal8Bit("偶校验"), QString::fromLocal8Bit("奇校验") }; ui.comboBox_Check->addItems(checklist); ui.comboBox_Check->setCurrentIndex(0); QStringList stoplist = { QString::fromLocal8Bit("1位"),QString::fromLocal8Bit("1.5位"), QString::fromLocal8Bit("2位") }; ui.comboBox_Stop->addItems(stoplist); ui.comboBox_Stop->setCurrentIndex(0); on_pushButton_refresh_clicked(); myPort = NULL; myPort = new QSerialPort(this); connect(myPort, &QSerialPort::readyRead, this, &PortWidgets::receive_data);}PortWidgets::~PortWidgets(){}//刷新串口
- void PortWidgets::on_pushButton_refresh_clicked()
- {
- QStringList portNameList;
- QList<QSerialPortInfo> serialPortInfos = QSerialPortInfo::availablePorts();
- ui.comboBox_portlist->clear();
- // 遍历所有可用的串行端口信息
- for (const QSerialPortInfo &info : serialPortInfos)
- {
- portNameList.append(info.portName()); // 添加端口名到列表中
- }
- // 将端口名列表添加到下拉框中
- ui.comboBox_portlist->addItems(portNameList);
- // 默认情况下选择第一个端口
- if (!portNameList.isEmpty())
- {
- ui.comboBox_portlist->setCurrentIndex(0);
- }
- }//串口毗连void PortWidgets::on_pushButton_portconnect_clicked(){ myPort->setPortName(ui.comboBox_portlist->currentText()); int baudindex = ui.comboBox_BaudRate->currentIndex(); myPort->setBaudRate(baudRateMap[baudindex]); int dataindex = ui.comboBox_Data->currentIndex(); myPort->setDataBits(dataMap[dataindex]); int stopindex = ui.comboBox_Stop->currentIndex(); myPort->setStopBits(stopMap[stopindex]); int checkindex = ui.comboBox_Check->currentIndex(); myPort->setParity(parityMap[checkindex]); myPort->setFlowControl(QSerialPort::NoFlowControl); if (!myPort->isOpen()) { myPort->open(QIODevice::ReadWrite); if (myPort->isOpen()) cout << "Connection success!" << endl; else cout << "Connection failed!" << endl; }}//下发命令void PortWidgets::write_data(QByteArray writedata){ myPort->write(writedata);}//接收来自串口的数据,发送到主串口void PortWidgets::receive_data(){ QByteArray data = myPort->readAll(); emit receivedata(data);}
复制代码 2.4主界面信息接收,命令下发。
到这里,串口界面的根本功能已经具备了,也能够接收串口信息。下面就到了两个界面交互的部分。首先给出主界面类的定义及实现。
类定义:类中增加了几个私有槽函数;一个信号
1、void receive_data(QByteArray data);这是接收数据槽函数,用于响应串口类发送信号。
2、void on_lineEdit_data_returnPressed();这是响应界面中lineEdit按下enter后,进入该槽函数,在这里可以进行一些操纵。
3、void writedata(QByteArray data);该信号就是与串口类的下发命令毗连。
- #pragma once
- #include <QtWidgets/QWidget>
- #include "ui_SerialPort.h"
- #include "PortWidgets.h"
- class SerialPort : public QWidget
- {
- Q_OBJECT
- public:
- SerialPort(QWidget *parent = Q_NULLPTR);
- private slots:
- void on_pushButton_connect_clicked();
- void on_lineEdit_data_returnPressed();
- void receive_data(QByteArray data);//接收串口数据的槽
- void on_pushButton_clear_clicked();//清除接收框的数据
- signals:
- void writedata(QByteArray data);
- private:
- Ui::SerialPortClass ui;
- PortWidgets *portwidgets;
- };
复制代码 类实现:
1、可以看到,我们在串口毗连的时候,对两个类之间的信号与槽进行了毗连,这里需要注意的是,如果我们在中途想要断开毗连一段时间后,再次毗连串口。需要将信号与槽的毗连也断开,可以自己尝试一下,实现这个功能。
2、数据发送中,我们在void SerialPort: n_lineEdit_data_returnPressed()槽函数中,获取了当前编辑框的信息转为int,接着定义了一个QByteArray,通过如下的方式将该int转为16进制,
data.resize(1);
data[0] = value & 0xff;
emit writedata(data);
并发送信号,然后就转到串口类的槽函数中,完成命令下发。
void PotWidgets::write_data(QByteArray writedata)
{
myPort->write(writedata);
}
- #include "SerialPort.h"
- SerialPort::SerialPort(QWidget *parent)
- : QWidget(parent)
- {
- ui.setupUi(this);
- portwidgets = NULL;
- }
- //按钮点击
- void SerialPort::on_pushButton_connect_clicked()
- {
- if (portwidgets == NULL)
- {
- portwidgets = new PortWidgets();
- connect(portwidgets, &PortWidgets::receivedata, this, &SerialPort::receive_data);//接收来自串口界面的消息
- connect(this, &SerialPort::writedata, portwidgets, &PortWidgets::write_data); //发送数据到串口界面
- }
- portwidgets->showNormal();//界面显示
- }
- //数据发送,编辑框回车确定
- void SerialPort::on_lineEdit_data_returnPressed()
- {
- if (ui.lineEdit_data->text() != NULL)
- {
- int value = ui.lineEdit_data->text().toInt();
- QByteArray data;
- data.resize(1);
- data[0] = value & 0xff;
- emit writedata(data);
- }
- }
- //接收数据,显示
- void SerialPort::receive_data(QByteArray data)
- {
- bool ok;
- QString str = data.toHex(' ').toUpper();
- ui.textEdit_receive->append(str);
- }
- //清除数据显示框
- void SerialPort::on_pushButton_clear_clicked()
- {
- ui.textEdit_receive->clear();
- }
复制代码 背面的内容我没有写的很详细,但是源代码都给出了,初学者颠末前面的操纵后,然后看代码,不断明白,应该可以把握该步伐的精髓。同时这个代码照旧不完善的。
这里指出:
1、串口毗连之后,并没没有提示是否毗连
2、串口毗连之后,没有断开操纵。
3、这里串口接收消息,只能处理简单数据,现实工作汇总,串口接收数据快,且多,需要单独线程处理。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |