Qt中的串口编程之二

          Qt Serial Port

【概述】

   Qt Serial Port提供了基本的功能,包括配置,I/O操作,获取和设置RS-232引脚的信号。

[cpp]   view plain  copy
  1. <span style="font-size:14px;"><span style="font-family: Arial, Helvetica, sans-serif;"></span></span>  
本模块暂不支持如下特性:
*终端的特性,例如回显,控制CR/LF等等
*文本模式
*配置读操作的超时和延时
*当RS-232引脚信号改变的时候跟踪和通知
要在自己的应用程序中使用这些类,那么就必须包括如下的声明:
#include <QtSerialPort/QtSerialPort>
要链接本模块,那么需要在.pro文件中添加如下内容:
QT += serialport

【类】

本模块包括两个类:
QSerialPort:提供访问串口的功能
QSerialPortInfo:提供系统中存在的串口的信息

【QSerialPort】

       该类提供访问串口的功能。你可以使用QSerialPortInfo帮助类获取系统上可用的串口的信息,可以枚举系统上存在的所有串口。通过该类你可以获取串口的正确名称。你可以传递一个该类的对象作为setPort()或者setPortName()方法的参数指定想要访问的串口设备。
       在设置完了串口,你就可以以只读或者只写或者读写模式调用open()方法打开串口。
注意:串口都是以互斥的方式访问,这也就是说我们不能打开一个已经打开的串口。
        成功打开之后,QSerialPort尝试着获取串口当前的配置并初始化它。你也可以使用setBaudRate(),setDataBits(),setParity(),
setStopBits()

和setFlowControl()方法重新配置它。控制管脚的状态是根据isDataTerminalReady(),isRequestToSend()和pinoutSignals()决定的。要改变控制信息,可以使用如下方法:setDataTerminalReady()和setRequestToSend()。

        一旦你知道了串口可用于读或者写,你就可以调用read()或者write()方法。可选的还有readline()和readAll()方法。如果数据不能在一次读完,那么剩下的数据接下来就会存在QSerialPort的内部缓冲区中。你可以使用setReadBufferSize()方法设置缓冲区的大小。可以使用close()方法来关闭串口和取消I/O操作。
看看下面的示例:

[cpp]   view plain  copy
  1. <strong><span style="font-family:Verdana;font-size:18px;">int numRead = 0, numReadTotal = 0;  
  2. char buffer[50];  
  3.   
  4.   
  5. forever {  
  6.     numRead  = serial.read(buffer, 50);  
  7.   
  8.   
  9.     // Do whatever with the array  
  10.   
  11.   
  12.     numReadTotal += numRead;  
  13.     if (numRead == 0 && !serial.waitForReadyRead())  
  14.         break;  
  15. }</span></strong>  
         在串口连接被关闭或者出现错误的时候,waitForReadyRead()就会返回false。
         阻塞的串口编程与非阻塞的串口编程是不一样的。阻塞的串口不许要事件循环,需要的代码很少。然而,在一个GUI应用程序中,阻塞的串口操作应该仅仅在非GUI线程中使用,避免用户界面冻结。对于这一点,详细信息可以查看示例程序。
         QSerialPort类可以跟QTextStream和QDataStream的流操作一起使用(operator<<()和operator>>())。这里需要注意一件事:使用操作符operator>>()的重载函数读取之前请确保有足够的数据可用。

【QSerialPortInfo】

提供系统中已存在的串口信息。
使用该类的静态函数获取一系列的QSerialPortInfo对象。列表中的每一个QSerialPort对象都代表了一个单独的串口,可以用于获取串口名、

系统路径、描述以及制造商等信息。QSerialPortInfo类也可以作为QSerialPort类的setPort()方法的一个输入参数。

【示例】

【示例一】显示系统上可用的串口信息

示例一展示了如何使用QSerialInfo类获取系统上可用的串口,显示所有串口的信息:

【源代码】
[cpp]   view plain  copy
  1. <strong><span style="font-family:Verdana;font-size:18px;">#include <QTextStream>  
  2. #include <QCoreApplication>  
  3. #include <QtSerialPort/QSerialPortInfo>  
  4.   
  5. QT_USE_NAMESPACE  
  6.   
  7. int main(int argc, char *argv[])  
  8. {  
  9.     QCoreApplication a(argc, argv);  
  10.     QTextStream out(stdout);  
  11.     QList<QSerialPortInfo> serialPortInfoList = QSerialPortInfo::availablePorts();  
  12.   
  13.     out << QObject::tr("Total number of ports available: ") << serialPortInfoList.count() << endl;  
  14.   
  15.     foreach (const QSerialPortInfo &serialPortInfo, serialPortInfoList) {  
  16.         out << endl  
  17.             << QObject::tr("Port: ") << serialPortInfo.portName() << endl  
  18.             << QObject::tr("Location: ") << serialPortInfo.systemLocation() << endl  
  19.             << QObject::tr("Description: ") << serialPortInfo.description() << endl  
  20.             << QObject::tr("Manufacturer: ") << serialPortInfo.manufacturer() << endl  
  21.             << QObject::tr("Vendor Identifier: ") << (serialPortInfo.hasVendorIdentifier() ? QByteArray::number(serialPortInfo.vendorIdentifier(), 16) : QByteArray()) << endl  
  22.             << QObject::tr("Product Identifier: ") << (serialPortInfo.hasProductIdentifier() ? QByteArray::number(serialPortInfo.productIdentifier(), 16) : QByteArray()) << endl  
  23.             << QObject::tr("Busy: ") << (serialPortInfo.isBusy() ? QObject::tr("Yes") : QObject::tr("No")) << endl;  
  24.     }  
  25.   
  26.     return 0;  
  27. }</span></strong>  
【运行效果如下】


【示例二】:显示系统可用串口信息---图形界面版本

【源代码】:
[cpp]   view plain  copy
  1. <strong><span style="font-family:Verdana;font-size:18px;">#include <QApplication>  
  2. #include <QWidget>  
  3. #include <QVBoxLayout>  
  4. #include <QLabel>  
  5. #include <QtSerialPort/QSerialPortInfo>  
  6.   
  7. QT_USE_NAMESPACE  
  8.   
  9. int main(int argc, char *argv[])  
  10. {  
  11.     QApplication a(argc, argv);  
  12.   
  13.     QWidget w;  
  14.     w.setWindowTitle(QObject::tr("Info about all available serial ports."));  
  15.     QVBoxLayout *layout = new QVBoxLayout;  
  16.   
  17.     foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) {  
  18.         QString s = QObject::tr("Port: ") + info.portName() + "\n"  
  19.                     + QObject::tr("Location: ") + info.systemLocation() + "\n"  
  20.                     + QObject::tr("Description: ") + info.description() + "\n"  
  21.                     + QObject::tr("Manufacturer: ") + info.manufacturer() + "\n"  
  22.                     + QObject::tr("Vendor Identifier: ") + (info.hasVendorIdentifier() ? QString::number(info.vendorIdentifier(), 16) : QString()) + "\n"  
  23.                     + QObject::tr("Product Identifier: ") + (info.hasProductIdentifier() ?QString::number(info.productIdentifier(), 16) : QString()) + "\n"  
  24.                     + QObject::tr("Busy: ") + (info.isBusy() ? QObject::tr("Yes") : QObject::tr("No")) + "\n";  
  25.   
  26.         QLabel *label = new QLabel(s);  
  27.         layout->addWidget(label);  
  28.     }  
  29.   
  30.     w.setLayout(layout);  
  31.     w.show();  
  32.   
  33.     return a.exec();  
  34. }</span></strong>  
【运行的效果如下】:


【示例三】:阻塞式编程之主设备

本示例展示了如何在非GUI线程中使用QSerialPort的同步API。

QSerialPort支持两种编程方法:

*异步(非阻塞)方式。当控制权返回到Qt的事件循环中,相应的操作就会被调度和执行。当操作执行完了QSerial就会触发一个信号。例如:

QSerialPort::write()方法返回。当数据发送到串口,QSerialPort就会触发bytesWirtten()。

*同步(阻塞)方式。在非GUI和多线程应用程序中,我们可以调用waitFor...()函数(例如QSerialPort::waitForReadyRead())使得调用线程在完成之前都是阻塞的。

        在本示例中,我们展示如何使用同步的方式,在Terminal示例中展示如何使用异步方式。

         本示例的目的是向你展示一种模式:简化代码而不至于使得UI失去响应。Qt中阻塞的串口编程API可以简化代码,但是由于它的阻塞特性,所以我们必须只在非GUI线程中使用它。但是跟大多数人相反,使用QThread并不会使得你的应用程序更复杂。

         本示例是主程序,还有一个与之对应的从程序示例。主程序通过串口将请求发送给从程序并等待响应。

下面是我们定义的主线程类,它集成自QThread:

【源代码】
[cpp]   view plain  copy
  1. <strong><span style="font-family:Verdana;font-size:18px;">class MasterThread : public QThread  
  2. {  
  3.     Q_OBJECT  
  4.   
  5. public:  
  6.     MasterThread(QObject *parent = 0);  
  7.     ~MasterThread();  
  8.   
  9.     void transaction(const QString &portName, int waitTimeout, const QString &request);  
  10.     void run();  
  11.   
  12. signals:  
  13.     void response(const QString &s);  
  14.     void error(const QString &s);  
  15.     void timeout(const QString &s);  
  16.   
  17. private:  
  18.     QString portName;  
  19.     QString request;  
  20.     int waitTimeout;  
  21.     QMutex mutex;  
  22.     QWaitCondition cond;  
  23.     bool quit;  
  24. };</span></strong>  
在线程的run函数中主要就是向串口中写入数据,代码如下:
[cpp]   view plain  copy
  1. <span style="font-family:Verdana;font-size:18px;"><strong>// write request  
  2.         QByteArray requestData = currentRequest.toLocal8Bit();  
  3.         serial.write(requestData);  
  4.         if (serial.waitForBytesWritten(waitTimeout)) {  
  5.             // read response  
  6.             if (serial.waitForReadyRead(currentWaitTimeout)) {  
  7.                 QByteArray responseData = serial.readAll();  
  8.                 while (serial.waitForReadyRead(10))  
  9.                     responseData += serial.readAll();  
  10.   
  11.                 QString response(responseData);  
  12.                 emit this->response(response);  
  13.             } else {  
  14.                 emit timeout(tr("Wait read response timeout %1")  
  15.                              .arg(QTime::currentTime().toString()));  
  16.             }  
  17.         } else {  
  18.             emit timeout(tr("Wait write request timeout %1")  
  19.                          .arg(QTime::currentTime().toString()));  
  20.         }</strong></span>  

【示例四】:阻塞式编程之从设备

从程序类似上面的,就是起线程,线程从串口中读取数据:

【源代码】
[cpp]   view plain  copy
  1. <span style="font-size:14px;"> </span><span style="font-family:Verdana;font-size:18px;"><strong>      if (serial.waitForReadyRead(currentWaitTimeout)) {  
  2. //! [7] //! [8]  
  3.             // read request  
  4.             QByteArray requestData = serial.readAll();  
  5.             while (serial.waitForReadyRead(10))  
  6.                 requestData += serial.readAll();  
  7. //! [8] //! [10]  
  8.             // write response  
  9.             QByteArray responseData = currentRespone.toLocal8Bit();  
  10.             serial.write(responseData);  
  11.             if (serial.waitForBytesWritten(waitTimeout)) {  
  12.                 QString request(requestData);  
  13. //! [12]  
  14.                 emit this->request(request);  
  15. //! [10] //! [11] //! [12]  
  16.             } else {  
  17.                 emit timeout(tr("Wait write response timeout %1")  
  18.                              .arg(QTime::currentTime().toString()));  
  19.             }  
  20. //! [9] //! [11]  
  21.         } else {  
  22.             emit timeout(tr("Wait read request timeout %1")  
  23.                          .arg(QTime::currentTime().toString()));  
  24.         }</strong></span>  
【运行结果如下】:


【示例五】:非阻塞编程

       Terminal示例展示了如何使用Qt Serial Port创建简单的终端。
        本示例展示了QSerialPort类的主要特性,例如:配置,I/O实现等等。本示例也同样调用了QSerialPortInfo类获取系统中可用的串口信息。
QSerialPort支持两种基本的编程方法:
*异步(非阻塞)方式。当控制权返回到Qt的事件循环中时,操作就得以调度和执行。当操作执行完成了就会QSerialPort就会触发一个信号。例如:QSerialPort::write()函数会立即返回,而不会阻塞在写操作上。当有数据发送到串口,QSerialPort就会触发bytesWritten()信号。
*同步(阻塞)方式。在非GUI和多线程应用程序中,可以调用waitFor...()函数(例如:QSerialPort::waitForReadyRead())挂起调用线程,直到操作完成。
         在本示例中,展示异步编程方式。
示例中包含了一些GUI窗口部件:
主窗口:应用程序的主窗口,包括了串口编程的所有逻辑工作,包括配置,I/O处理等等,继承自QMainWindow。
Console:主窗口的中心部件,显示发送和接受的数据。该类继承自QPlainTextEdit类。
设置对话窗:用于配置串口的对话框,也显示了系统上可用的串口的信息。

【源代码】

本程序主要展示异步操作方式,也就是调用write和read函数,并且设置好相应的槽函数。

点击了connect菜单,就会触发如下信号-槽连接

connect(serial, SIGNAL(readyRead()), this, SLOT(readData()));
在终端上输入字符就会触发如下信号-槽连接
connect(console, SIGNAL(getData(QByteArray)), this, SLOT(writeData(QByteArray)));
[cpp]   view plain  copy
  1. <span style="font-size:14px;">/</span><span style="font-family:Verdana;font-size:18px;"><strong>/! [6]  
  2. void MainWindow::writeData(const QByteArray &data)  
  3. {  
  4.     serial->write(data);  
  5. }  
  6. //! [6]  
  7.   
  8. //! [7]  
  9. void MainWindow::readData()  
  10. {  
  11.     QByteArray data = serial->readAll();  
  12.     console->putData(data);  
  13. }  
  14. //! [7]</strong></span>  
【运行效果如下】



FROM:  http://blog.csdn.net/chenlong12580/article/details/9003139



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值