多線程串口編程詳解_第1頁(yè)
多線程串口編程詳解_第2頁(yè)
多線程串口編程詳解_第3頁(yè)
多線程串口編程詳解_第4頁(yè)
多線程串口編程詳解_第5頁(yè)
已閱讀5頁(yè),還剩19頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

深入淺出Win32多線程程序設(shè)計(jì)綜合實(shí)例本章我們將以工業(yè)控制和嵌入式系統(tǒng)中運(yùn)用極為廣泛的串口通信為例講述多線程的典型應(yīng)用。而網(wǎng)絡(luò)通信也是多線程應(yīng)用最廣泛的領(lǐng)域之一,所以本章的最后一節(jié)也將對(duì)多線程網(wǎng)絡(luò)通信進(jìn)行簡(jiǎn)短的描述。1?串口通信在工業(yè)控制系統(tǒng)中,工控機(jī)(一般都基于PCWindows平§§§§§本章我們將以工業(yè)控制和嵌入式系統(tǒng)中運(yùn)用極為廣泛的串口通信為例講述多線程的典型應(yīng)用。而網(wǎng)絡(luò)通信也是多線程應(yīng)用最廣泛的領(lǐng)域之一,所以本章的最后一節(jié)也將對(duì)多線程網(wǎng)絡(luò)通信進(jìn)行簡(jiǎn)短的描述。1.串口通信在工業(yè)控制系統(tǒng)中,工控機(jī)(一般都基于PCWindows平臺(tái))經(jīng)常需要與單片機(jī)通過(guò)串口進(jìn)行通信。因此,操作和使用PC的串口成為大多數(shù)單片機(jī)、嵌入式系統(tǒng)領(lǐng)域工程師必須具備的能力。串口的使用需要通過(guò)三個(gè)步驟來(lái)完成的:(1)打開通信端口;(2)初始化串口,設(shè)置波特率、數(shù)據(jù)位、停止位、奇偶校驗(yàn)等參數(shù)。為了給讀者一個(gè)直觀的印象,下圖從Windows的"控制面板一〉系統(tǒng)一〉設(shè)備管理器一〉通信端口(C0M1)"打開COM的設(shè)置窗口:(3)讀寫串口。在WIN32平臺(tái)下,對(duì)通信端口進(jìn)行操作跟基本的文件操作一樣。創(chuàng)建/打開COM資源下列函數(shù)如果調(diào)用成功,則返回一個(gè)標(biāo)識(shí)通信端口的句柄,否則返回-1HADLECreateFile(PCTSTRlpFileName,//通信端口名,如〃COM1〃WORDdwDesiredAccess,//對(duì)資源的訪問(wèn)類型WORDdwShareMode,//指定共享模式,COM不能共享,該參數(shù)為0PSECURITY_ATTRIBUTESlpSecurityAttributes,//安全描述符指針,可為NULLWORDdwCreationDisposition,//創(chuàng)建方式WORDdwFlagsAndAttributes,//文件屬性,可為NULLHANDLEhTemplateFile//模板文件句柄,置為NULL);獲得/設(shè)置COM屬性下列函數(shù)可以獲得COM口的設(shè)備控制塊,從而獲得相關(guān)參數(shù):BOOLWINAPIGetCommState(HANDLEhFile,//標(biāo)識(shí)通信端口的句柄LPDCBlpDCB//指向一個(gè)設(shè)備控制塊(DCB結(jié)構(gòu))的指針);如果要調(diào)整通信端口的參數(shù),則需要重新配置設(shè)備控制塊,再用WIN32APISetCommState()函數(shù)進(jìn)行設(shè)置:BOOLSetCommState(HANDLEhFile,//標(biāo)識(shí)通信端口的句柄LPDCBlpDCB//指向一個(gè)設(shè)備控制塊(DCB結(jié)構(gòu))的指針);DCB結(jié)構(gòu)包含了串口的各項(xiàng)參數(shù)設(shè)置,如下:typedefstruct_DCB{//dcbDWORDDCBlength;//sizeof(DCB)DWORDBaudRate;//currentbaudrateDWORDfBinary:1;//binarymode,noEOFcheckDWORDfParity:1;//enableparitycheckingDWORDfOutxCtsFlow:1;//CTSoutputflowcontrolDWORDfOutxDsrFlow:1;//DSRoutputflowcontrolDWORDfDtrControl:2;//DTRflowcontroltypeDWORDfDsrSensitivity:1;//DSRsensitivityDWORDfTXContinueOnXoff:1;//XOFFcontinuesTxDWORDfOutX:1;//XON/XOFFoutflowcontrolDWORDfInX:1;//XON/XOFFinflowcontrolDWORDfErrorChar:1;//enableerrorreplacementDWORDfNull:1;//enablenullstrippingDWORDfRtsControl:2;//RTSflowcontrolDWORDfAbortOnError:1;//abortreads/writesonerrorDWORDfDummy2:17;//reservedWORDwReserved;//notcurrentlyusedWORDXonLim;//transmitXONthresholdWORDXoffLim;//transmitXOFFthresholdBYTEByteSize;//numberofbits/byte,4-8BYTEParity;//0-4=no,odd,even,mark,spaceBYTEStopBits;//0,1,2=1,1.5,2charXonChar;//TxandRxXONcharactercharXoffChar;//TxandRxXOFFcharactercharErrorChar;//errorreplacementcharactercharEofChar;//endofinputcharactercharEvtChar;//receivedeventcharacterWORDwReserved1;//reserved;donotuse}DCB;讀寫串口在讀寫串口之前,還要用PurgeComm()函數(shù)清空緩沖區(qū),并用SetCommMask()函數(shù)設(shè)置事件掩模來(lái)監(jiān)視指定通信端口上的事件,其原型為:BOOLSetCommMask(HANDLEhFile,//標(biāo)識(shí)通信端口的句柄DWORDdwEvtMask//能夠使能的通信事件);串口上可能發(fā)生的事件如下表所示:值 事件描述EV_BREAK Abreakwasdetectedon input.EV_CTS TheCTS(clear-to-send) signal changed state.EV_DSR TheDSR(data-set-ready) signal changed state.Aline-statuserroroccurred.Line-statuserrorsareCE_FRAME,EV_ERRCE_OVERRUN,andCE_RXPARITY.EV_RINGAringindicatorwasdetected.EV_RLSDTheRLSD(receive-line-signal-detect)signalchangedstate.EV_RXCHARAcharacterwasreceivedandplacedintheinputbuffer.Theeventcharacterwasreceivedandplacedintheinputbuffer.TheEV_RXFLAGeventcharacterisspecifiedinthedevice'sDCBstructure,whichisappliedtoaserialportbyusingtheSetCommStatefunction.EV_TXEMPTYThelastcharacterintheoutputbufferwassent.在設(shè)置好事件掩模后,我們就可以利用WaitCommEvent()函數(shù)來(lái)等待串口上發(fā)生事件,其函數(shù)原型為:BOOLWaitCommEvent(HANDLEhFile,//標(biāo)識(shí)通信端口的句柄LPDWORDlpEvtMask,//指向存放事件標(biāo)識(shí)變量的指針LPOVERLAPPEDlpOverlapped,//指向overlapped結(jié)構(gòu));我們可以在發(fā)生事件后,根據(jù)相應(yīng)的事件類型,進(jìn)行串口的讀寫操作:BOOLReadFile(HANDLEhFile,//標(biāo)識(shí)通信端口的句柄LPVOIDlpBuffer,//輸入數(shù)據(jù)Buffer指針DWORDnNumberOfBytesToRead,//需要讀取的字節(jié)數(shù)LPDWORDlpNumberOfBytesRead,//實(shí)際讀取的字節(jié)數(shù)指針LPOVERLAPPEDlpOverlapped//指向overlapped結(jié)構(gòu));BOOLWriteFile(HANDLEhFile,//標(biāo)識(shí)通信端口的句柄LPCVOIDlpBuffer,//輸出數(shù)據(jù)Buffer指針DWORDnNumberOfBytesToWrite,//需要寫的字節(jié)數(shù)LPDWORDlpNumberOfBytesWritten,//實(shí)際寫入的字節(jié)數(shù)指針LPOVERLAPPEDlpOverlapped//指向overlapped結(jié)構(gòu));2.工程實(shí)例下面我們用第1節(jié)所述API實(shí)現(xiàn)一個(gè)多線程的串口通信程序。這個(gè)例子工程(工程名為MultiThreadCom)的界面很簡(jiǎn)單,如下圖所示:它是一個(gè)多線程的應(yīng)用程序,包括兩個(gè)工作者線程,分別處理串口1和串口2。為了簡(jiǎn)化問(wèn)題,我們讓連接兩個(gè)串口的電纜只包含RX、TX兩根連線(即不以硬件控制RS-232,串口上只會(huì)發(fā)生EV_TXEMPTY、EV_RXCHAR事件)。在工程實(shí)例的BOOLCMultiThreadComApp::InitInstance()函數(shù)中,啟動(dòng)并設(shè)置COM1和COM2,其源代碼為:BOOLCMultiThreadComApp::InitInstance(){AfxEnableControlContainer();//打開并設(shè)置COM1hComm1=CreateFile("COM1",GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);if(hComm1==(HANDLE)-1){AfxMessageBox("打開COM1失敗");returnfalse;}else{DCBwdcb;GetCommState(hComm1,&wdcb);wdcb.BaudRate=9600;SetCommState(hComm1,&wdcb);PurgeComm(hComm1,PURGE_TXCLEAR);}//打開并設(shè)置COM2hComm2=CreateFile("COM2",GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);if(hComm2==(HANDLE)-1){AfxMessageBox("打開COM2失敗");returnfalse;}else{DCBwdcb;GetCommState(hComm2,&wdcb);wdcb.BaudRate=9600;SetCommState(hComm2,&wdcb);PurgeComm(hComm2,PURGE_TXCLEAR);}CMultiThreadComDlgdlg;m_pMainWnd=&dlg;intnResponse=dlg.DoModal();if(nResponse==IDOK){//TODO:Placecodeheretohandlewhenthedialogis//dismissedwithOK}elseif(nResponse==IDCANCEL){//TODO:Placecodeheretohandlewhenthedialogis//dismissedwithCancel}returnFALSE;}此后我們?cè)趯?duì)話框CMultiThreadComDlg的初始化函數(shù)OnlnitDialog中啟動(dòng)兩個(gè)分別處理COM1和COM2的線程:BOOLCMultiThreadComDlg::OnInitDialog(){CDialog::OnInitDialog();//Add"About..."menuitemtosystemmenu.//IDM_ABOUTBOXmustbeinthesystemcommandrange.ASSERT((IDM_ABOUTBOX&0xFFF0)==IDM_ABOUTBOX);ASSERT(IDM_ABOUTBOX<0xF000);CMenu*pSysMenu=GetSystemMenu(FALSE);if(pSysMenu!=NULL){CStringstrAboutMenu;strAboutMenu.LoadString(IDS_ABOUTBOX);if(!strAboutMenu.IsEmpty()){pSysMenu->AppendMenu(MF_SEPARATOR);pSysMenu->AppendMenu(MF_STRING,IDM_ABOUTBOX,strAboutMenu);}}//Settheiconforthisdialog.Theframeworkdoesthisautomatically//whentheapplication'smainwindowisnotadialogSetIcon(m_hIcon,TRUE);//SetbigiconSetIcon(m_hIcon,FALSE);//Setsmallicon//TODO:Addextrainitializationhere//啟動(dòng)串口1處理線程DWORDnThreadId1;hCommThread1=::CreateThread((LPSECURITY_ATTRIBUTES)NULL,0,(LPTHREAD_START_ROUTINE)Com1ThreadProcess,AfxGetMainWnd()->m_hWnd,0,&nThreadId1);if(hCommThread1==NULL){AfxMessageBox("創(chuàng)建串口1處理線程失敗");returnfalse;}//啟動(dòng)串口2處理線程DWORDnThreadId2;hCommThread2=::CreateThread((LPSECURITY_ATTRIBUTES)NULL,0,(LPTHREAD_START_ROUTINE)Com2ThreadProcess,AfxGetMainWnd()->m_hWnd,0,&nThreadId2);if(hCommThread2==NULL){AfxMessageBox("創(chuàng)建串口2處理線程失敗");returnfalse;}returnTRUE;//returnTRUEunlessyousetthefocustoacontrol}兩個(gè)串口C0M1和COM2對(duì)應(yīng)的線程處理函數(shù)等待串口上發(fā)生事件,并根據(jù)事件類型和自身緩沖區(qū)是否有數(shù)據(jù)要發(fā)送進(jìn)行相應(yīng)的處理,其源代碼為:DWORDWINAPIComlThreadProcess(HWNDhWnd//主窗口句柄){DWORDwEven;charstr[10];//讀入數(shù)據(jù)SetCommMask(hComm1,EV_RXCHAR|EV_TXEMPTY);while(TRUE){WaitCommEvent(hComm1,&wEven,NULL);if(wEven=0){CloseHandle(hCommThread1);hCommThread1=NULL;ExitThread(0);}else{switch(wEven){caseEV_TXEMPTY:if(wTxPos<wTxLen){//在串口1寫入數(shù)據(jù)DWORDwCount;//寫入的字節(jié)數(shù)WriteFile(hComm1,com1Data.TxBuf[wTxPos],1,&wCount,NULL);com1Data.wTxPos++;}break;caseEV_RXCHAR:if(com1Data.wRxPos<com1Data.wRxLen){//讀取串口數(shù)據(jù),處理收到的數(shù)據(jù)DWORDwCount;//讀取的字節(jié)數(shù)ReadFile(hComm1,com1Data.RxBuf[wRxPos],1,&wCount,NULL);com1Data.wRxPos++;if(com1Data.wRxPos==com1Data.wRxLen);::PostMessage(hWnd,COM_SENDCHAR,0,1);}break;}}returnTRUE;}DWORDWINAPICom2ThreadProcess(HWNDhWnd//主窗口句柄){DWORDwEven;charstr[10];//讀入數(shù)據(jù)SetCommMask(hComm2,EV_RXCHAR|EV_TXEMPTY);while(TRUE){WaitCommEvent(hComm2,&wEven,NULL);if(wEven=0){CloseHandle(hCommThread2);hCommThread2=NULL;ExitThread(0);}else{switch(wEven){caseEV_TXEMPTY:if(wTxPos<wTxLen){//在串口2寫入數(shù)據(jù)DWORDwCount;//寫入的字節(jié)數(shù)WriteFile(hComm2,com2Data.TxBuf[wTxPos],1,&wCount,NULL);com2Data.wTxPos++;}break;caseEV_RXCHAR:if(com2Data.wRxPos<com2Data.wRxLen){//讀取串口數(shù)據(jù),處理收到的數(shù)據(jù)DWORDwCount;//讀取的字節(jié)數(shù)ReadFile(hComm2,com2Data.RxBuf[wRxPos],1,&wCount,NULL);com2Data.wRxPos++;if(com2Data.wRxPos==com2Data.wRxLen);::PostMessage(hWnd,COM_SENDCHAR,0,1);}break;}returnTRUE;}線程控制函數(shù)中所操作的com1Data和com2Data是與串口對(duì)應(yīng)的數(shù)據(jù)結(jié)構(gòu)structtagSerialPort的實(shí)例,這個(gè)數(shù)據(jù)結(jié)構(gòu)是:typedefstructtagSerialPort{BYTERxBuf[SPRX_BUFLEN];//接收BufferWORDwRxPos;//當(dāng)前接收字節(jié)位置WORDwRxLen;//要接收的字節(jié)數(shù)BYTETxBuf[SPTX_BUFLEN];//發(fā)送BufferWORDwTxPos;//當(dāng)前發(fā)送字節(jié)位置WORDwTxLen;//要發(fā)送的字節(jié)數(shù)}SerialPort,*LPSerialPort;3.多線程串口類使用多線程串口通信更方便的途徑是編寫一個(gè)多線程的串口類,例如RemonSpekreijse編寫了一個(gè)CSerialPort串口類。仔細(xì)分析這個(gè)類的源代碼,將十分有助于我們對(duì)先前所學(xué)多線程及同步知識(shí)的理解。類的定義#ifndef__SERIALPORT_H__#define__SERIALPORT_H__#defineWM_COMM_BREAK_DETECTEDWM_USER+1//Abreakwasdetectedoninput.#defineWM_COMM_CTS_DETECTEDWM_USER+2//TheCTS(clear-to-send)signalchangedstate.#defineWM_COMM_DSR_DETECTEDWM_USER+3//TheDSR(data-set-ready)signalchangedstate.#defineWM_COMM_ERR_DETECTEDWM_USER+4//Aline-statuserroroccurred.Line-statuserrorsareCE_FRAME,CE_OVERRUN,andCE_RXPARITY.#defineWM_COMM_RING_DETECTEDWM_USER+5//Aringindicatorwasdetected.#defineWM_COMM_RLSD_DETECTEDWM_USER+6//TheRLSD(receive-line-signal-detect)signalchangedstate.#defineWM_COMM_RXCHARWM_USER+7//Acharacterwasreceivedandplacedintheinputbuffer.#defineWM_COMM_RXFLAG_DETECTEDWM_USER+8//Theeventcharacterwasreceivedandplacedintheinputbuffer.#defineWM_COMM_TXEMPTY_DETECTEDWM_USER+9//Thelastcharacterintheoutputbufferwassent.classCSerialPort{public://contructionanddestructionCSerialPort();virtual~CSerialPort();//portinitialisationBOOLInitPort(CWnd*pPortOwner,UINTportnr=1,UINTbaud=19200,charparity='N',UINTdatabits=8,UINTstopsbits=1,DWORDdwCommEvents=EV_RXCHAR|EV_CTS,UINTnBufferSize=512);//start/stopcommwatchingBOOLStartMonitoring();BOOLRestartMonitoring();BOOLStopMonitoring();DWORDGetWriteBufferSize();DWORDGetCommEvents();DCBGetDCB();voidWriteToPort(char*string);protected://protectedmemberfunctionsvoidProcessErrorMessage(char*ErrorText);staticUINTCommThread(LPVOIDpParam);staticvoidReceiveChar(CSerialPort*port,COMSTATcomstat);staticvoidWriteChar(CSerialPort*port);//threadCWinThread*m_Thread;//synchronisationobjectsCRITICAL_SECTIONm_csCommunicationSync;BOOLm_bThreadAlive;//handlesHANDLEm_hShutdownEvent;HANDLEm_hComm;HANDLEm_hWriteEvent;//Eventarray.//Oneelementisusedforeachevent.Therearetwoeventhandlesforeachport.//AWriteeventandareceivecharactereventwhichislocatedintheoverlappedstructure(m_ov.hEvent).//Thereisageneralshutdownwhentheportisclosed.HANDLEm_hEventArray[3];//structuresOVERLAPPEDm_ov;COMMTIMEOUTSm_CommTimeouts;DCBm_dcb;//ownerwindowCWnd*m_pOwner;§//miscUINTm_nPortNr;char*m_szWriteBuffer;DWORDm_dwCommEvents;DWORDm_nWriteBufferSize;};#endif__SERIALPORT_H__類的實(shí)現(xiàn)3.2.1構(gòu)造函數(shù)與析構(gòu)函數(shù)進(jìn)行相關(guān)變量的賦初值及內(nèi)存恢復(fù):CSerialPort::CSerialPort(){m_hComm=NULL;//initializeoverlappedstructurememberstozerom_ov.Offset=0;m_ov.OffsetHigh=0;//createeventsm_ov.hEvent=NULL;m_hWriteEvent=NULL;m_hShutdownEvent=NULL;m_szWriteBuffer=NULL;m_bThreadAlive=FALSE;}////Deletedynamicmemory//CSerialPort::~CSerialPort(){do{SetEvent(m_hShutdownEvent);}while(m_bThreadAlive);TRACE("Threadended");delete[]m_szWriteBuffer;}核心函數(shù):初始化串口在初始化串口函數(shù)中,將打開串口,設(shè)置相關(guān)參數(shù),并創(chuàng)建串口相關(guān)的用戶控制事件,初始化臨界區(qū)(CriticalSection),以成隊(duì)的EnterCriticalSection()、LeaveCriticalSection()函數(shù)進(jìn)行資源的排它性訪問(wèn):BOOLCSerialPort::InitPort(CWnd*pPortOwner,//theowner(CWnd)oftheport(receivesmessage)UINTportnr,//portnumber(1..4)UINTbaud,//baudratecharparity,//parityUINTdatabits,//databitsUINTstopbits,//stopbitsDWORDdwCommEvents,//EV_RXCHAR,EV_CTSetcUINTwritebuffersize)//sizetothewritebuffer{assert(portnr>0&&portnr<5);assert(pPortOwner!=NULL);//ifthethreadisalive:Killif(m_bThreadAlive){do{SetEvent(m_hShutdownEvent);}while(m_bThreadAlive);TRACE("Threadended");}//createeventsif(m_ov.hEvent!=NULL)ResetEvent(m_ov.hEvent);m_ov.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);if(m_hWriteEvent!=NULL)ResetEvent(m_hWriteEvent);m_hWriteEvent=CreateEvent(NULL,TRUE,FALSE,NULL);if(m_hShutdownEvent!=NULL)ResetEvent(m_hShutdownEvent);m_hShutdownEvent=CreateEvent(NULL,TRUE,FALSE,NULL);//initializetheeventobjectsm_hEventArray[0]=m_hShutdownEvent;//highestprioritym_hEventArray[1]=m_ov.hEvent;m_hEventArray[2]=m_hWriteEvent;//initializecriticalsectionInitializeCriticalSection(&m_csCommunicationSync);//setbuffersizeforwritingandsavetheowner

m_pOwner=pPortOwner;if(m_szWriteBuffer!=NULL)delete[]m_szWriteBuffer;m_szWriteBuffer=newchar[writebuffersize];m_nPortNr=portnr;m_nWriteBufferSize=writebuffersize;m_dwCommEvents=dwCommEvents;BOOLbResult=FALSE;char*szPort=newchar[50];char*szBaud=newchar[50];//nowitcritical!EnterCriticalSection(&m_csCommunicationSync);//iftheportisalreadyopened:closeit§if(m_hComm!=NULL){CloseHandle(m_hComm);m_hComm=NULL;}parity,//prepareportstringssprintf(szPort,"COM%d",portnr);sprintf(szBaud,"baud=%dparity=%cdata=%dstop=%d",baud,databits,stopbits);parity,//getahandletotheportm_hComm=CreateFile(szPort,//communicationportstring(COMX)GENERIC_READ|GENERIC_WRITE,//read/writetypes0,//commdevicesmustbeopenedwithexclusiveaccessNULL,//nosecurityattributesOPEN_EXISTING,//commdevicesmustuseOPEN_EXISTINGFILE_FLAG_OVERLAPPED,//AsyncI/O0);//templatemustbe0forcommdevicesif(m_hComm==INVALID_HANDLE_VALUE){//portnotfounddelete[]szPort;delete[]szBaud;returnFALSE;}//setthetimeoutvaluesm_CommTimeouts.ReadIntervalTimeout=1000;m_CommTimeouts.ReadTotalTimeoutMultiplier=1000;m_CommTimeouts.ReadTotalTimeoutConstant=1000;m_CommTimeouts.WriteTotalTimeoutMultiplier=1000;m_CommTimeouts.WriteTotalTimeoutConstant=1000;//configureif(SetCommTimeouts(m_hComm,&m_CommTimeouts)){if(SetCommMask(m_hComm,dwCommEvents)){if(GetCommState(m_hComm,&m_dcb)){m_dcb.fRtsControl=RTS_CONTROL_ENABLE;//setRTSbithigh!if(BuildCommDCB(szBaud,&m_dcb)){if(SetCommState(m_hComm,&m_dcb))//normaloperation...continueelseProcessErrorMessage("SetCommState()");}elseProcessErrorMessage("BuildCommDCB()");}elseProcessErrorMessage("GetCommState()");}elseProcessErrorMessage("SetCommMask()");}elseProcessErrorMessage("SetCommTimeouts()");delete[]szPort;delete[]szBaud;//flushtheportPurgeComm(m_hComm,PURGE_RXCLEAR|PURGE_TXCLEAR|PURGE_RXABORT|PURGE_TXABORT);//releasecriticalsectionLeaveCriticalSection(&m_csCommunicationSync);TRACE("Initialisationforcommunicationport%dcompleted.UseStartmonitortocommunicate.",portnr);returnTRUE;}核心函數(shù):串口線程控制函數(shù)串口線程處理函數(shù)是整個(gè)類中最核心的部分,它主要完成兩類工作:(1)利用WaitCommEvent函數(shù)對(duì)串口上發(fā)生的事件進(jìn)行獲取并根據(jù)事件的不同類型進(jìn)行相應(yīng)的處理;(2)利用WaitForMultipleObjects函數(shù)對(duì)串口相關(guān)的用戶控制事件進(jìn)行等待并做相應(yīng)處理。UINTCSerialPort::CommThread(LPVOIDpParam){//Castthevoidpointerpassedtothethreadbackto//apointerofCSerialPortclassCSerialPort*port=(CSerialPort*)pParam;//Setthestatusvariableinthedialogclassto//TRUEtoindicatethethreadisrunning.port->m_bThreadAlive=TRUE;//Misc.variablesDWORDBytesTransfered=0;DWORDEvent=0;DWORDCommEvent=0;DWORDdwError=0;COMSTATcomstat;BOOLbResult=TRUE;//Clearcommbuffersatstartupif(port->m_hComm)//checkiftheportisopenedPurgeComm(port->m_hComm,PURGE_RXCLEAR|PURGE_TXCLEAR|PURGE_RXABORT|PURGE_TXABORT);//beginforeverloop.Thisloopwillrunaslongasthethreadisalive.for(;;){//MakeacalltoWaitCommEvent().Thiscallwillreturnimmediatly//becauseourportwascreatedasanasyncport(FILE_FLAG_OVERLAPPED//andanm_OverlappedStructerlappedstructurespecified).Thiscallwillcausethe//m_OverlappedStructerlappedelementm_OverlappedStruct.hEvent,whichispartofthem_hEventArrayto//beplacedinanon-signeledstateiftherearenobytesavailabletoberead,//ortoasigneledstateiftherearebytesavailable.Ifthiseventhandle//issettothenon-signeledstate,itwillbesettosigneledwhena//characterarrivesattheport.//wedothisforeachport!bResult=WaitCommEvent(port->m_hComm,&Event,&port->m_ov);if(!bResult){//IfWaitCommEvent()returnsFALSE,processthelasterrortodetermin//thereason..switch(dwError=GetLastError()){caseERROR_IO_PENDING:{//Thisisanormalreturnvalueiftherearenobytes//toreadattheport.//Donothingandcontinuebreak;}case87:{//UnderWindowsNT,thisvalueisreturnedforsomereason.//Ihavenotinvestigatedwhy,butitisalsoavalidreply//Alsodonothingandcontinue.break;}default:{//Allothererrorcodesindicateaseriouserrorhas//occured.Processthiserror.port->ProcessErrorMessage("WaitCommEvent()");break;}}}else{//IfWaitCommEvent()returnsTRUE,checktobesurethereare//actuallybytesinthebuffertoread.////Ifyouarereadingmorethanonebyteatatimefromthebuffer//(whichthisprogramdoesnotdo)youwillhavethesituationoccur//wherethefirstbytetoarrivewillcausetheWaitForMultipleObjects()//functiontostopwaiting.TheWaitForMultipleObjects()function//resetstheeventhandleinm_OverlappedStruct.hEventtothenon-signeleadstate//asitreturns.////Ifinthetimebetweentheresetofthiseventandthecallto//ReadFile()morebytesarrive,them_OverlappedStruct.hEventhandlewillbesetagain//tothesigneledstate.WhenthecalltoReadFile()occurs,itwill//readallofthebytesfromthebuffer,andtheprogramwill//loopbackaroundtoWaitCommEvent().////Atthispointyouwillbeinthesituationwherem_OverlappedStruct.hEventisset,//buttherearenobytesavailabletoread.Ifyouproceedandcall//ReadFile(),itwillreturnimmediatlyduetotheasyncportsetup,but//GetOverlappedResults()willnotreturnuntilthenextcharacterarrives.////ItisnotdesirablefortheGetOverlappedResults()functiontobein//thisstate.Thethreadshutdownevent(event0)andtheWriteFile()//event(Event2)willnotworkifthethreadisblockedbyGetOverlappedResults().////ThesolutiontothisistocheckthebufferwithacalltoClearCommError().//Thiscallwillresettheeventhandle,andiftherearenobytestoread//wecanloopbackthroughWaitCommEvent()again,thenproceed.//Iftherearereallybytestoread,donothingandproceed.bResult=ClearCommError(port->m_hComm,&dwError,&comstat);if(comstat.cbInQue==0)continue;}//endifbResult//Mainwaitfunction.Thisfunctionwillnormallyblockthethread//untiloneofnineeventsoccurthatrequireaction.Event=WaitForMultipleObjects(3,port->m_hEventArray,FALSE,INFINITE);switch(Event){case0:{//Shutdownevent.Thisiseventzerosoitwillbe//thehigestpriorityandbeservicedfirst.port->m_bThreadAlive=FALSE;//Killthisthread.breakisnotneeded,butmakesmefeelbetter.AfxEndThread(100);break;}case1://readevent{GetCommMask(port->m_hComm,&CommEvent);if(CommEvent&EV_CTS)::SendMessage(port->m_pOwner->m_hWnd,WM_COMM_CTS_DETECTED,(WPARAM)0,(LPARAM)port->m_nPortNr);if(CommEvent&EV_RXFLAG)::SendMessage(port->m_pOwner->m_hWnd,WM_COMM_RXFLAG_DETECTED,(WPARAM)0,(LPARAM)port->m_nPortNr);if(CommEvent&EV_BREAK)::SendMessage(port->m_pOwner->m_hWnd,WM_COMM_BREAK_DETECTED,(WPARAM)0,(LPARAM)port->m_nPortNr);if(CommEvent&EV_ERR)::SendMessage(port->m_pOwner->m_hWnd,WM_COMM_ERR_DETECTED,(WPARAM)0,(LPARAM)port->m_nPortNr);if(CommEvent&EV_RING)::SendMessage(port->m_pOwner->m_hWnd,WM_COMM_RING_DETECTED,(WPARAM)0,(LPARAM)port->m_nPortNr);if(CommEvent&EV_RXCHAR)//Receivecharactereventfromport.ReceiveChar(port,comstat);break;}case2://writeevent{//WritecharactereventfromportWriteChar(port);break;}}//endswitch}//closeforeverloopreturn0;}下列三個(gè)函數(shù)用于對(duì)串口線程進(jìn)行啟動(dòng)、掛起和恢復(fù):////startcommwatching//BOOLCSerialPort::StartMonitoring(){if(!(m_Thread=AfxBeginThread(CommThread,this)))returnFALSE;TRACE("Threadstarted");returnTRUE;}////Restartthecommthread//BOOLCSerialPort::RestartMonitoring(){TRACE("Threadresumed");m_Thread->ResumeThread();returnTRUE;}////Suspendthecommthread//BOOLCSerialPort::StopMonitoring(){TRACE("Threadsuspended");m_Thread->SuspendThread();returnTRUE;}讀寫串口下面一組函數(shù)是用戶對(duì)串口進(jìn)行讀寫操作的接口:////Writeacharacter.//voidCSerialPort::WriteChar(CSerialPort*port){BOOLbWrite=TRUE;BOOLbResult=TRUE;DWORDBytesSent=0;ResetEvent(port->m_hWriteEvent);//GainownershipofthecriticalsectionEnterCriticalSection(&port->m_csCommunicationSync);if(bWrite){//Initailizevariablesport->m_ov.Offset=0;port->m_ov.OffsetHigh=0;//ClearbufferPurgeComm(port->m_hComm,PURGE_RXCLEAR|PURGE_TXCLEAR|PURGE_RXABORT|PURGE_TXABORT);bResult=WriteFile(port->m_hComm,//HandletoCOMMPortport->m_szWriteBuffer,//Pointertomessagebufferincallingfinctionstrlen((char*)port->m_szWriteBuffer),//Lengthofmessagetosend&BytesSent,//Wheretostorethenumberofbytessent&port->m_ov);//Overlappedstructure//dealwithanyerrorcodesif(!bResult){DWORDdwError=GetLastError();switch(dwError){caseERROR_IO_PENDING:{//continuetoGetOverlappedResults()BytesSent=0;bWrite=FALSE;break;}default:{//allothererrorcodesport->ProcessErrorMessage("WriteFile()");}}}else{LeaveCriticalSection(&port->m_csCommunicationSync);}}//endif(bWrite)if(!bWrite){bWrite=TRUE;bResult=GetOverlappedResult(port->m_hComm,//HandletoCOMMport&port->m_ov,//Overlappedstructure&BytesSent,//StoresnumberofbytessentTRUE);//WaitflagLeaveCriticalSection(&port->m_csCommunicationSync);//dealwiththeerrorcodeif(!bResult){port->ProcessErrorMessage("GetOverlappedResults()inWriteFile()");}}//endif(!bWrite)//Verifythatthedatasizesendequalswhatwetriedtosendif(BytesSent!=strlen((char*)port->m_szWriteBuffer)){TRACE("WARNING:WriteFile()error..BytesSent:%d;MessageLength:%d〃BytesSent,strlen((char*)port->m_szWriteBuffer));}}////Characterreceived.Informtheowner//voidCSerialPort::ReceiveChar(CSerialPort*port,COMSTATcomstat){BOOLbRead=TRUE;BOOLbResult=TRUE;DWORDdwError=0;DWORDBytesRead=0;unsignedcharRXBuff;for(;;){//Gainownershipofthecommportcriticalsection.//Thisprocessguaranteesnootherpartofthisprogram//isusingtheportobject.EnterCriticalSection(&port->m_csCommunicationSync);//ClearCommError()willupdatetheCOMSTATstructureand//clearanyothererrors.bResult=ClearCommError(port->m_hComm,&dwError,&comstat);LeaveCriticalSection(&port->m_csCommunicationSync);//startforeverloop.IusethistypeofloopbecauseI//donotknowatruntimehowmanyloopsthiswillhaveto//run.Mysolutionistostartaforeverloopandto//breakoutofitwhenIhaveprocessedallofthe//dataavailable.Becarefulwiththisapproachand//besureyourloopwillexit.//Myreasonsforthisarenotasclearinthissample//asitisinmyproductioncode,butIhavefoundthis//solutiiontobethemostefficientwaytodothis.if(comstat.cbInQue==0){//breakoutwhenallbyteshavebeenreadbreak;}EnterCriticalSection(&port->m_csCommunicationSync);if(bRead){bResult=ReadFile(port->m_hComm,//HandletoCOMMport&RXBuff,//RXBufferPointer1,//Readonebyte&BytesRead,//Storesnumberofbytesread&port->m_ov);//pointertothem_ovstructure//dealwiththeerrorcodeif(!bResult){switch(dwError=GetLastError()){caseERROR_IO_PENDING:{//asynchronousi/oisstillinprogress//ProceedontoGetOverlappedResults();bRead=FALSE;break;}default:{//Anothererrorhasoccured.Processthiserror.port->ProcessErrorMessage("ReadFile()");break;}}}else{//ReadFile()returnedcomplete.ItisnotnecessarytocallGetOverlappedResults()bRead=TRUE;}}//closeif

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論