现在的位置: 首页 > 自动控制 > 工业·编程 > 正文

QT串口通信之自己写串口类

2014-04-30 06:05 工业·编程 ⁄ 共 6051字 ⁄ 字号 暂无评论

最近在研究基于QT的串口通信程序。下载了别人写的第三方类,但是感觉看得不是很懂,另外跟我想象中的事件驱动有些区别。因此自己尝试着写了一个基于WIN2api的串口类。经过调试发现性能很不错,贴出来给大家看看。

本类只包含一个H文件和一个CPP文件,应用时只要包含该H文件即可,H文件中只有一个类KQSP,只要实例化该类的对象就可以了。

下边贴出H文件的源代码:

#ifndef KQSP_H 

#define KQSP_H 

#include    <QtCore> 

#include    <qt_windows.h> 

/*

class THRD : public QThread

{

Q_OBJECT

public:

KQSPTHRD();

   ~KQSPTHRD();

public:

  

void run()

{

  listen.setInterval(0);

  QObject::connect(&listen,SIGNAL(timeout()),&P,SLOT(Monitor()));

  listen.start();

  exec();

}

};

*/ 

  

class KQSP : public QIODevice 

    Q_OBJECT 

public: 

    KQSP();                                                 //CONSTRUCTION 

//  ~KQSP();                                                    //FINALIZE 

public: 

    bool            open();                                 //open the port 

    void            close();                                //close the port 

    qint64          readData(char *buf,qint64 count);       //overwrit 

    qint64          writeData(const char* buf,qint64 count);//overwrit 

    void            write(); 

private: 

    DWORD           BAUD;                                   //baudrate 

    DWORD           EVTG;                                   //EVTigger 

    DWORD           WCNT; 

    HANDLE          HCOM;                                   //Handle of port 

  

    OVERLAPPED      OV; 

    COMMTIMEOUTS    TimeOuts; 

    DCB             dcb; 

public: 

    BYTE            TXBF[100]; 

    BYTE            RXBF[100];                               //RXBUF 

    

    QTimer          LTMR; 

    QThread         THRD; 

signals: 

    void            DT_RDVD();                              //Data recived 

public slots: 

    void            ON_CHEK();                              //checking the ev_rxchar 

    void            ON_WRIT();                              //to write to the port 

}; 

  

#endif // KQSP_H 

类中的方法和属性都很简单:open方法负责打开端口,这个方法已经包含进构造函数,不需要主动调用;write方法就是写,但是我是通过信号来调用的。因为本类一般工作在第二线程,不同线程之间无法直接调用方法。BAUD就是波特率。

接下来是我们的CPP文件:

#include "KQSP.h" 

  

KQSP::KQSP() 

    this->moveToThread(&THRD); 

    LTMR.setInterval(0); 

  

    BAUD = BAUD_9600; 

    EVTG = 0; 

    WCNT = 10; 

    memset(TXBF,0x00,100); 

    memset(RXBF,0x00,100); 

  

    open(); 

  

    TimeOuts.ReadIntervalTimeout = MAXDWORD; 

    TimeOuts.ReadTotalTimeoutMultiplier = 0; 

    TimeOuts.ReadTotalTimeoutConstant= 100; 

    TimeOuts.WriteTotalTimeoutMultiplier= 0; 

    TimeOuts.WriteTotalTimeoutConstant= 100; 

    SetCommTimeouts(HCOM,&TimeOuts); 

  

    SetupComm(HCOM,2048,2048);//HUANCHONG 

    GetCommState(HCOM,&dcb); 

    dcb.BaudRate = 57600; //波特率为9600 

    dcb.ByteSize = 8; //每个字节有8位 

    dcb.Parity = NOPARITY; //无奇偶校验位 

    dcb.StopBits = ONESTOPBIT; //1个停止位 

    SetCommState (HCOM,&dcb); 

  

    // Initialize the rest of the OVERLAPPED structure to zero. 

    OV.Internal = 0; 

    OV.InternalHigh = 0; 

    OV.Offset = 0; 

    OV.OffsetHigh = 0; 

    OV.hEvent = CreateEvent(NULL,   // default security attributes 

                            TRUE,   // manual-reset event 

                            FALSE,  // not signaled 

                            NULL    // no name 

                            ); 

  

    SetCommMask(HCOM,EV_RXCHAR); 

  

    QObject::connect(&LTMR,SIGNAL(timeout()),this,SLOT(ON_CHEK())); 

    LTMR.start(); 

/*

KQSP::~KQSP()

{

    //close();

}

*/ 

bool KQSP::open() 

    HCOM = CreateFileA("COM1", 

                        GENERIC_READ | GENERIC_WRITE, 

                        0, 

                        0, 

                        OPEN_EXISTING, 

                        FILE_FLAG_OVERLAPPED, 

                        NULL); 

  

    if(INVALID_HANDLE_VALUE == HCOM) 

        return false; 

    else 

        return true; 

  

void KQSP::close() 

    THRD.quit(); 

    CloseHandle(HCOM); 

  

void KQSP::ON_WRIT() 

    write(); 

  

void KQSP::write() 

    DWORD X = GetLastError(); 

    if(X != 0) 

        return; 

    PurgeComm(HCOM,PURGE_TXCLEAR | PURGE_TXABORT | PURGE_RXABORT | PURGE_RXCLEAR ); 

    WriteFile(HCOM,TXBF,9,NULL,&OV); 

    WaitCommEvent(HCOM,&EVTG,&OV); 

  

void KQSP::ON_CHEK() 

    if(EVTG & EV_RXCHAR) 

    { 

        memset(RXBF,0x00,100); 

        bool x =ReadFile(HCOM,RXBF,100,NULL,&OV); 

  

        if(!x) 

        { 

            WaitForSingleObject(HCOM,100); 

        } 

//      DWORD T = GetLastError(); 

        PurgeComm(HCOM,PURGE_TXCLEAR | PURGE_TXABORT | PURGE_RXABORT | PURGE_RXCLEAR ); 

        EVTG = 0; 

  

        emit DT_RDVD(); 

    } 

    

qint64  KQSP::readData(char *buf,qint64 count) 

    return 0; 

  

qint64  KQSP::writeData(const char* buf,qint64 count) 

    return 0; 

程序都非常简单,一目了然。

必须指出本程序的多线程方式从性能上讲应该是第二选择:最佳的方式应该是重写qiodevice的exec方法,类似于.NET中的重写wndproc方法,这样可以利用QT自身的消息循环来做监听。但是不知为何在网上搜索没有发现这个结果,我也没有去尝试。有兴趣的可以去试一下。我用的方法是在第二线程中使用一个间隔为0的定时器实现了无限循环的方法。

接下来是利用这个类进行收发的1个例子。

#ifndef MAINWINDOW_H 

#define MAINWINDOW_H 

#include "KQSP.h" 

#include <QMainWindow> 

  

namespace Ui { 

    class MainWindow; 

  

class MainWindow : public QMainWindow 

    Q_OBJECT 

  

public: 

    explicit MainWindow(QWidget *parent = 0); 

    ~MainWindow(); 

    KQSP    PORT; 

private: 

    Ui::MainWindow *ui; 

signals: 

    void LS_STOP(); 

    void LS_GOON(); 

    void WT_REDY(); 

private slots: 

    void on_pushButton_1_clicked(); 

    void on_pushButton_2_clicked(); 

    void on_pushButton_3_clicked(); 

    void ON_DT_RCVD(); 

}; 

  

#endif // MAINWINDOW_H 

#include "mainwindow.h" 

#include "ui_mainwindow.h" 

  

MainWindow::MainWindow(QWidget *parent) : 

    QMainWindow(parent), 

    ui(new Ui::MainWindow) 

    ui->setupUi(this); 

  

    QObject::connect(&PORT,SIGNAL(DT_RDVD()),this,SLOT(ON_DT_RCVD())); 

    QObject::connect(this,SIGNAL(LS_STOP()),&PORT.LTMR,SLOT(stop())); 

    QObject::connect(this,SIGNAL(LS_GOON()),&PORT.LTMR,SLOT(start())); 

    QObject::connect(this,SIGNAL(WT_REDY()),&PORT,SLOT(ON_WRIT())); 

  

    PORT.THRD.start(); 

  

MainWindow::~MainWindow() 

    delete ui; 

  

void MainWindow::on_pushButton_1_clicked() 

    emit LS_STOP(); 

    ui->pushButton_3->setText("TMSTOP_SEND"); 

  

void MainWindow::on_pushButton_2_clicked() 

    emit LS_GOON(); 

    ui->pushButton_3->setText("TMGOON_SEND"); 

  

void MainWindow::on_pushButton_3_clicked() 

    BYTE temp[10] = {0xbb,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0xdf,0x00}; 

    memcpy(PORT.TXBF,temp,10); 

    emit WT_REDY(); 

void MainWindow::ON_DT_RCVD() 

    emit LS_STOP(); 

    QString temp; 

    int i = 0; 

    for(i = 0;i < 20;i++) 

    { 

  

        temp.setNum(PORT.RXBF[i]); 

        ui->textBrowser->append(temp); 

        //ui->textBrowser->append(" "); 

    } 

    emit LS_GOON(); 

好了以上就是我的串口类。enjoy qt!

来源

给我留言

留言无头像?