qt5.0串列埠寫資料返回為-1的問題
阿新 • • 發佈:2019-01-11
開發環境是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.
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);
遇到兩個問題,一個是串列埠開始寫資料返回為-1的問題,另一個是由於YL1和YL2輸入端功能不單一:導致回零停時或是控制停時,步進電機控制器沒有返回資料(用串列埠除錯助手不存在這個問題,我也不清楚原因),沒法保證命令是否完成,於是把輸入端改成YL3-YL13其中的任何兩個就可以。
再說寫串列埠返回為-1的問題,主要以前沒有做過串列埠通訊,對過程不是很瞭解,對qt封裝的類構造函數了解不足。其實,qt封裝的程式碼還是呼叫windows底層的東西。首先,我來申明一件事:
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()));
//訊號和槽函式關聯,當串列埠緩衝區有資料時,進行讀串列埠操作