QextSerialPort是一个跨平台的第三方串口类,可以很方便地在QT中对串口读写操作。但是默认使用的读写方式是查询方式,一般都是在程序中使用定时器。如果需要快速响应串口读写,可以使用多线程方式。在qtcentre论坛上找到了一位作者贴出了自己的源码,在此转贴出来,方便大家。(原帖地址:http://www.qtcentre.org/threads/21063-QextSerialPort-with-QTimer-approch-for-reading?p=103325&highlight=#post103325)
程序是QT4直接可用的。如果是QTE2,相应做一些修改后也可以工作。
mythreadport.h
#ifndef MYSERIALPORT_H #define MYSERIALPORT_H #include <QObject> #include <QQueue> #include <QMetaType> #include <QThread> #include <QMutex> #include "qextserialport.h" Q_DECLARE_METATYPE(BaudRateType); Q_DECLARE_METATYPE(DataBitsType); Q_DECLARE_METATYPE(ParityType); Q_DECLARE_METATYPE(StopBitsType); Q_DECLARE_METATYPE(FlowType); class SendThread; class ReceiveThread; class MySerialPort : public QObject { Q_OBJECT public: MySerialPort(); MySerialPort(const QString &name, const BaudRateType baudRate, const DataBitsType dataBits, const ParityType parity, const StopBitsType stopBits, const FlowType flowControl, ulong seconds = 0, ulong milliseconds = 10); ~MySerialPort(); bool open(); bool open(const QString &name, const BaudRateType baudRate, const DataBitsType dataBits, const ParityType parity, const StopBitsType stopBits, const FlowType flowControl, ulong seconds = 0, ulong milliseconds = 10); bool isOpen() const; void close(); // Setter and getter for the basic property of the QextSerialPort void setPortName(const QString &name); QString portName() const; void setBaudRate(const BaudRateType baudRate); BaudRateType baudRate() const; void setDataBits(const DataBitsType dataBits); DataBitsType dataBits() const; void setParity(const ParityType parity); ParityType parity() const; void setStopBits(StopBitsType stopBits); StopBitsType stopBits() const; void setFlowControl(const FlowType flowControl); FlowType flowControl() const; void setTimeout(const ulong seconds, const ulong milliseconds); /* Send */ void enableSending(); // enable the SerialPort to send data (init the thread) void disableSending(); // disable the SerialPort to send data (terminate the thread) bool isSendingEnable() const; void stopSending(); // stop the currently sending data operation (don't terminate the thread) uchar sendData(const QByteArray &data); // send data to the SerialPort (enqueue data to the sendThread queue) // return 1 OK // return 2 port not open // return 3 sending operation disable /* Receive */ void enableReceiving(); // enable the SerialPort to receive data (init the thread) void disableReceiving(); // disable the SerialPort to receive data (terminate the thread) bool isReceivingEnable() const; void stopReceiving(); // stop the currently receiving data operation (don't terminate the thread) uchar receiveData(); // Start the receiving thread // return 1 OK // return 2 port closed // return 3 receiving operation disable signals: void dataReceived(const QByteArray &dataReceived); private: void initPrivateVariable(); private: QextSerialPort port; SendThread *sendThread; ReceiveThread *receiveThread; bool sendingEnable; bool receivingEnable; // Variables to restore the previous state to a reopening of the SerialPort bool closeCalled; bool saveStateSendingEnable; bool saveStateReceivingEnable; bool saveStateReceiveData; }; class SendThread : public QThread { Q_OBJECT public: SendThread(QextSerialPort &adrPort); ~SendThread(); void addDataToSend(const QByteArray &dataToAdd); void stopSending(); protected: void run(); private: QextSerialPort &port; QQueue<QByteArray> dataToSend; QMutex mutexSend; bool stopped; }; class ReceiveThread : public QThread { Q_OBJECT public: ReceiveThread(QextSerialPort &adrPort); ~ReceiveThread(); void stopReceiving(); protected: void run(); signals: void dataReceived(const QByteArray &dataReceived); private : QextSerialPort &port; QMutex mutexReceive; bool stopped; }; #endif // MYSERIALPORT_H
mythreadport.cpp
#include "myserialport.h" /* Private Functions */ void MySerialPort::initPrivateVariable() { // Init private variable sendThread = NULL; receiveThread = NULL; sendingEnable = false; receivingEnable = false; closeCalled = false; saveStateSendingEnable = false; saveStateReceivingEnable = false; saveStateReceiveData = false; } /******************************************************************************* ******************************* PUBLIC **************************************** ******************************************************************************/ /******************************* Constructor **********************************/ MySerialPort::MySerialPort() { initPrivateVariable(); } MySerialPort::MySerialPort(const QString &name, const BaudRateType baudRate, const DataBitsType dataBits, const ParityType parity, const StopBitsType stopBits, const FlowType flowControl, ulong seconds, ulong milliseconds) { initPrivateVariable(); setPortName(name); setBaudRate(baudRate); setDataBits(dataBits); setParity(parity); setStopBits(stopBits); setFlowControl(flowControl); setTimeout(seconds, milliseconds); } /******************************* Distructor ***********************************/ MySerialPort::~MySerialPort() { if (sendThread) { delete sendThread; sendThread = NULL; } if (receiveThread) { delete receiveThread; receiveThread = NULL; } if (isOpen()) port.close(); } /******************************* Methods **************************************/ // Open the SerialPort bool MySerialPort::open() { bool res = port.open(QIODevice::ReadWrite); // If the port is reopened after an earlier closure restores the previous state if (closeCalled) { if (saveStateSendingEnable) enableSending(); if (saveStateReceivingEnable) enableReceiving(); if (saveStateReceiveData) receiveData(); closeCalled = false; } return res; } bool MySerialPort::open(const QString &name, const BaudRateType baudRate, const DataBitsType dataBits, const ParityType parity, const StopBitsType stopBits, const FlowType flowControl, ulong seconds, ulong milliseconds) { setPortName(name); setBaudRate(baudRate); setDataBits(dataBits); setParity(parity); setStopBits(stopBits); setFlowControl(flowControl); setTimeout(seconds, milliseconds); //return open(); return port.open(QIODevice::ReadWrite); } // SerialPort is open? bool MySerialPort::isOpen() const { return port.isOpen(); } // Close the SerialPort void MySerialPort::close() { closeCalled = true; // Save the state saveStateSendingEnable = isSendingEnable(); saveStateReceivingEnable = isReceivingEnable(); // Close the port disableReceiving(); disableSending(); port.close(); // TODO: should I stop send and receive? } // Setter and getter for the basic property of the QextSerialPort void MySerialPort::setPortName(const QString &name) { port.setPortName(name); } QString MySerialPort::portName() const { return port.portName(); } void MySerialPort::setBaudRate(const BaudRateType baudRate) { port.setBaudRate(baudRate); } BaudRateType MySerialPort::baudRate() const { return port.baudRate(); } void MySerialPort::setDataBits(const DataBitsType dataBits) { port.setDataBits(dataBits); } DataBitsType MySerialPort::dataBits() const { return port.dataBits(); } void MySerialPort::setParity(const ParityType parity) { port.setParity(parity); } ParityType MySerialPort::parity() const { return port.parity(); } void MySerialPort::setStopBits(StopBitsType stopBits) { port.setStopBits(stopBits); } StopBitsType MySerialPort::stopBits() const { return port.stopBits(); } void MySerialPort::setFlowControl(const FlowType flowControl) { port.setFlowControl(flowControl); } FlowType MySerialPort::flowControl() const { return port.flowControl(); } void MySerialPort::setTimeout(const ulong seconds, const ulong milliseconds) { port.setTimeout(seconds, milliseconds); } /* Send */ // Enable the SerialPort to send data (init the thread) void MySerialPort::enableSending() { // If the Sending is not already active AND the sendThead is not initialized if (!sendingEnable && !sendThread) { sendThread = new SendThread(port); sendingEnable = true; } } // Disable the SerialPort to send data (terminate the thread) void MySerialPort::disableSending() { // If the Sending is already active AND there is a sendThread if (sendingEnable && sendThread) { delete sendThread; sendThread = NULL; sendingEnable = false; } } bool MySerialPort::isSendingEnable() const { return sendingEnable; } // Stop the currently sending data operation (don't terminate the thread) void MySerialPort::stopSending() { // If the Sending is not alread active OR the sendThread is not initialized if (!sendingEnable || !sendThread) return; // If the SerialPort is currently sending data, stop if (sendThread->isRunning()) { sendThread->stopSending(); //wait(); ?????????? sendThread->wait(); } } // Enqueue data to the sendThread queue // return 1 OK // return 2 port closed // return 3 sending operation disable uchar MySerialPort::sendData(const QByteArray &data) { // check the port if is open if (!isOpen()) return 2; // check if sending operation is enable if (!sendingEnable || !sendThread) return 3; sendThread->addDataToSend(data); return 1; } /* Receive */ // Enable the SerialPort to receive data (init the thread) void MySerialPort::enableReceiving() { // If the Receiving is not already active AND the receiveThead is not initialized if (!receivingEnable && !receiveThread) { receiveThread = new ReceiveThread(port); connect(receiveThread, SIGNAL(dataReceived(const QByteArray &)), this, SIGNAL(dataReceived(const QByteArray &))); receivingEnable = true; } } // Disable the SerialPort to receive data (terminate the thread) void MySerialPort::disableReceiving() { // If the Receiving is already active AND there is a receiveThread if (receivingEnable && receiveThread) { delete receiveThread; receiveThread = NULL; receivingEnable = false; } } bool MySerialPort::isReceivingEnable() const { return receivingEnable; } // Stop the currently receiving data operation (don't terminate the thread) void MySerialPort::stopReceiving() { // If the Receiving is not alread active OR the receiveThread is not initialized if (!receivingEnable || !receiveThread) return; // If the SerialPort is currently receiving data, stop if (receiveThread->isRunning()) { saveStateReceiveData = false; receiveThread->stopReceiving(); // wait(); receiveThread->wait(); } } // Start the receiving thread // return 1 OK // return 2 port closed // return 3 receiving operation disable uchar MySerialPort::receiveData() { // check the port if is open if (!isOpen()) return 2; // check if receiving operation is enable if (!receivingEnable && !receiveThread) return 3; // If the SerialPort receiving thread is not currently active, start it if (!receiveThread->isRunning()) { saveStateReceiveData = true; receiveThread->start(); } return 1; } /******************************************************************************* ******************************* SENDTHREAD ************************************ ******************************************************************************/ /******************************* Constructor **********************************/ SendThread::SendThread(QextSerialPort &adrPort): port(adrPort) { dataToSend.clear(); stopped = false; } /******************************* Distructor ***********************************/ SendThread::~SendThread() { if (isRunning()) { stopSending(); wait(); } } /******************************* Methods **************************************/ // Add the data to the Send Queue void SendThread::addDataToSend(const QByteArray &dataToAdd) { QMutexLocker locker(&mutexSend); for (int i=0; i<dataToAdd.size(); i++) dataToSend.enqueue(QByteArray(1,dataToAdd.at(i))); if (!isRunning()) start(); } // Stop the sending operation void SendThread::stopSending() { stopped = true; } // Thread Send Loop void SendThread::run() { QByteArray byteArray; forever { mutexSend.lock(); if (dataToSend.isEmpty() || stopped) { mutexSend.unlock(); stopped = false; break; } byteArray = dataToSend.dequeue(); mutexSend.unlock(); port.write(byteArray, 1); } } /******************************************************************************* ******************************* RECEIVETHREAD ********************************* ******************************************************************************/ /******************************* Constructor **********************************/ ReceiveThread::ReceiveThread(QextSerialPort &adrPort) : port(adrPort) { stopped = false; } /******************************* Distructor ***********************************/ ReceiveThread::~ReceiveThread() { if (isRunning()) { stopReceiving(); wait(); } } /******************************* Methods **************************************/ // Stop the sending operation void ReceiveThread::stopReceiving() { stopped = true; } // Thread Receive Loop void ReceiveThread::run() { int numBytes = 0; QByteArray data; forever { if (stopped) { stopped = false; break; } numBytes = port.bytesAvailable(); if (numBytes>0) { mutexReceive.lock(); data = port.read(numBytes); mutexReceive.unlock(); emit dataReceived(data); } } }