1. 程式人生 > >qt5.0串列埠寫資料返回為-1的問題

qt5.0串列埠寫資料返回為-1的問題

 開發環境是vs2012,qt5.2.0版本。通過串列埠通訊與步進電機控制器進行互動。步進電機連線兩個電機驅動器,步進電機控制器控制兩個電機運動,正反轉,回零,執行到一定位置,控制輸入輸出停等基本操作。為了調整鏡頭和相機的距離,從而調整相機的放大倍率。兩個電機只能分時運動,兩個命令直接需要加延時,全部停除外。
       遇到兩個問題,一個是串列埠開始寫資料返回為-1的問題,另一個是由於YL1和YL2輸入端功能不單一:導致回零停時或是控制停時,步進電機控制器沒有返回資料(用串列埠除錯助手不存在這個問題,我也不清楚原因),沒法保證命令是否完成,於是把輸入端改成YL3-YL13其中的任何兩個就可以。
        再說寫串列埠返回為-1的問題,主要以前沒有做過串列埠通訊,對過程不是很瞭解,對qt封裝的類構造函數了解不足。其實,qt封裝的程式碼還是呼叫windows底層的東西。首先,我來申明一件事:
網上給的程式碼有的是有問題的
。因為,我是這麼做的,初次向串列埠寫資料返回為-1。然後我查閱很多資料,都沒有找到問題所在,後來受到一句話啟發:串列埠必須先開啟,然後在對他配置才是有效地。然後我仔細研究了原始碼,主要是Qt封裝的是有一點問題。其實,我們可以邁過這個問題,就是建構函式使用問題。
     Win_QextSerialPort();
     Win_QextSerialPort(Win_QextSerialPort const& s);
     Win_QextSerialPort(const QString & name, QextSerialBase::QueryMode mode = QextSerialBase::Polling);

     Win_QextSerialPort(const PortSettings& settings, QextSerialBase::QueryMode mode = QextSerialBase::Polling);
     Win_QextSerialPort(const QString & name, const PortSettings& settings, QextSerialBase::QueryMode mode = QextSerialBase::Polling);
    這五個建構函式第三個比較常用,我開始寫得是用的第5個,然後並沒又再次對PortSettings進行設定,所以寫資料會返回為-1.


來看看埠的open函式:

bool Win_QextSerialPort::open(OpenMode mode) {
 unsigned long confSize = sizeof(COMMCONFIG);
 Win_CommConfig.dwSize = confSize;
 DWORD dwFlagsAndAttributes = 0;
 if (queryMode() == QextSerialBase::EventDriven)
  dwFlagsAndAttributes += FILE_FLAG_OVERLAPPED;
    LOCK_MUTEX();
    if (mode == QIODevice::NotOpen)
        return isOpen();
    if (!isOpen()) {
        /*open the port*/
        Win_Handle=CreateFileA(port.toAscii(), GENERIC_READ|GENERIC_WRITE,
                              FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, dwFlagsAndAttributes, NULL);
        if (Win_Handle!=INVALID_HANDLE_VALUE) {
            /*configure port settings*/
            GetCommConfig(Win_Handle, &Win_CommConfig, &confSize);
            GetCommState(Win_Handle, &(Win_CommConfig.dcb));
            /*set up parameters*/
            Win_CommConfig.dcb.fBinary=TRUE;
            Win_CommConfig.dcb.fInX=FALSE;
            Win_CommConfig.dcb.fOutX=FALSE;
            Win_CommConfig.dcb.fAbortOnError=FALSE;
            Win_CommConfig.dcb.fNull=FALSE;
            setBaudRate(Settings.BaudRate);
            setDataBits(Settings.DataBits);
            setStopBits(Settings.StopBits);
            setParity(Settings.Parity);
            setFlowControl(Settings.FlowControl);
            setTimeout(Settings.Timeout_Millisec);
            SetCommConfig(Win_Handle, &Win_CommConfig, sizeof(COMMCONFIG));
            //init event driven approach
   if (queryMode() == QextSerialBase::EventDriven) {
          Win_CommTimeouts.ReadIntervalTimeout = MAXDWORD;
          Win_CommTimeouts.ReadTotalTimeoutMultiplier = 0;
          Win_CommTimeouts.ReadTotalTimeoutConstant = 0;
        Win_CommTimeouts.WriteTotalTimeoutMultiplier = 0;
        Win_CommTimeouts.WriteTotalTimeoutConstant = 0;
    SetCommTimeouts(Win_Handle, &Win_CommTimeouts);
             if (!SetCommMask( Win_Handle, EV_TXEMPTY | EV_RXCHAR | EV_DSR)) {
              qWarning("Failed to set Comm Mask. Error code: %ld", GetLastError());
     UNLOCK_MUTEX();
              return false;
             }
             overlapThread->start();
            }
   QIODevice::open(mode);
        }
    } else {
  UNLOCK_MUTEX();
     return false;
    }
    UNLOCK_MUTEX();
    return isOpen();
}
而其中的:             setBaudRate(Settings.BaudRate);
            setDataBits(Settings.DataBits);
            setStopBits(Settings.StopBits);
            setParity(Settings.Parity);
            setFlowControl(Settings.FlowControl);
            setTimeout(Settings.Timeout_Millisec);
這些函式只有在埠開啟的時候才會設定有效的,具體自己看程式碼。 再看建構函式裡面,if (!isOpen()) {}不開啟又進行設定,所以說開啟函式並不會PortSettings設定成功,所以在開啟之後我們要單獨對PortSettings進行設定。
     正確的寫法是,以事件驅動的為例:    
     myCom = new Win_QextSerialPort(“COM1″,QextSerialBase::EventDriven);

    //定義串列埠物件,指定串列埠名和查詢模式,這裡使用事件驅動EventDriven

    myCom ->open(QIODevice::ReadWrite);

    //以讀寫方式開啟串列埠

    myCom->setBaudRate(BAUD9600);

    //波特率設定,我們設定為9600

    myCom->setDataBits(DATA_8);

   //資料位設定,我們設定為8位資料位

    myCom->setParity(PAR_NONE);

    //奇偶校驗設定,我們設定為無校驗

    myCom->setStopBits(STOP_1);

    //停止位設定,我們設定為1位停止位

    myCom->setFlowControl(FLOW_OFF);

    //資料流控制設定,我們設定為無資料流控制

    myCom->setTimeout(500);

    //延時設定,我們設定為延時500ms,這個在Windows下好像不起作用

    connect(myCom,SIGNAL(readyRead()),this,SLOT(readMyCom()));

    //訊號和槽函式關聯,當串列埠緩衝區有資料時,進行讀串列埠操作