前言
在实际工程项目中,一般是在Linux环境下,使用Qt开发多线程串口通信功能的上位机软件,不多逼逼,直接上正文:
一、自定义串口类
代码如下(示例):
CCtrlSerial::CCtrlSerial(const QString & portName, const int & baudRate, const QString & parity,
const QString & dataBits, const QString & stopBits, const QString & flowControl,
QObject * parent)
: QObject(parent)
{
// 对串口配置参数进行解析
int opt_baudrate = baudRate;
QSerialPort::Parity opt_parity = QSerialPort::Parity::NoParity;
if (parity == "NoParity")
{
opt_parity = QSerialPort::Parity::NoParity;
}
else if (parity == "OddParity")
{
opt_parity = QSerialPort::Parity::OddParity;
}
else if (parity == "EvenParity")
{
opt_parity = QSerialPort::Parity::EvenParity;
}
QSerialPort::DataBits opt_dataBits = QSerialPort::DataBits::Data8;
if (dataBits == "Data5")
{
opt_dataBits = QSerialPort::DataBits::Data5;
}
else if (dataBits == "Data6")
{
opt_dataBits = QSerialPort::DataBits::Data6;
}
else if (dataBits == "Data7")
{
opt_dataBits = QSerialPort::DataBits::Data7;
}
else if (dataBits == "Data8")
{
opt_dataBits = QSerialPort::DataBits::Data8;
}
QSerialPort::StopBits opt_stopBits = QSerialPort::StopBits::OneStop;
if (stopBits == "OneStop")
{
opt_stopBits = QSerialPort::StopBits::OneStop;
}
else if (stopBits == "OneAndHalfStop")
{
opt_stopBits = QSerialPort::StopBits::OneAndHalfStop;
}
else if (stopBits == "TwoStop")
{
opt_stopBits = QSerialPort::StopBits::TwoStop;
}
QSerialPort::FlowControl opt_flowControl = QSerialPort::FlowControl::NoFlowControl;
if (flowControl == "NoFlowControl")
{
opt_flowControl = QSerialPort::FlowControl::NoFlowControl;
}
else if (flowControl == "SoftwareControl")
{
opt_flowControl = QSerialPort::FlowControl::SoftwareControl;
}
else if (flowControl == "HardwareControl")
{
opt_flowControl = QSerialPort::FlowControl::HardwareControl;
}
threadSerial = new QThread(nullptr);
workerSerial = new CSerialport(portName, opt_baudrate, opt_parity, opt_dataBits, opt_stopBits, opt_flowControl, nullptr);
workerSerial->moveToThread(threadSerial);
connect(threadSerial, &QThread::started, workerSerial, &CSerialport::onInitSerial);
connect(threadSerial, &QThread::finished, workerSerial, &CSerialport::deleteLater);
connect(threadSerial, &QThread::finished, threadSerial, &QThread::deleteLater);
}
二、启动串口工作
代码如下(示例):
void CDeviceSerial::openDevice()
{
// 设备如果已经打开则关闭
if (flagOpen)
{
closeDevice();
}
// 创建工作类对象 - 串口 0
pSerial0 = new CCtrlSerial("/dev/ttyS0", 115200, "NoParity", "Data8", "OneStop", "NoFlowControl", this); // 指定了 parent,便于自动释放
connect(pSerial0, &CCtrlSerial::sigErrorOccurred, this, &CDeviceSerial::onErrorOccurred);
// 创建工作类对象 - 串口 2
pSerial2 = new CCtrlSerial("/dev/ttyS2", 115200, "NoParity", "Data8", "OneStop", "NoFlowControl", this); // 指定了 parent,便于自动释放
connect(pSerial2, &CCtrlSerial::sigErrorOccurred, this, &CDeviceSerial::onErrorOccurred);
connect(pSerial2, &CCtrlSerial::sigReadFromSerial, this, &CDeviceSerial::onReadFromSerial2);
// 创建工作类对象 - 串口 3
pSerial3 = new CCtrlSerial("/dev/ttyS3", 115200, "NoParity", "Data8", "OneStop", "NoFlowControl", this); // 指定了 parent,便于自动释放
connect(pSerial3, &CCtrlSerial::sigErrorOccurred, this, &CDeviceSerial::onErrorOccurred);
// 创建工作类对象 - 串口 4
pSerial4 = new CCtrlSerial("/dev/ttyS4", 115200, "NoParity", "Data8", "OneStop", "NoFlowControl", this); // 指定了 parent,便于自动释放
connect(pSerial4, &CCtrlSerial::sigErrorOccurred, this, &CDeviceSerial::onErrorOccurred);
// 创建工作类对象 - 串口 5
pSerial5 = new CCtrlSerial("/dev/ttyS5", 115200, "NoParity", "Data8", "OneStop", "NoFlowControl", this); // 指定了 parent,便于自动释放
connect(pSerial5, &CCtrlSerial::sigErrorOccurred, this, &CDeviceSerial::onErrorOccurred);
connect(pSerial5, &CCtrlSerial::sigReadFromSerial, this, &CDeviceSerial::onReadFromSerial5);
// 创建工作类对象 - 串口 6
pSerial6 = new CCtrlSerial("/dev/ttyS6", 115200, "NoParity", "Data8", "OneStop", "NoFlowControl", this); // 指定了 parent,便于自动释放
connect(pSerial6, &CCtrlSerial::sigErrorOccurred, this, &CDeviceSerial::onErrorOccurred);
connect(pSerial6, &CCtrlSerial::sigReadFromSerial, this, &CDeviceSerial::onReadFromSerial6);
// 必要的初始化变量
rdbuf2.clear();
rdbuf5.clear();
rdbuf6.clear();
rdbuf7.clear();
// 启用串口工作
//pSerial0->initParams();
pSerial2->initParams();
pSerial3->initParams();
pSerial4->initParams();
pSerial5->initParams();
pSerial6->initParams();
flagOpen = true; // 置标识
return;
}
开线程(关键点!!!)
void CCtrlSerial::initParams()
{
// 信号 - 槽
connect(workerSerial, &CSerialport::sigReadFromSerial, this, &CCtrlSerial::sigReadFromSerial);
connect(workerSerial, &CSerialport::sigErrorOccurred, this, &CCtrlSerial::sigErrorOccurred);
connect(workerSerial, &CSerialport::sigBytesWrited, this, &CCtrlSerial::sigBytesWrited);
connect(this, &CCtrlSerial::sigWriteToSerial, workerSerial, &CSerialport::onWriteToSerial);
threadSerial->start(); // 开启线程
}
1.串口写入数据
代码如下(示例):
void CSerialport::onWriteToSerial(const QByteArray & ba)
{
if (ba.isEmpty())
{
return;
}
if ((pSport == nullptr) || (!flagOpen))
{
return;
}
bufWrite.clear();
bufWrite.append(ba);
qint64 nums = pSport->write(bufWrite);
if (nums != -1)
{
int len = static_cast<int>(nums);
bufWrite.remove(0, len);
if (len > 0)
{
sigBytesWrited(len);
}
}
return;
}
2.串口读取数据
代码如下(示例):
void CSerialport::onProcessReadData()
{
if ((pSport == nullptr) || (!flagOpen))
{
return;
}
qint64 nums = pSport->bytesAvailable();
if (nums > 0)
{
bufRead.clear();
bufRead.append(pSport->readAll());
if (bufRead.size() > 0) // 这里用 size(),因为 count() 和 length() 其实也是 size()
{
emit sigReadFromSerial(bufRead); // 发射信号
}
}
return;
}
总结
以上为个人以前工作中,实际落地项目的代码节选内容,分享的目的是为了更好的帮助有真正需要帮助的人,如有疑问,欢迎拍砖。