• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            Xiao.Zhu C++

            Xiao.Zhu C++

              C++博客 :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
              29 隨筆 :: 14 文章 :: 17 評(píng)論 :: 0 Trackbacks

             

            無(wú)論那種操作方式,一般都通過(guò)四個(gè)步驟來(lái)完成:
            1打開(kāi)串口

            Win32系統(tǒng)把文件的概念進(jìn)行了擴(kuò)展。無(wú)論是文件、通信設(shè)備、命名管道、郵件槽、磁盤、還是控制臺(tái),都是用API函數(shù)CreateFile來(lái)打開(kāi)或創(chuàng)建的。該函數(shù)的原型為:

            HANDLE CreateFile( LPCTSTR lpFileName, 
                            
            DWORD dwDesiredAccess,  
                           
            DWORD dwShareMode,    
                          
            LPSECURITY_ATTRIBUTES lpSecurityAttributes, 
                          
            DWORD dwCreationDistribution,
                           DWORD dwFlagsAndAttributes,
                           HANDLE hTemplateFile);

            ·           lpFileName:將要打開(kāi)的串口邏輯名,如“COM1”

            ·           dwDesiredAccess:指定串口訪問(wèn)的類型,可以是讀取、寫入或二者并列;

            ·           dwShareMode:指定共享屬性,由于串口不能共享,該參數(shù)必須置為0

            ·           lpSecurityAttributes:引用安全性屬性結(jié)構(gòu),缺省值為NULL

            ·           dwCreationDistribution:創(chuàng)建標(biāo)志,對(duì)串口操作該參數(shù)必須置為OPEN_EXISTING

            ·           dwFlagsAndAttributes:屬性描述,用于指定該串口是否進(jìn)行異步操作,該值為FILE_FLAG_OVERLAPPED,表示使用異步的I/O;該值為0,表示同步I/O操作;

            ·           hTemplateFile:對(duì)串口而言該參數(shù)必須置為NULL

            同步I/O方式打開(kāi)串口的示例代碼:

            HANDLE hCom; //全局變量,串口句柄
            hCom=CreateFile("COM1",//COM1         
              
            GENERIC_READ|GENERIC_WRITE, //
            允許讀和寫         
                
            0, //
            獨(dú)占方式         
             
                  NULL,   
                
            OPEN_EXISTING, //
            打開(kāi)而不是創(chuàng)建             
              
               0, //
            同步方式       
              
            NULL);    
            if(hCom==(HANDLE)-1)  
            {              
                     AfxMessageBox("
            打開(kāi)COM失敗!");    
               
                 return FALSE; 
            }  
                
            return TRUE;

            重疊I/O打開(kāi)串口的示例代碼:

            HANDLE hCom; //全局變量,串口句柄 
            hCom =CreateFile("COM1", //COM1
                      
              
            GENERIC_READ|GENERIC_WRITE, //
            允許讀和寫     
                   
            0, //
            獨(dú)占方式            
                   
            NULL,           
              
               OPEN_EXISTING, //
            打開(kāi)而不是創(chuàng)建       
              
                FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, //
            重疊方式 
                 
            NULL);
             
            if(hCom ==INVALID_HANDLE_VALUE)     
            {           
                      
            AfxMessageBox("
            打開(kāi)COM失敗!"); 
                      
            return FALSE; 
            }        
             
            return TRUE;

            2)、配置串口

            在打開(kāi)通訊設(shè)備句柄后,常常需要對(duì)串口進(jìn)行一些初始化配置工作。這需要通過(guò)一個(gè)DCB結(jié)構(gòu)來(lái)進(jìn)行。DCB結(jié)構(gòu)包含了諸如波特率、數(shù)據(jù)位數(shù)、奇偶校驗(yàn)和停止位數(shù)等信息。在查詢或配置串口的屬性時(shí),都要用DCB結(jié)構(gòu)來(lái)作為緩沖區(qū)。
              一般用CreateFile打開(kāi)串口后,可以調(diào)用GetCommState函數(shù)來(lái)獲取串口的初始配置。要修改串口的配置,應(yīng)該先修改DCB結(jié)構(gòu),然后再調(diào)用SetCommState函數(shù)設(shè)置串口。
              DCB結(jié)構(gòu)包含了串口的各項(xiàng)參數(shù)設(shè)置,下面僅介紹幾個(gè)該結(jié)構(gòu)常用的變量:

            typedef struct _DCB{ 
             
            ………   //
            波特率,指定通信設(shè)備的傳輸速率。這個(gè)成員可以是實(shí)際波特率值或者下面的常量值之一:
               DWORD BaudRate;
            CBR_110

            CBR_300
            CBR_600
            CBR_1200
            CBR_2400
            CBR_4800

            CBR_9600
            CBR_19200
            CBR_38400
            CBR_56000
            CBR_57600
            CBR_115200

            CBR_128000

            CBR_256000

            CBR_14400DWORD fParity; //
            指定奇偶校驗(yàn)使能。若此成員為1,允許奇偶校驗(yàn)檢查   
            …BYTE ByteSize; //
            通信字節(jié)位數(shù),4—8BYTE
            Parity; //
            指定奇偶校驗(yàn)方法。此成員可以有下列值:EVENPARITY 偶校驗(yàn)     NOPARITY 無(wú)校驗(yàn)MARKPARITY 標(biāo)記校驗(yàn)   ODDPARITY 奇校驗(yàn)BYTE
            StopBits; //
            指定停止位的位數(shù)。
            此成員可以有下列值:
            ONESTOPBIT 1位停止位  
            TWOSTOPBITS 2
            位停止位
            ONE5STOPBITS   1.5
            位停止位   ……… } DCB;
            winbase.h
            文件中定義了以上用到的常量。
            如下:
            #define NOPARITY            0
            #define ODDPARITY           1
            #define EVENPARITY          2
            #define ONESTOPBIT          0
            #define ONE5STOPBITS        1
            #define TWOSTOPBITS         2
            #define CBR_110             110
            #define CBR_300             300
            #define CBR_600             600
            #define CBR_1200            1200
            #define CBR_2400            2400
            #define CBR_4800            4800
            #define CBR_9600            9600
            #define CBR_14400           14400
            #define CBR_19200           19200
            #define CBR_38400           38400
            #define CBR_56000           56000
            #define CBR_57600           57600
            #define CBR_115200          115200
            #define CBR_128000          128000
            #define CBR_256000          256000

            GetCommState函數(shù)可以獲得COM口的設(shè)備控制塊,從而獲得相關(guān)參數(shù):

            BOOL GetCommState(   HANDLE hFile, //標(biāo)識(shí)通訊端口的句柄  
            LPDCB lpDCB //
            指向一個(gè)設(shè)備控制塊(DCB結(jié)構(gòu))的指針 );
            SetCommState
            函數(shù)設(shè)置COM口的設(shè)備控制塊:
            BOOL SetCommState(   HANDLE hFile,    LPDCB lpDCB   );

            除了在BCD中的設(shè)置外,程序一般還需要設(shè)置I/O緩沖區(qū)的大小和超時(shí)。WindowsI/O緩沖區(qū)來(lái)暫存串口輸入和輸出的數(shù)據(jù)。如果通信的速率較高,則應(yīng)該設(shè)置較大的緩沖區(qū)。調(diào)用SetupComm函數(shù)可以設(shè)置串行口的輸入和輸出緩沖區(qū)的大小。

            BOOL SetupComm(    HANDLE hFile,    // 通信設(shè)備的句柄    
            DWORD dwInQueue, //
            輸入緩沖區(qū)的大小(字節(jié)數(shù))    
            DWORD dwOutQueue   //
            輸出緩沖區(qū)的大小(字節(jié)數(shù))   );

            在用ReadFileWriteFile讀寫串行口時(shí),需要考慮超時(shí)問(wèn)題。超時(shí)的作用是在指定的時(shí)間內(nèi)沒(méi)有讀入或發(fā)送指定數(shù)量的字符,ReadFileWriteFile的操作仍然會(huì)結(jié)束。
              要查詢當(dāng)前的超時(shí)設(shè)置應(yīng)調(diào)用GetCommTimeouts函數(shù),該函數(shù)會(huì)填充一個(gè)COMMTIMEOUTS結(jié)構(gòu)。調(diào)用SetCommTimeouts可以用某一個(gè)COMMTIMEOUTS結(jié)構(gòu)的內(nèi)容來(lái)設(shè)置超時(shí)。
              讀寫串口的超時(shí)有兩種:間隔超時(shí)和總超時(shí)。間隔超時(shí)是指在接收時(shí)兩個(gè)字符之間的最大時(shí)延。總超時(shí)是指讀寫操作總共花費(fèi)的最大時(shí)間。寫操作只支持總超時(shí),而讀操作兩種超時(shí)均支持。用COMMTIMEOUTS結(jié)構(gòu)可以規(guī)定讀寫操作的超時(shí)。
            COMMTIMEOUTS
            結(jié)構(gòu)的定義為:

            typedef struct _COMMTIMEOUTS {      
            DWORD ReadIntervalTimeout; //
            讀間隔超時(shí)   
            DWORD ReadTotalTimeoutMultiplier; //
            讀時(shí)間系數(shù)   
            DWORD ReadTotalTimeoutConstant; //
            讀時(shí)間常量   
            DWORD WriteTotalTimeoutMultiplier; //
            寫時(shí)間系數(shù)   
            DWORD WriteTotalTimeoutConstant; //
            寫時(shí)間常量
            } COMMTIMEOUTS,*LPCOMMTIMEOUTS;

            COMMTIMEOUTS結(jié)構(gòu)的成員都以毫秒為單位。總超時(shí)的計(jì)算公式是:
            總超時(shí)=時(shí)間系數(shù)×要求讀/寫的字符數(shù)+時(shí)間常量
            例如,要讀入10個(gè)字符,那么讀操作的總超時(shí)的計(jì)算公式為:
            讀總超時(shí)=ReadTotalTimeoutMultiplier×10ReadTotalTimeoutConstant
            可以看出:間隔超時(shí)和總超時(shí)的設(shè)置是不相關(guān)的,這可以方便通信程序靈活地設(shè)置各種超時(shí)。

            如果所有寫超時(shí)參數(shù)均為0,那么就不使用寫超時(shí)。如果ReadIntervalTimeout0,那么就不使用讀間隔超時(shí)。如果ReadTotalTimeoutMultiplier ReadTotalTimeoutConstant 都為0,則不使用讀總超時(shí)。如果讀間隔超時(shí)被設(shè)置成MAXDWORD并且讀時(shí)間系數(shù)和讀時(shí)間常量都為0,那么在讀一次輸入緩沖區(qū)的內(nèi)容后讀操作就立即返回,而不管是否讀入了要求的字符。
              在用重疊方式讀寫串口時(shí),雖然ReadFileWriteFile在完成操作以前就可能返回,但超時(shí)仍然是起作用的。在這種情況下,超時(shí)規(guī)定的是操作的完成時(shí)間,而不是ReadFileWriteFile的返回時(shí)間。
            配置串口的示例代碼:

            SetupComm(hCom,1024,1024); //輸入緩沖區(qū)和輸出緩沖區(qū)的大小都是1024
            COMMTIMEOUTS TimeOuts;     //
            設(shè)定讀超時(shí)  
            TimeOuts.ReadIntervalTimeout=1000;    
            TimeOuts.ReadTotalTimeoutMultiplier=500;     
            TimeOuts.ReadTotalTimeoutConstant=5000;     //
            設(shè)定寫超時(shí)   T
            imeOuts.WriteTotalTimeoutMultiplier=500;    
            TimeOuts.WriteTotalTimeoutConstant=2000;     
            SetCommTimeouts(hCom,&TimeOuts); //
            設(shè)置超時(shí)
            DCB dcb;      
            GetCommState(hCom,&dcb);      
            dcb.BaudRate=9600; //
            波特率為9600    
            dcb.ByteSize=8; //
            每個(gè)字節(jié)有8     
            dcb.Parity=NOPARITY; //
            無(wú)奇偶校驗(yàn)位    
            dcb.StopBits=TWOSTOPBITS; //
            兩個(gè)停止位       
            SetCommState(hCom,&dcb);    
            PurgeComm(hCom,PURGE_TXCLEAR|PURGE_RXCLEAR);

            在讀寫串口之前,還要用PurgeComm()函數(shù)清空緩沖區(qū),該函數(shù)原型:

            BOOL PurgeComm(    HANDLE hFile,    //串口句柄    
                                                DWORD dwFlags    //
            需要完成的操作  
            );

            參數(shù)dwFlags指定要完成的操作,可以是下列值的組合:

            PURGE_TXABORT        中斷所有寫操作并立即返回,即使寫操作還沒(méi)有完成。PURGE_RXABORT       中斷所有讀操作并立即返回,即使讀操作還沒(méi)有完成。PURGE_TXCLEAR      清除輸出緩沖區(qū)PURGE_RXCLEAR        清除輸入緩沖區(qū)

            3)、讀寫串口

            我們使用ReadFileWriteFile讀寫串口,下面是兩個(gè)函數(shù)的聲明:

            BOOL ReadFile(    HANDLE hFile,     //串口的句柄        // 讀入的數(shù)據(jù)存儲(chǔ)的地址,    // 即讀入的數(shù)據(jù)將存儲(chǔ)在以該指針的值為首地址的一片內(nèi)存區(qū)   
            LPVOID lpBuffer,         
            DWORD nNumberOfBytesToRead,       //
            要讀入的數(shù)據(jù)的字節(jié)數(shù)        // 指向一個(gè)DWORD數(shù)值,該數(shù)值返回讀操作實(shí)際讀入的字節(jié)數(shù)   
            LPDWORD lpNumberOfBytesRead,             //
            重疊操作時(shí),該參數(shù)指向一個(gè)OVERLAPPED結(jié)構(gòu),同步操作時(shí),該參數(shù)為NULL   
            LPOVERLAPPED lpOverlapped        );    
            BOOL WriteFile(    HANDLE hFile,      //
            串口的句柄            // 即以該指針的值為首地址的nNumberOfBytesToWrite    // 個(gè)字節(jié)的數(shù)據(jù)將要寫入串口的發(fā)送數(shù)據(jù)緩沖區(qū)。   
            LPCVOID lpBuffer,       // 寫入的數(shù)據(jù)存儲(chǔ)的地址,       
            DWORD nNumberOfBytesToWrite, //
            要寫入的數(shù)據(jù)的字節(jié)數(shù)        // 指向指向一個(gè)DWORD數(shù)值,該數(shù)值返回實(shí)際寫入的字節(jié)數(shù)   
            LPDWORD lpNumberOfBytesWritten,             //
            重疊操作時(shí),該參數(shù)指向一個(gè)OVERLAPPED結(jié)構(gòu),    // 同步操作時(shí),該參數(shù)為NULL  
             
            LPOVERLAPPED lpOverlapped        );

            在用ReadFileWriteFile讀寫串口時(shí),既可以同步執(zhí)行,也可以重疊執(zhí)行。在同步執(zhí)行時(shí),函數(shù)直到操作完成后才返回。這意味著同步執(zhí)行時(shí)線程會(huì)被阻塞,從而導(dǎo)致效率下降。在重疊執(zhí)行時(shí),即使操作還未完成,這兩個(gè)函數(shù)也會(huì)立即返回,費(fèi)時(shí)的I/O操作在后臺(tái)進(jìn)行。
              ReadFileWriteFile函數(shù)是同步還是異步由CreateFile函數(shù)決定,如果在調(diào)用CreateFile創(chuàng)建句柄時(shí)指定了FILE_FLAG_OVERLAPPED標(biāo)志,那么調(diào)用ReadFileWriteFile對(duì)該句柄進(jìn)行的操作就應(yīng)該是重疊的;如果未指定重疊標(biāo)志,則讀寫操作應(yīng)該是同步的。ReadFileWriteFile函數(shù)的同步或者異步應(yīng)該和CreateFile函數(shù)相一致。
              ReadFile函數(shù)只要在串口輸入緩沖區(qū)中讀入指定數(shù)量的字符,就算完成操作。而WriteFile函數(shù)不但要把指定數(shù)量的字符拷入到輸出緩沖區(qū),而且要等這些字符從串行口送出去后才算完成操作。
              如果操作成功,這兩個(gè)函數(shù)都返回TRUE。需要注意的是,當(dāng)ReadFileWriteFile返回FALSE時(shí),不一定就是操作失敗,線程應(yīng)該調(diào)用GetLastError函數(shù)分析返回的結(jié)果。例如,在重疊操作時(shí)如果操作還未完成函數(shù)就返回,那么函數(shù)就返回FALSE,而且GetLastError函數(shù)返回ERROR_IO_PENDING。這說(shuō)明重疊操作還未完成。

            同步方式讀寫串口比較簡(jiǎn)單,下面先例舉同步方式讀寫串口的代碼:

            //同步讀串口char str[100];
            DWORD wCount;//
            讀取的字節(jié)數(shù)
            BOOL bReadStat;
            bReadStat=ReadFile(hCom,str,100,&wCount,NULL);
            if(!bReadStat){  
            AfxMessageBox("
            讀串口失敗!");
            return FALSE;
            }
            return TRUE;
            //
            同步寫串口       
            char lpOutBuffer[100];
            DWORD dwBytesWrite=100;  
            COMSTAT ComStat;      
            DWORD dwErrorFlags;   
            BOOL bWriteStat;    
            ClearCommError(hCom,&dwErrorFlags,&ComStat);    
            bWriteStat=WriteFile(hCom,lpOutBuffer,dwBytesWrite,& dwBytesWrite,NULL);    
            if(!bWriteStat) { 
                        
            AfxMessageBox("
            寫串口失敗!");
             }      
            PurgeComm(hCom, PURGE_TXABORT|              PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);

            在重疊操作時(shí),操作還未完成函數(shù)就返回。

              重疊I/O非常靈活,它也可以實(shí)現(xiàn)阻塞(例如我們可以設(shè)置一定要讀取到一個(gè)數(shù)據(jù)才能進(jìn)行到下一步操作)。有兩種方法可以等待操作完成:一種方法是用象WaitForSingleObject這樣的等待函數(shù)來(lái)等待OVERLAPPED結(jié)構(gòu)的hEvent成員;另一種方法是調(diào)用GetOverlappedResult函數(shù)等待,后面將演示說(shuō)明。
            下面我們先簡(jiǎn)單說(shuō)一下OVERLAPPED結(jié)構(gòu)和GetOverlappedResult函數(shù):
            OVERLAPPED
            結(jié)構(gòu)
            OVERLAPPED
            結(jié)構(gòu)包含了重疊I/O的一些信息,定義如下:

            typedef struct _OVERLAPPED { // o      DWORD Internal;     DWORD InternalHigh;     DWORD Offset;     DWORD OffsetHigh;     HANDLE hEvent; } OVERLAPPED;

            在使用ReadFileWriteFile重疊操作時(shí),線程需要?jiǎng)?chuàng)建OVERLAPPED結(jié)構(gòu)以供這兩個(gè)函數(shù)使用。線程通過(guò)OVERLAPPED結(jié)構(gòu)獲得當(dāng)前的操作狀態(tài),該結(jié)構(gòu)最重要的成員是hEventhEvent是讀寫事件。當(dāng)串口使用異步通訊時(shí),函數(shù)返回時(shí)操作可能還沒(méi)有完成,程序可以通過(guò)檢查該事件得知是否讀寫完畢。
              當(dāng)調(diào)用ReadFile, WriteFile 函數(shù)的時(shí)候,該成員會(huì)自動(dòng)被置為無(wú)信號(hào)狀態(tài);當(dāng)重疊操作完成后,該成員變量會(huì)自動(dòng)被置為有信號(hào)狀態(tài)。

            GetOverlappedResult函數(shù)BOOL GetOverlappedResult(    HANDLE hFile,        // 串口的句柄          // 指向重疊操作開(kāi)始時(shí)指定的OVERLAPPED結(jié)構(gòu)    LPOVERLAPPED lpOverlapped,         // 指向一個(gè)32位變量,該變量的值返回實(shí)際讀寫操作傳輸?shù)淖止?jié)數(shù)。    LPDWORD lpNumberOfBytesTransferred,             // 該參數(shù)用于指定函數(shù)是否一直等到重疊操作結(jié)束。    // 如果該參數(shù)為TRUE,函數(shù)直到操作結(jié)束才返回。    // 如果該參數(shù)為FALSE,函數(shù)直接返回,這時(shí)如果操作沒(méi)有完成,    // 通過(guò)調(diào)用GetLastError()函數(shù)會(huì)返回ERROR_IO_INCOMPLETE    BOOL bWait    );

            該函數(shù)返回重疊操作的結(jié)果,用來(lái)判斷異步操作是否完成,它是通過(guò)判斷OVERLAPPED結(jié)構(gòu)中的hEvent是否被置位來(lái)實(shí)現(xiàn)的。

            異步讀串口的示例代碼:

            char lpInBuffer[1024];
            DWORD dwBytesRead=1024;
            COMSTAT ComStat;
            DWORD dwErrorFlags;
            OVERLAPPED m_osRead;
            memset(&m_osRead,0,sizeof(OVERLAPPED));
            m_osRead.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
            ClearCommError(hCom,&dwErrorFlags,&ComStat);
            dwBytesRead=min(dwBytesRead,(DWORD)ComStat.cbInQue);
            if(!dwBytesRead)
            return FALSE;
            BOOL bReadStatus;
            bReadStatus=ReadFile(hCom,
            lpInBuffer,                               
            dwBytesRead,
            &dwBytesRead,
            &m_osRead);
            if(!bReadStatus) //
            如果ReadFile函數(shù)返回FALSE
            {    
            if(GetLastError()==ERROR_IO_PENDING) //GetLastError()
            函數(shù)返回ERROR_IO_PENDING,表明串口正在進(jìn)行讀操作  
            {             
            WaitForSingleObject(m_osRead.hEvent,2000);         //
            使用WaitForSingleObject函數(shù)等待,直到讀操作完成或延時(shí)已達(dá)到2秒鐘        //當(dāng)串口讀操作進(jìn)行完畢后,m_osReadhEvent事件會(huì)變?yōu)橛行盘?hào)              
            PurgeComm(hCom, PURGE_TXABORT|                      PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);  
             
                 return dwBytesRead;   
            }      
            return 0;
            }
            PurgeComm(hCom, PURGE_TXABORT|               PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);
            return dwBytesRead;

            對(duì)以上代碼再作簡(jiǎn)要說(shuō)明:在使用ReadFile 函數(shù)進(jìn)行讀操作前,應(yīng)先使用ClearCommError函數(shù)清除錯(cuò)誤。ClearCommError函數(shù)的原型如下:

            BOOL ClearCommError(    HANDLE hFile,      // 串口句柄   
            LPDWORD lpErrors,      //
            指向接收錯(cuò)誤碼的變量   
            LPCOMSTAT lpStat //
            指向通訊狀態(tài)緩沖區(qū)  
            );

            該函數(shù)獲得通信錯(cuò)誤并報(bào)告串口的當(dāng)前狀態(tài),同時(shí),該函數(shù)清除串口的錯(cuò)誤標(biāo)志以便繼續(xù)輸入、輸出操作。
            參數(shù)lpStat指向一個(gè)COMSTAT結(jié)構(gòu),該結(jié)構(gòu)返回串口狀態(tài)信息。 COMSTAT結(jié)構(gòu) COMSTAT結(jié)構(gòu)包含串口的信息,結(jié)構(gòu)定義如下:

            typedef struct _COMSTAT { // cst     
            DWORD fCtsHold : 1; // Tx waiting for CTS signal    
            DWORD fDsrHold : 1;   // Tx waiting for DSR signal    
            DWORD fRlsdHold : 1; // Tx waiting for RLSD signal    
            DWORD fXoffHold : 1; // Tx waiting, XOFF char rec''d    
            DWORD fXoffSent : 1; // Tx waiting, XOFF char sent    
            DWORD fEof : 1;       // EOF character sent    
            DWORD fTxim : 1;      // character waiting for Tx    
            DWORD fReserved : 25; // reserved    
            DWORD cbInQue;        // bytes in input buffer    
            DWORD cbOutQue;       // bytes in output buffer
            } COMSTAT, *LPCOMSTAT;

            本文只用到了cbInQue成員變量,該成員變量的值代表輸入緩沖區(qū)的字節(jié)數(shù)。

              最后用PurgeComm函數(shù)清空串口的輸入輸出緩沖區(qū)。

            這段代碼用WaitForSingleObject函數(shù)來(lái)等待OVERLAPPED結(jié)構(gòu)的hEvent成員,下面我們?cè)傺菔疽欢握{(diào)用GetOverlappedResult函數(shù)等待的異步讀串口示例代碼:

            char lpInBuffer[1024];
            DWORD dwBytesRead=1024;     
            BOOL bReadStatus;     
            DWORD dwErrorFlags;      
            COMSTAT ComStat;
            OVERLAPPED m_osRead;    
            ClearCommError(hCom,&dwErrorFlags,&ComStat); 
            if(!ComStat.cbInQue)           return 0;
            dwBytesRead=min(dwBytesRead,(DWORD)ComStat.cbInQue); 
            bReadStatus=ReadFile(hCom,
            lpInBuffer,
            dwBytesRead,            
            &dwBytesRead,
            &m_osRead);      
            if(!bReadStatus) //
            如果ReadFile函數(shù)返回FALSE     
            {             
            if(GetLastError()==ERROR_IO_PENDING)         
            {             
            GetOverlappedResult(hCom,                         
            &m_osRead,&dwBytesRead,TRUE);           // GetOverlappedResult
            函數(shù)的最后一個(gè)參數(shù)設(shè)為TRUE           //函數(shù)會(huì)一直等待,直到讀操作完成或由于錯(cuò)誤而返回。                   return dwBytesRead;           
            }             
            return 0;     
            }      
            return dwBytesRead;

            異步寫串口的示例代碼:

            char buffer[1024];
            DWORD dwBytesWritten=1024;      
            DWORD dwErrorFlags;   
            COMSTAT ComStat;
            OVERLAPPED m_osWrite;      
            BOOL bWriteStat;    
            bWriteStat=WriteFile(hCom,buffer,dwBytesWritten,           &dwBytesWritten,&m_OsWrite);  
            if(!bWriteStat) {           
            if(GetLastError()==ERROR_IO_PENDING)         
            {                  
            WaitForSingleObject(m_osWrite.hEvent,1000);                 
            return dwBytesWritten; 
            }            
            return 0;     
            }      
            return dwBytesWritten;

            4)、關(guān)閉串口

            利用API函數(shù)關(guān)閉串口非常簡(jiǎn)單,只需使用CreateFile函數(shù)返回的句柄作為參數(shù)調(diào)用CloseHandle即可:

            BOOL CloseHandle(    HANDLE hObject; //handle to object to close );

            串口編程的一個(gè)實(shí)例

            為了讓您更好地理解串口編程,下面我們分別編寫兩個(gè)例程(見(jiàn)附帶的源碼部分),這兩個(gè)例程都實(shí)現(xiàn)了工控機(jī)與百特顯示儀表通過(guò)RS485接口進(jìn)行的串口通信。其中第一個(gè)例程采用同步串口操作,第二個(gè)例程采用異步串口操作。
              我們只介紹軟件部分,RS485接口接線方法不作介紹,感興趣的讀者可以查閱相關(guān)資料。

            例程1

            打開(kāi)VC++6.0,新建基于對(duì)話框的工程RS485Comm,在主對(duì)話框窗口IDD_RS485COMM_DIALOG上添加兩個(gè)按鈕,ID分別為IDC_SENDIDC_RECEIVE,標(biāo)題分別為發(fā)送接收;添加一個(gè)靜態(tài)文本框IDC_DISP,用于顯示串口接收到的內(nèi)容。

            RS485CommDlg.cpp文件中添加全局變量:

            HANDLE hCom; //全局變量,串口句柄

            RS485CommDlg.cpp文件中的OnInitDialog()函數(shù)添加如下代碼:

            // TODO: Add extra initialization here    
            hCom=CreateFile("COM1",//COM1
                       
            GENERIC_READ|GENERIC_WRITE, //
            允許讀和寫             
            0, //
            獨(dú)占方式         
            NULL,       
            OPEN_EXISTING, //
            打開(kāi)而不是創(chuàng)建              
            0, //
            同步方式         
            NULL);    
            if(hCom==(HANDLE)-1)  
            {             
            AfxMessageBox("
            打開(kāi)COM失敗!");           
            return FALSE; 
            }      
            SetupComm(hCom,100,100); //
            輸入緩沖區(qū)和輸出緩沖區(qū)的大小都是1024    
            COMMTIMEOUTS TimeOuts; //
            設(shè)定讀超時(shí)  
            TimeOuts.ReadIntervalTimeout=MAXDWORD;    
            TimeOuts.ReadTotalTimeoutMultiplier=0;       
            TimeOuts.ReadTotalTimeoutConstant=0;     //
            在讀一次輸入緩沖區(qū)的內(nèi)容后讀操作就立即返回,        //而不管是否讀入了要求的字符。     //設(shè)定寫超時(shí)   TimeOuts.WriteTotalTimeoutMultiplier=100;    
            TimeOuts.WriteTotalTimeoutConstant=500;      
            SetCommTimeouts(hCom,&TimeOuts); //
            設(shè)置超時(shí)
            DCB dcb;      
            GetCommState(hCom,&dcb);      
            dcb.BaudRate=9600; //
            波特率為9600    
            dcb.ByteSize=8; //
            每個(gè)字節(jié)有8     
            dcb.Parity=NOPARITY; //
            無(wú)奇偶校驗(yàn)位    
            dcb.StopBits=TWOSTOPBITS; //
            兩個(gè)停止位       
            SetCommState(hCom,&dcb);    
            PurgeComm(hCom,PURGE_TXCLEAR|PURGE_RXCLEAR);

            分別雙擊IDC_SEND按鈕和IDC_RECEIVE按鈕,添加兩個(gè)按鈕的響應(yīng)函數(shù):

            void CRS485CommDlg::OnSend() {     
            // TODO: Add your control notification handler code here    
            //
            在此需要簡(jiǎn)單介紹百特公司XMA5000的通訊協(xié)議:      
            //
            該儀表RS485通訊采用主機(jī)廣播方式通訊。    
            //
            串行半雙工,幀11位,1個(gè)起始位(0)8個(gè)數(shù)據(jù)位,2個(gè)停止位(1)      
            //
            如:讀儀表顯示的瞬時(shí)值,主機(jī)發(fā)送:DC1 AAA BB ETX  
            //
            其中:DC1是標(biāo)準(zhǔn)ASCII碼的一個(gè)控制符號(hào),碼值為11H(十進(jìn)制的17)    
            //
            XMA5000的通訊協(xié)議中,DC1表示讀瞬時(shí)值   
            //AAA
            是從機(jī)地址碼,也就是XMA5000顯示儀表的通訊地址 
            //BB
            為通道號(hào),讀瞬時(shí)值時(shí)該值為01    
            //ETX
            也是標(biāo)準(zhǔn)ASCII碼的一個(gè)控制符號(hào),碼值為03H     
            //
            XMA5000的通訊協(xié)議中,ETX表示主機(jī)結(jié)束符 
            char lpOutBuffer[7];    
            memset(lpOutBuffer,''\0'',7); //
            7個(gè)字節(jié)先清零     l
            pOutBuffer[0]=''\x11''; //
            發(fā)送緩沖區(qū)的第1個(gè)字節(jié)為DC1     
            lpOutBuffer[1]=''0''; //
            2個(gè)字節(jié)為字符0(30H)  
            lpOutBuffer[2]=''0''; //
            3個(gè)字節(jié)為字符0(30H)    
            lpOutBuffer[3]=''1''; //
            4個(gè)字節(jié)為字符1(31H)     
            lpOutBuffer[4]=''0''; //
            5個(gè)字節(jié)為字符0(30H)     
            lpOutBuffer[5]=''1''; //
            6個(gè)字節(jié)為字符1(31H)    
            lpOutBuffer[6]=''\x03''; //
            7個(gè)字節(jié)為字符ETX       //從該段代碼可以看出,儀表的通訊地址為001          
            DWORD dwBytesWrite=7; 
            COMSTAT ComStat;      
            DWORD dwErrorFlags;    
            BOOL bWriteStat;      
            ClearCommError(hCom,&dwErrorFlags,&ComStat);    
            bWriteStat=WriteFile(hCom,lpOutBuffer,dwBytesWrite,& dwBytesWrite,NULL);    
            if(!bWriteStat) {             
            AfxMessageBox("
            寫串口失敗!"); 
            }
            }
            void CRS485CommDlg::OnReceive() {       
            // TODO: Add your control notification handler code here    
            char str[100];
            memset(str,''\0'',100);       
            DWORD wCount=100;//
            讀取的字節(jié)數(shù)    
            BOOL bReadStat;
            bReadStat=ReadFile(hCom,str,wCount,&wCount,NULL);    
            if(!bReadStat)     
            AfxMessageBox("
            讀串口失敗!"); 
            PurgeComm(hCom, PURGE_TXABORT|      PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);  
            m_disp=str;   
            UpdateData(FALSE);    
            }

            您可以觀察返回的字符串,其中有和儀表顯示值相同的部分,您可以進(jìn)行相應(yīng)的字符串操作取出儀表的顯示值。
            打開(kāi)ClassWizard,為靜態(tài)文本框IDC_DISP添加CString類型變量m_disp,同時(shí)添加WM_CLOSE的相應(yīng)函數(shù):

            void CRS485CommDlg::OnClose() {    
            // TODO: Add your message handler code here and/or call default   
            CloseHandle(hCom);       //
            程序退出時(shí)關(guān)閉串口  
            CDialog::OnClose();
            }

            程序的相應(yīng)部分已經(jīng)在代碼內(nèi)部作了詳細(xì)介紹。連接好硬件部分,編譯運(yùn)行程序,細(xì)心體會(huì)串口同步操作部分。

            例程2

            打開(kāi)VC++6.0,新建基于對(duì)話框的工程RS485Comm,在主對(duì)話框窗口IDD_RS485COMM_DIALOG上添加兩個(gè)按鈕,ID分別為IDC_SENDIDC_RECEIVE,標(biāo)題分別為發(fā)送接收;添加一個(gè)靜態(tài)文本框IDC_DISP,用于顯示串口接收到的內(nèi)容。在RS485CommDlg.cpp文件中添加全局變量:

            HANDLE hCom; //全局變量,

            串口句柄在RS485CommDlg.cpp文件中的OnInitDialog()函數(shù)添加如下代碼:

            hCom=CreateFile("COM1",//COM1           
            GENERIC_READ|GENERIC_WRITE, //
            允許讀和寫          
            0, //
            獨(dú)占方式         
            NULL,         
            OPEN_EXISTING, //
            打開(kāi)而不是創(chuàng)建           
            FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, //
            重疊方式              
            NULL);    
            if(hCom==(HANDLE)-1)   {             
            AfxMessageBox("
            打開(kāi)COM失敗!");           
            return FALSE; 
            }      
            SetupComm(hCom,100,100); //
            輸入緩沖區(qū)和輸出緩沖區(qū)的大小都是100    
            COMMTIMEOUTS TimeOuts; //
            設(shè)定讀超時(shí)  
            TimeOuts.ReadIntervalTimeout=MAXDWORD;    
            TimeOuts.ReadTotalTimeoutMultiplier=0;       
            TimeOuts.ReadTotalTimeoutConstant=0;     //
            在讀一次輸入緩沖區(qū)的內(nèi)容后讀操作就立即返回,        //而不管是否讀入了要求的字符。     //設(shè)定寫超時(shí)   TimeOuts.WriteTotalTimeoutMultiplier=100;    
            TimeOuts.WriteTotalTimeoutConstant=500;      
            SetCommTimeouts(hCom,&TimeOuts); //
            設(shè)置超時(shí)
            DCB dcb;      
            GetCommState(hCom,&dcb);      
            dcb.BaudRate=9600; //
            波特率為9600    
            dcb.ByteSize=8; //
            每個(gè)字節(jié)有8     
            dcb.Parity=NOPARITY; //
            無(wú)奇偶校驗(yàn)位    
            dcb.StopBits=TWOSTOPBITS; //
            兩個(gè)停止位       
            SetCommState(hCom,&dcb);    
            PurgeComm(hCom,PURGE_TXCLEAR|PURGE_RXCLEAR);

            分別雙擊IDC_SEND按鈕和IDC_RECEIVE按鈕,添加兩個(gè)按鈕的響應(yīng)函數(shù):

            void CRS485CommDlg::OnSend() {     
            // TODO: Add your control notification handler code here    
            OVERLAPPED m_osWrite;
             memset(&m_osWrite,0,sizeof(OVERLAPPED)); 
               
            m_osWrite.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);  
            char lpOutBuffer[7];    
            memset(lpOutBuffer,''\0'',7); 
            lpOutBuffer[0]=''\x11'';      
            lpOutBuffer[1]=''0'';    
            lpOutBuffer[2]=''0''; 
            lpOutBuffer[3]=''1''; 
            lpOutBuffer[4]=''0'';    
            lpOutBuffer[5]=''1''; 
            lpOutBuffer[6]=''\x03'';             
            DWORD dwBytesWrite=7;    
            COMSTAT ComStat;      
            DWORD dwErrorFlags;   
            BOOL bWriteStat;    
            ClearCommError(hCom,&dwErrorFlags,&ComStat); 
            bWriteStat=WriteFile(hCom,lpOutBuffer,      dwBytesWrite,& dwBytesWrite,&m_osWrite);     
            if(!bWriteStat) {           
            if(GetLastError()==ERROR_IO_PENDING)         
            {                  
            WaitForSingleObject(m_osWrite.hEvent,1000);
            }      
            }
            }
            void CRS485CommDlg::OnReceive()
            {       
            // TODO: Add your control notification handler code here    
            OVERLAPPED m_osRead;  
            memset(&m_osRead,0,sizeof(OVERLAPPED));    
            m_osRead.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);   
            COMSTAT ComStat;      
            DWORD dwErrorFlags;              
            char str[100]; memset(str,''\0'',100);       
            DWORD dwBytesRead=100;//
            讀取的字節(jié)數(shù)     
            BOOL bReadStat;    
            ClearCommError(hCom,&dwErrorFlags,&ComStat); 
            dwBytesRead=min(dwBytesRead, (DWORD)ComStat.cbInQue);   
            bReadStat=ReadFile(hCom,str,        dwBytesRead,&dwBytesRead,&m_osRead); 
            if(!bReadStat) {           
            if(GetLastError()==ERROR_IO_PENDING)     //GetLastError()
            函數(shù)返回ERROR_IO_PENDING,表明串口正在進(jìn)行讀操作       
            {                  
            WaitForSingleObject(m_osRead.hEvent,2000);                //
            使用WaitForSingleObject函數(shù)等待,直到讀操作完成或延時(shí)已達(dá)到2秒鐘               //當(dāng)串口讀操作進(jìn)行完畢后,m_osReadhEvent事件會(huì)變?yōu)橛行盘?hào)            
            }      
            }      
            PurgeComm(hCom, PURGE_TXABORT|      PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);  
            m_disp=str;   
            UpdateData(FALSE);
            }

            打開(kāi)ClassWizard,為靜態(tài)文本框IDC_DISP添加CString類型變量m_disp,同時(shí)添加WM_CLOSE的相應(yīng)函數(shù):

            void CRS485CommDlg::OnClose() {    
            // TODO: Add your message handler code here and/or call default   
            CloseHandle(hCom);       //
            程序退出時(shí)關(guān)閉串口  
            CDialog::OnClose();
            }

             

            posted on 2007-06-16 23:25 Xiao.Zhu 閱讀(481) 評(píng)論(0)  編輯 收藏 引用

            只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問(wèn)   Chat2DB   管理


            久久伊人亚洲AV无码网站| 伊人久久大香线焦AV综合影院 | 久久国产精品免费一区| 久久毛片免费看一区二区三区| 久久夜色精品国产亚洲| 国产韩国精品一区二区三区久久| 亚洲国产精品婷婷久久| 婷婷久久香蕉五月综合加勒比| 久久99精品久久久久久不卡| 人妻精品久久无码区| 午夜精品久久久久久| 狠狠色丁香久久综合五月| 欧美日韩精品久久免费| 日本精品久久久久中文字幕8| 亚洲七七久久精品中文国产| 久久久国产精品网站| 久久亚洲欧美国产精品 | 无码日韩人妻精品久久蜜桃| 久久久WWW免费人成精品| .精品久久久麻豆国产精品| 久久综合亚洲色一区二区三区| 四虎国产永久免费久久| 精品熟女少妇a∨免费久久| 亚洲中文字幕无码久久精品1| 久久青青国产| 久久精品亚洲福利| 办公室久久精品| 国产精品美女久久久免费| 久久久精品免费国产四虎| 久久久久女人精品毛片| 久久久久久久久无码精品亚洲日韩 | 久久精品国产免费| 久久国产色AV免费观看| 亚洲色欲久久久综合网东京热| 青青久久精品国产免费看| 精品无码久久久久久久动漫 | 久久丫忘忧草产品| 久久久久久久波多野结衣高潮| 四虎国产精品成人免费久久| 久久最新免费视频| 久久精品国产欧美日韩99热|