青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

Xiao.Zhu C++

Xiao.Zhu C++

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

 

無論那種操作方式,一般都通過四個步驟來完成:
1打開串口

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

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

·           lpFileName:將要打開的串口邏輯名,如“COM1”;

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

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

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

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

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

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

同步I/O方式打開串口的示例代碼:

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

重疊I/O打開串口的示例代碼:

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

2)、配置串口

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

typedef struct _DCB{ 
 
………   //
波特率,指定通信設(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; //
指定奇偶校驗使能。若此成員為1,允許奇偶校驗檢查   
…BYTE ByteSize; //
通信字節(jié)位數(shù),4—8BYTE
Parity; //
指定奇偶校驗方法。此成員可以有下列值:EVENPARITY 偶校驗     NOPARITY 無校驗MARKPARITY 標(biāo)記校驗   ODDPARITY 奇校驗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)識通訊端口的句柄  
LPDCB lpDCB //
指向一個設(shè)備控制塊(DCB結(jié)構(gòu))的指針 );
SetCommState
函數(shù)設(shè)置COM口的設(shè)備控制塊:
BOOL SetCommState(   HANDLE hFile,    LPDCB lpDCB   );

除了在BCD中的設(shè)置外,程序一般還需要設(shè)置I/O緩沖區(qū)的大小和超時。WindowsI/O緩沖區(qū)來暫存串口輸入和輸出的數(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讀寫串行口時,需要考慮超時問題。超時的作用是在指定的時間內(nèi)沒有讀入或發(fā)送指定數(shù)量的字符,ReadFileWriteFile的操作仍然會結(jié)束。
  要查詢當(dāng)前的超時設(shè)置應(yīng)調(diào)用GetCommTimeouts函數(shù),該函數(shù)會填充一個COMMTIMEOUTS結(jié)構(gòu)。調(diào)用SetCommTimeouts可以用某一個COMMTIMEOUTS結(jié)構(gòu)的內(nèi)容來設(shè)置超時。
  讀寫串口的超時有兩種:間隔超時和總超時。間隔超時是指在接收時兩個字符之間的最大時延??偝瑫r是指讀寫操作總共花費的最大時間。寫操作只支持總超時,而讀操作兩種超時均支持。用COMMTIMEOUTS結(jié)構(gòu)可以規(guī)定讀寫操作的超時。
COMMTIMEOUTS
結(jié)構(gòu)的定義為:

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

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

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

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

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

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

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

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

3)、讀寫串口

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

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

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

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

//同步讀串口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ù)就返回。

  重疊I/O非常靈活,它也可以實現(xiàn)阻塞(例如我們可以設(shè)置一定要讀取到一個數(shù)據(jù)才能進(jìn)行到下一步操作)。有兩種方法可以等待操作完成:一種方法是用象WaitForSingleObject這樣的等待函數(shù)來等待OVERLAPPED結(jié)構(gòu)的hEvent成員;另一種方法是調(diào)用GetOverlappedResult函數(shù)等待,后面將演示說明。
下面我們先簡單說一下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重疊操作時,線程需要創(chuàng)建OVERLAPPED結(jié)構(gòu)以供這兩個函數(shù)使用。線程通過OVERLAPPED結(jié)構(gòu)獲得當(dāng)前的操作狀態(tài),該結(jié)構(gòu)最重要的成員是hEvent。hEvent是讀寫事件。當(dāng)串口使用異步通訊時,函數(shù)返回時操作可能還沒有完成,程序可以通過檢查該事件得知是否讀寫完畢。
  當(dāng)調(diào)用ReadFile, WriteFile 函數(shù)的時候,該成員會自動被置為無信號狀態(tài);當(dāng)重疊操作完成后,該成員變量會自動被置為有信號狀態(tài)。

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

該函數(shù)返回重疊操作的結(jié)果,用來判斷異步操作是否完成,它是通過判斷OVERLAPPED結(jié)構(gòu)中的hEvent是否被置位來實現(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ù)等待,直到讀操作完成或延時已達(dá)到2秒鐘        //當(dāng)串口讀操作進(jìn)行完畢后,m_osReadhEvent事件會變?yōu)橛行盘?span>              
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;

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

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

該函數(shù)獲得通信錯誤并報告串口的當(dāng)前狀態(tài),同時,該函數(shù)清除串口的錯誤標(biāo)志以便繼續(xù)輸入、輸出操作。
參數(shù)lpStat指向一個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ù)來等待OVERLAPPED結(jié)構(gòu)的hEvent成員,下面我們再演示一段調(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ù)的最后一個參數(shù)設(shè)為TRUE           //函數(shù)會一直等待,直到讀操作完成或由于錯誤而返回。                   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)閉串口非常簡單,只需使用CreateFile函數(shù)返回的句柄作為參數(shù)調(diào)用CloseHandle即可:

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

串口編程的一個實例

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

例程1

打開VC++6.0,新建基于對話框的工程RS485Comm,在主對話框窗口IDD_RS485COMM_DIALOG上添加兩個按鈕,ID分別為IDC_SENDIDC_RECEIVE,標(biāo)題分別為發(fā)送接收;添加一個靜態(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, //
獨占方式         
NULL,       
OPEN_EXISTING, //
打開而不是創(chuàng)建              
0, //
同步方式         
NULL);    
if(hCom==(HANDLE)-1)  
{             
AfxMessageBox("
打開COM失敗!");           
return FALSE; 
}      
SetupComm(hCom,100,100); //
輸入緩沖區(qū)和輸出緩沖區(qū)的大小都是1024    
COMMTIMEOUTS TimeOuts; //
設(shè)定讀超時  
TimeOuts.ReadIntervalTimeout=MAXDWORD;    
TimeOuts.ReadTotalTimeoutMultiplier=0;       
TimeOuts.ReadTotalTimeoutConstant=0;     //
在讀一次輸入緩沖區(qū)的內(nèi)容后讀操作就立即返回,        //而不管是否讀入了要求的字符。     //設(shè)定寫超時   TimeOuts.WriteTotalTimeoutMultiplier=100;    
TimeOuts.WriteTotalTimeoutConstant=500;      
SetCommTimeouts(hCom,&TimeOuts); //
設(shè)置超時
DCB dcb;      
GetCommState(hCom,&dcb);      
dcb.BaudRate=9600; //
波特率為9600    
dcb.ByteSize=8; //
每個字節(jié)有8     
dcb.Parity=NOPARITY; //
無奇偶校驗位    
dcb.StopBits=TWOSTOPBITS; //
兩個停止位       
SetCommState(hCom,&dcb);    
PurgeComm(hCom,PURGE_TXCLEAR|PURGE_RXCLEAR);

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

void CRS485CommDlg::OnSend() {     
// TODO: Add your control notification handler code here    
//
在此需要簡單介紹百特公司XMA5000的通訊協(xié)議:      
//
該儀表RS485通訊采用主機(jī)廣播方式通訊。    
//
串行半雙工,幀11位,1個起始位(0),8個數(shù)據(jù)位,2個停止位(1)      
//
如:讀儀表顯示的瞬時值,主機(jī)發(fā)送:DC1 AAA BB ETX  
//
其中:DC1是標(biāo)準(zhǔn)ASCII碼的一個控制符號,碼值為11H(十進(jìn)制的17)    
//
XMA5000的通訊協(xié)議中,DC1表示讀瞬時值   
//AAA
是從機(jī)地址碼,也就是XMA5000顯示儀表的通訊地址 
//BB
為通道號,讀瞬時值時該值為01    
//ETX
也是標(biāo)準(zhǔn)ASCII碼的一個控制符號,碼值為03H     
//
XMA5000的通訊協(xié)議中,ETX表示主機(jī)結(jié)束符 
char lpOutBuffer[7];    
memset(lpOutBuffer,''\0'',7); //
7個字節(jié)先清零     l
pOutBuffer[0]=''\x11''; //
發(fā)送緩沖區(qū)的第1個字節(jié)為DC1     
lpOutBuffer[1]=''0''; //
2個字節(jié)為字符0(30H)  
lpOutBuffer[2]=''0''; //
3個字節(jié)為字符0(30H)    
lpOutBuffer[3]=''1''; //
4個字節(jié)為字符1(31H)     
lpOutBuffer[4]=''0''; //
5個字節(jié)為字符0(30H)     
lpOutBuffer[5]=''1''; //
6個字節(jié)為字符1(31H)    
lpOutBuffer[6]=''\x03''; //
7個字節(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)的字符串操作取出儀表的顯示值。
打開ClassWizard,為靜態(tài)文本框IDC_DISP添加CString類型變量m_disp,同時添加WM_CLOSE的相應(yīng)函數(shù):

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

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

例程2

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

HANDLE hCom; //全局變量,

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

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

分別雙擊IDC_SEND按鈕和IDC_RECEIVE按鈕,添加兩個按鈕的響應(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ù)等待,直到讀操作完成或延時已達(dá)到2秒鐘               //當(dāng)串口讀操作進(jìn)行完畢后,m_osReadhEvent事件會變?yōu)橛行盘?span>            
}      
}      
PurgeComm(hCom, PURGE_TXABORT|      PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);  
m_disp=str;   
UpdateData(FALSE);
}

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

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

 

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

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


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            亚洲一区二区三区四区五区午夜 | 亚洲美女毛片| 鲁大师成人一区二区三区| 久久看片网站| 亚洲福利专区| 牛牛国产精品| 亚洲美女性视频| 亚洲天堂成人| 久久久中精品2020中文| 欧美激情精品久久久六区热门| 欧美美女喷水视频| 国产精品红桃| 伊人久久亚洲美女图片| 日韩视频永久免费观看| 先锋影音一区二区三区| 两个人的视频www国产精品| 亚洲黄色毛片| 羞羞答答国产精品www一本| 免费短视频成人日韩| 欧美视频中文字幕| 在线精品福利| 亚洲欧美日本精品| 欧美福利一区二区| 亚洲免费网站| 欧美日韩精品欧美日韩精品| 国产精品一区免费视频| 亚洲欧洲一区二区三区在线观看 | 一区二区久久| 久久爱91午夜羞羞| 欧美日韩三级在线| 在线观看亚洲视频| 欧美一区二区精品在线| 欧美国产先锋| 久久精品91| 国产精品久久久久久av福利软件| 亚洲电影免费观看高清完整版在线 | 亚洲午夜国产一区99re久久| 久久综合九色综合久99| 国产精品一区二区欧美| 亚洲神马久久| 国产精品日韩欧美一区二区| 亚洲人成艺术| 蜜乳av另类精品一区二区| 亚洲网站在线| 欧美色图麻豆| 在线一区免费观看| 亚洲高清毛片| 久久久伊人欧美| 一区二区视频欧美| 久久久噜噜噜| 欧美在线观看视频| 国产深夜精品| 欧美自拍偷拍| 午夜欧美精品久久久久久久| 国产精品进线69影院| 亚洲最新中文字幕| 亚洲美女在线国产| 欧美日韩精品欧美日韩精品| 在线视频一区观看| 日韩五码在线| 国产精品久久久久av| 亚洲视频在线观看三级| 亚洲狼人精品一区二区三区| 欧美日韩国产精品自在自线| 在线亚洲电影| 一区二区av在线| 国产精品久久久99| 久久er精品视频| 久久国产精品久久久久久久久久 | 在线色欧美三级视频| 欧美不卡视频一区| 欧美精品久久天天躁| 亚洲视频一区二区免费在线观看| 99精品视频免费| 国产精品毛片大码女人| 欧美一级专区免费大片| 欧美在线观看视频在线| 亚洲国产成人精品女人久久久 | 久久福利资源站| 一区二区三区在线观看国产| 欧美激情四色| 国产精品国产一区二区| 久久综合伊人| 欧美日韩麻豆| 久久久久久久久久久久久9999| 久久久久久久一区| 亚洲美女黄网| 亚洲欧美日韩精品久久亚洲区 | 国产精品一区二区视频| 海角社区69精品视频| 免费观看一区| 国产精品超碰97尤物18| 久久久精品免费视频| 欧美韩日精品| 久久精品国产一区二区三| 美女任你摸久久| 亚洲影院污污.| 久久久久久一区| 亚洲综合导航| 欧美激情第五页| 久久精品国产在热久久| 欧美日韩国产区| 麻豆精品在线视频| 国产精品毛片a∨一区二区三区| 欧美成人dvd在线视频| 国产精品老牛| 亚洲激情精品| 在线日韩欧美视频| 亚洲免费网址| 亚洲一区二区在线播放| 你懂的国产精品永久在线| 久久超碰97人人做人人爱| 欧美剧在线免费观看网站| 久久综合给合| 国产日本欧美视频| 一区二区三区四区国产| 日韩特黄影片| 欧美大片一区二区三区| 另类av一区二区| 国产午夜久久| 亚洲欧美日韩精品久久| 亚洲免费影视| 欧美日韩午夜视频在线观看| 亚洲高清毛片| 亚洲精品久久久久久久久| 久久久久久亚洲精品不卡4k岛国| 午夜在线观看免费一区| 欧美午夜免费电影| 日韩午夜av在线| 亚洲午夜久久久久久久久电影网| 欧美黄色免费| 91久久精品国产91久久性色tv | 欧美精品aa| 亚洲第一二三四五区| 影音先锋亚洲精品| 欧美一区国产一区| 久久精品日产第一区二区| 国产嫩草一区二区三区在线观看 | 久久爱www| 久久综合99re88久久爱| 伊人久久综合| 欧美成人日韩| 日韩性生活视频| 亚洲影院在线观看| 国产精品系列在线播放| 亚洲欧美欧美一区二区三区| 亚洲欧美偷拍卡通变态| 国产麻豆视频精品| 久久精品国语| 亚洲国产精品一区在线观看不卡 | 一本久道久久综合中文字幕| 一区二区久久| 性做久久久久久免费观看欧美| 国产精品免费福利| 欧美一级专区| 嫩草国产精品入口| 亚洲精品乱码久久久久| 欧美三级日本三级少妇99| 一本一本a久久| 久久精品免费播放| 亚洲电影免费在线| 欧美日韩免费看| 久久精品国产亚洲一区二区| 亚洲第一精品夜夜躁人人爽| 夜色激情一区二区| 国产日韩欧美不卡| 玖玖视频精品| 一本色道久久综合狠狠躁篇怎么玩| 欧美一区二区成人6969| 最新中文字幕一区二区三区| 欧美亚洲第一页| 久久亚洲综合| 亚洲专区国产精品| 亚洲电影免费观看高清完整版在线| 亚洲午夜性刺激影院| 一区久久精品| 国产精品久久久免费| 美日韩精品免费观看视频| 亚洲一级特黄| 最新日韩欧美| 久久婷婷人人澡人人喊人人爽| 9l国产精品久久久久麻豆| 国内精品免费午夜毛片| 欧美视频在线观看免费网址| 久久久久久9999| 亚洲欧美国产精品va在线观看| 亚洲日本精品国产第一区| 久久综合色天天久久综合图片| 亚洲欧美www| 99精品视频免费观看视频| 精久久久久久| 国产亚洲欧美激情| 国产精品成人一区二区艾草| 欧美成人久久| 巨乳诱惑日韩免费av| 欧美亚洲一区三区| 亚洲一级二级| 亚洲午夜在线观看视频在线| 亚洲精品视频在线播放| 亚洲国产精品久久久久秋霞不卡 |