主要目的:通过串口获取外设的数据,转发到服务器进行处理并在Web端显示设备的信息。
主要用到的知识点:
第一:串口通信相关的知识。
1.串口通信用到的两个头文件:
#include
#include
QSerialPort:用于访问串口,并对串口进行操作。
QSerialPortInfo:提供了系统中存在的串口的信息。
2.工程文件(.pro)中加下面一行代码:
QT += serialport
注意:工程文件中添加上述代码后,要保存后才能生效,方法:在QT Creator中文件—保存所有文件。
第二:Tcp通信相关知识。
1.Tcp通信用到的头文件:
#include
2.需要.pro文件中加入下面代码:
QT += network
代码实现:
第一:设计模块截图
下面的红色是各个控件的QbjectNname,在代码要用到,为了方便读者方便阅读所以都标记出来了。下面“发送”按钮是预留按钮,在代码中没有用到,准备在后面的更新中再优化用到此按钮哦。
第二:代码展示
#-------------------------------------------------
#
# Project created by QtCreator 2019-09-30T15:51:56
#
#-------------------------------------------------
QT += core gui network serialport
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = qianxunSerialPort
TEMPLATE = app
SOURCES += main.cpp\
widget.cpp
HEADERS += widget.h
FORMS += widget.ui
注意:QT += core gui network serialport,一定要添加后在文件中保存,不然会出问题的哦。
widget.h:
#ifndef WIDGET_H
#define WIDGET_H
#include
#include
#include
#include
#include
#include
#include
#include
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
void InitTcp();
void InitPort();
void doProcessWrite();
void doProcessTcpWrite();
void writeByteArray();
private slots:
void doProssConnected();
void doProcessReadyRead();
void doProssDisconnected();
void doProcessSerialRead();
private slots:
void on_pushButton_clicked();
void on_ConnectBtn_clicked();
//void on_SendBtn_clicked();
void on_ClearBtn_clicked();
void on_CheckBtn_clicked();
private:
Ui::Widget *ui;
QTcpSocket *myTcpSocket;
bool pushBtnFlag=false;
QSerialPort *mySerial;
QByteArray tempStr;//保存的从服务器获取的字节流
QByteArray readComDataMsg;//保存从串口获取的字节流
};
#endif // WIDGET_H
main.cpp:
#include "widget.h"
#include
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
w.setWindowTitle("串口转Tcp工具");
return a.exec();
}
widget.cpp:
#include "widget.h"
#include "ui_widget.h"
#include
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
//初始化端口
InitPort();
//初始化Tcp
InitTcp();
// ui->SendBtn->setEnabled(false);
}
Widget::~Widget()
{
delete ui;
}
void Widget::InitTcp()
{
myTcpSocket=new QTcpSocket(this);
//由于connectToHost没有返回值,所以通过三个connect来判断和服务器的状态
connect(myTcpSocket,SIGNAL(disconnected()),this,SLOT(doProssDisconnected()));
connect(myTcpSocket,SIGNAL(connected()),this,SLOT(doProssConnected()));
connect(myTcpSocket,SIGNAL(readyRead()),this,SLOT(doProcessReadyRead()));
}
//点击打开Tcp连接服务器
void Widget::on_pushButton_clicked()
{
if(ui->pushButton->text()=="打开TCP")
{
QString ServceIp=ui->lineEdit_IP->text();
QString ServcePort=ui->lineEdit_Port->text();
myTcpSocket->connectToHost(QHostAddress(ServceIp),ServcePort.toUInt());
ui->pushButton->setText("关闭TCP");
}
else if(ui->pushButton->text()=="关闭TCP")
{
myTcpSocket->close();
ui->pushButton->setText("打开TCP");
ui->textEdit_Client->append("TCP关闭成功!");
}
}
void Widget::doProssConnected()
{
QString str="打开服务器成功";
ui->textEdit_Client->append(str);
}
void Widget::doProcessReadyRead()
{
QTcpSocket *myTcpSocket=(QTcpSocket *)this->sender();
//读取服务器向缓冲区的存储数据
while (!myTcpSocket->atEnd())
{
tempStr= myTcpSocket->readAll();
// tempStr=QString::fromLocal8Bit(tempMsg);
qDebug()<<"服务器向缓冲区存储字节数据";
}
//处理向串口写入数据
doProcessWrite();
writeByteArray();
}
void Widget::doProssDisconnected()
{
// QString msg="服务器断开";
// ui->textEdit_Client->append(msg);
ui->pushButton->setText("关闭TCP");
}
//向服务器写入数据。
void Widget::doProcessTcpWrite()
{
if(!readComDataMsg.isEmpty())
{
int ret= myTcpSocket->write(readComDataMsg);
readComDataMsg.clear();
if(ret<0)
{
return;
}
}
else{
qDebug()<<"向服务器写入数据失败";
}
}
//........................................................................
//.............................串口.......................................
void Widget::InitPort()
{
mySerial = new QSerialPort(this);
foreach (const QSerialPortInfo&info,QSerialPortInfo::availablePorts())
{
QSerialPort serial;
serial.setPort(info);
//串口每打开一次就要close一次,不然下次打不开。
qDebug()<<"#######";
if(serial.open(QIODevice::ReadWrite))
{
ui->ComBC->addItem(info.portName());
serial.close();
}
}
QStringList baudList;//波特率
baudList<<"115200"<<"57600"<<"38400"<<"19200"<<"9600"<< "4800"<<"2400"<<"1200";
ui->BaudCB->addItems(baudList);
QStringList dataBitsList;
dataBitsList<<"8"<<"7"<<"6"<<"5";
ui->DataBitsCB->addItems(dataBitsList);
QStringList parityList;
parityList<<"无校验"<<"奇校验"<<"偶校验";
ui->ParityCB->addItems(parityList);
QStringList stopBitsList;
stopBitsList<<"1"<<"1.5"<<"2";
ui->StopCB->addItems(stopBitsList);
QStringList setFlowCtrl;
setFlowCtrl<<"off"<<"RTS/CTS"<<"XON/XOFF";
ui->FlowsCB->addItems(setFlowCtrl);
//ui->SendBtn->setEnabled(false);
}
void Widget::on_ConnectBtn_clicked()
{
if(ui->ConnectBtn->text()=="串口连接")
{
mySerial->setPortName(ui->ComBC->currentText());
qDebug()<<"***********";
bool openSerial= mySerial->open(QIODevice::ReadWrite);
if(openSerial)
{
//设置波特率
if ( ui->BaudCB->currentText()=="115200")
{
mySerial->setBaudRate(QSerialPort::Baud115200);
}
//qDebug()<<"115200";
else if ( ui->BaudCB->currentText()==" 9600")
{
mySerial->setBaudRate(QSerialPort::Baud9600);
}
else if ( ui->BaudCB->currentText()==" 1200")
{
mySerial->setBaudRate(QSerialPort::Baud1200);
}
else if ( ui->BaudCB->currentText()==" 2400")
{
mySerial->setBaudRate(QSerialPort::Baud2400);
}
else if ( ui->BaudCB->currentText()==" 4800")
{
mySerial->setBaudRate(QSerialPort::Baud4800);
}
else if ( ui->BaudCB->currentText()==" 19200")
{
mySerial->setBaudRate(QSerialPort::Baud19200);
}
else if ( ui->BaudCB->currentText()==" 38400")
{
mySerial->setBaudRate(QSerialPort::Baud38400);
}
else if ( ui->BaudCB->currentText()==" 57600")
{
mySerial->setBaudRate(QSerialPort::Baud57600);
}
//设置数据位
if (ui->DataBitsCB->currentText()=="8")
mySerial->setDataBits(QSerialPort::Data8);
else if (ui->DataBitsCB->currentText()=="7")
mySerial->setDataBits(QSerialPort::Data7);
else if (ui->DataBitsCB->currentText()=="6")
mySerial->setDataBits(QSerialPort::Data6);
else if (ui->DataBitsCB->currentText()=="5")
mySerial->setDataBits(QSerialPort::Data5);
//设置校验位
if (ui->ParityCB->currentText()=="0")
mySerial->setParity(QSerialPort::NoParity);
else if (ui->ParityCB->currentText()=="2")
mySerial->setParity(QSerialPort::EvenParity);
else if (ui->ParityCB->currentText()=="3")
mySerial->setParity(QSerialPort::OddParity);
//停止位
if (ui->StopCB->currentText()=="1")
mySerial->setStopBits(QSerialPort::OneStop);
else if (ui->StopCB->currentText()=="3")
mySerial->setStopBits(QSerialPort::OneAndHalfStop);
else if (ui->StopCB->currentText()=="2")
mySerial->setStopBits(QSerialPort::TwoStop);
//流控制
if (ui->FlowsCB->currentText()=="0")
mySerial->setFlowControl(QSerialPort::NoFlowControl);
else if (ui->FlowsCB->currentText()=="1")
mySerial->setFlowControl(QSerialPort::HardwareControl);
else if (ui->FlowsCB->currentText()=="2")
mySerial->setFlowControl(QSerialPort::SoftwareControl);
}
connect(mySerial,SIGNAL(readyRead()),this,SLOT(doProcessSerialRead()));
QString msg1="log gpgga ontime 5\r\n";
QString msg2="interfacemode auto auto on\r\n";
//mySerial->write(msg1+msg2);
mySerial->write(msg1.toLatin1());
mySerial->write(msg2.toLatin1());
ui->ConnectBtn->setText("串口关闭");
ui->BaudCB->setEnabled(false);
ui->DataBitsCB->setEnabled(false);
ui->FlowsCB->setEnabled(false);
ui->ParityCB->setEnabled(false);
ui->StopCB->setEnabled(false);
ui->ComBC->setEnabled(false);
}
else if(ui->ConnectBtn->text()=="串口关闭")
{
mySerial->close();
ui->ConnectBtn->setText("串口连接");
ui->BaudCB->setEnabled(true);
ui->DataBitsCB->setEnabled(true);
ui->FlowsCB->setEnabled(true);
ui->ParityCB->setEnabled(true);
ui->StopCB->setEnabled(true);
ui->ComBC->setEnabled(true);
}
}
//读取串口的数据
void Widget::doProcessSerialRead()
{
readComDataMsg = mySerial->readAll();
QString str=QString::fromLocal8Bit(readComDataMsg);
QString strTemp=str.replace(QString("\r\n"),QString(" "));
ui->textEdit_Servce->append(strTemp);
//ui->textEdit_Servce->setText(readComDataMsg);
// }
doProcessTcpWrite();
// readComData.clear();
}
//void Widget::on_SendBtn_clicked()
//{
// //QString serialTemp=ui->textEdit_Client->toPlainText();
// QString serialTemp="log versionb ontime 1\r\n";
// //QString serialTemp="log gpgga ontime 1 \r\n";
// //qDebug()<write(serialTemp.toLatin1());
// qDebug()<textEdit_Servce->clear();
ui->textEdit_Client->clear();
}
//向串口写入数据
void Widget::doProcessWrite()
{
if(!tempStr.isEmpty())
{
qDebug()<<"向串口写入数据正确";
// char *ch=tempStr.data();
// int ret= mySerial->write(ch);
mySerial->write(tempStr);
int byteLen= mySerial->bytesToWrite();
qDebug()<<"写数据的大小:"<textEdit_Client->append(strReplace);
//qDebug()<ComBC->clear();
foreach (const QSerialPortInfo&info,QSerialPortInfo::availablePorts())
{
QSerialPort serial;
serial.setPort(info);
if(serial.open(QIODevice::ReadWrite))
{
ui->ComBC->addItem(info.portName());
serial.close();
}
}
}
代码思路梳理:从服务器获取字节流保存在tempStr全局变量中,然后写入到串口,从串口中获取的数据保存在readComDataMsg全局变量中,写入到服务器和在界面上显示。
继续优化的问题:
1.进行大量串口数据的转发,运行一天软件正常运行,数据转发正常,可以优化成多线程间通信,拓展知识。
2.doProcessWrite()/doProcessTcpWrite()这两个函数时直接调用的,应该使用Qt的风格,用emit发送信号,使用信号和槽函数模式。
欢迎有问题的小伙伴或者对代码有见解的,多多交流哦。