| 關(guān)鍵字 串口原作者姓名 戚高
 介紹介紹工業(yè)控制領(lǐng)域利用串口和外圍設(shè)備進行通訊。
 讀者評分 25 評分次數(shù) 5 
 正文前言:
 總所周之,利用串口進行數(shù)據(jù)通訊在在通訊通訊領(lǐng)域重占有著重要的地位。利用RS232-RS485進行數(shù)據(jù)信號的采集和傳遞是VC編程的又一大熱點。串口通訊在通訊軟件重有著十分廣泛的應(yīng)用。如電話、傳真、視頻和各種控制等。在各種開發(fā)工具中間,VC由于功能強大和靈活,同時也得到了Microsoft的最大支持,所以在一般進行涉及硬件操作的通訊編程重,大都推薦使用VC作為開發(fā)工具。然而工業(yè)控制串口通訊這個又不同于一般的串口通訊程序,因為控制外圍設(shè)備傳送的大都是十六進制數(shù)據(jù)(BYTE類型),所以,為了提高程序的運行穩(wěn)定性,我們在編寫程序進行通訊時可以不考慮傳送BYTE類型數(shù)據(jù)的工作。
 串口通訊目前流行的方法大概有兩種:一是利用Microsoft提供的CMSCOMM控件進行通訊,不過現(xiàn)在很多程序員都覺應(yīng)該放棄這種方式。二是利用WINAPI函數(shù)進行編程,這種編程的難度最高,要求你要掌握很多的API函數(shù)。三是利用現(xiàn)在網(wǎng)絡(luò)上面提供的一些串口通訊控件進行編寫,比如CSerial類等。
 
 程序?qū)崿F(xiàn):
 我在經(jīng)過許多的項目的開發(fā)和實踐中發(fā)現(xiàn),采用WIN API函數(shù)進行串口的開發(fā)能夠給程序員很大的控件,并且程序運也很穩(wěn)定。所以我將與串口接觸的函數(shù)進行封裝,然后在各個工程中進行調(diào)用,效果還是比較好的,現(xiàn)將各個函數(shù)和調(diào)用方法列舉出來,希望對各位有所幫助。
 一、設(shè)置串口相關(guān)工作
 
 #define        MAXBLOCK 2048
 #define        XON 0x11
 #define        XOFF 0x13
 BOOL SetCom(HANDLE &m_hCom, const char *m_sPort, int BaudRate, int Databit, CString parity, CString stopbit)
 {
 COMMTIMEOUTS TimeOuts;                                ///串口輸出時間 超時設(shè)置
 DCB dcb;                                              ///與端口匹配的設(shè)備
 m_hCom=CreateFile(m_sPort, GENERIC_READ | GENERIC_WRITE, 0, NULL,
 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
 NULL); // 以重疊方式打開串口
 if(m_hCom==INVALID_HANDLE_VALUE)
 {
 AfxMessageBox("設(shè)置串口部分,串口打開失敗");   /////重疊方式 異步通信(INVALID_HANDLE_VALUE)函數(shù)失敗。
 return FALSE;
 }
 SetupComm(m_hCom,MAXBLOCK,MAXBLOCK);              //設(shè)置緩沖區(qū)
 memset(&TimeOuts,0,sizeof(TimeOuts));
 TimeOuts.ReadIntervalTimeout=MAXDWORD;           // 把間隔超時設(shè)為最大,把總超時設(shè)為0將導致ReadFile立即返回并完成操作
 TimeOuts.ReadTotalTimeoutMultiplier=0;           //讀時間系數(shù)
 TimeOuts.ReadTotalTimeoutConstant=0;            //讀時間常量
 TimeOuts.WriteTotalTimeoutMultiplier=50;       //總超時=時間系數(shù)*要求讀/寫的字符數(shù)+時間常量
 TimeOuts.WriteTotalTimeoutConstant=2000;       //設(shè)置寫超時以指定WriteComm成員函數(shù)中的
 SetCommTimeouts(m_hCom, &TimeOuts);           //GetOverlappedResult函數(shù)的等待時間*/
 if(!GetCommState(m_hCom, &dcb))               ////串口打開方式、端口、波特率 與端口匹配的設(shè)備
 {
 AfxMessageBox("GetCommState Failed");
 return FALSE;
 }
 
 dcb.fParity=TRUE;                          //允許奇偶校驗
 dcb.fBinary=TRUE;
 if(parity=="NONE")
 dcb.Parity=NOPARITY;
 if(parity=="ODD")
 dcb.Parity=ODDPARITY;
 if(parity=="EVEN")
 dcb.Parity=EVENPARITY;
 if(stopbit=="1")//設(shè)置波特率
 dcb.StopBits=ONESTOPBIT;
 //if(stopbit=="0")//設(shè)置波特率
 //    dcb.StopBits=NONESTOPBIT;
 if(stopbit=="2")//設(shè)置波特率
 dcb.StopBits=TWOSTOPBITS;
 BOOL m_bEcho=FALSE;                        ///
 int m_nFlowCtrl=0;
 BOOL m_bNewLine=FALSE;                     ///
 dcb.BaudRate=BaudRate;                     // 波特率
 dcb.ByteSize=Databit;                     // 每字節(jié)位數(shù)
 // 硬件流控制設(shè)置
 dcb.fOutxCtsFlow=m_nFlowCtrl==1;
 dcb.fRtsControl=m_nFlowCtrl==1    ?RTS_CONTROL_HANDSHAKE:RTS_CONTROL_ENABLE;
 // XON/XOFF流控制設(shè)置(軟件流控制?。?BR>    dcb.fInX=dcb.fOutX=m_nFlowCtrl==2;
 dcb.XonChar=XON;
 dcb.XoffChar=XOFF;
 dcb.XonLim=50;
 dcb.XoffLim=50;
 if(SetCommState(m_hCom, &dcb))
 return TRUE;          ////com的通訊口設(shè)置
 else
 {
 AfxMessageBox("串口已打開,設(shè)置失敗");
 return FALSE;
 }
 }
 
 二、讀串口操作:
 int ReadCom(HANDLE hComm, BYTE inbuff[], DWORD &nBytesRead, int ReadTime)
 {
 DWORD lrc;                                 ///縱向冗余校驗
 DWORD endtime;                            /////////jiesuo
 static OVERLAPPED ol;
 int ReadNumber=0;
 int numCount=0 ;                             //控制讀取的數(shù)目
 DWORD dwErrorMask,nToRead;
 COMSTAT comstat;
 ol.Offset=0;                            ///相對文件開始的字節(jié)偏移量
 ol.OffsetHigh=0;                        ///開始傳送數(shù)據(jù)的字節(jié)偏移量的高位字,管道和通信時調(diào)用進程可忽略。
 ol.hEvent=NULL;                         ///標識事件,數(shù)據(jù)傳送完成時設(shè)為信號狀態(tài)
 ol.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
 endtime=GetTickCount()+ReadTime;//GetTickCount()取回系統(tǒng)開始至此所用的時間(毫秒)
 for(int i=0;i<2000;i++)
 inbuff[i]=0;
 Sleep(ReadTime);
 ClearCommError(hComm,&dwErrorMask,&comstat);
 nToRead=min(2000,comstat.cbInQue);
 if(int(nToRead)<2)
 goto Loop;
 if(!ReadFile(hComm,inbuff,nToRead,&nBytesRead,&ol))
 {
 if((lrc=GetLastError())==ERROR_IO_PENDING)
 {
 ///////////////////
 endtime=GetTickCount()+ReadTime;//GetTickCount()取回系統(tǒng)開始至此所用的時間(毫秒)
 while(!GetOverlappedResult(hComm,&ol,&nBytesRead,FALSE))//該函數(shù)取回重疊操作的結(jié)果
 {
 if(GetTickCount()>endtime)
 break;
 }
 }
 }
 return 1;
 Loop:  return 0;
 }
 
 三、寫串口命令
 int WriteCom(HANDLE hComm, BYTE Outbuff[], int size, int bWrite[])
 {
 DWORD nBytesWrite,endtime,lrc;
 static OVERLAPPED ol;
 DWORD dwErrorMask,dwError;
 COMSTAT comstat;
 ol.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
 ol.Offset=0;
 ol.OffsetHigh=0;
 ol.hEvent=NULL;               ///標識事件,數(shù)據(jù)傳送完成時,將它設(shè)為信號狀態(tài)
 ClearCommError(hComm,&dwErrorMask,&comstat);
 if(!WriteFile(hComm,Outbuff,size,&nBytesWrite,&ol))
 {
 if((lrc=GetLastError())==ERROR_IO_PENDING)
 {
 endtime=GetTickCount()+1000;
 while(!GetOverlappedResult(hComm,&ol,&nBytesWrite,FALSE))
 {
 dwError=GetLastError();
 if(GetTickCount()>endtime)
 {
 AfxMessageBox("寫串口時間過長,目前串口發(fā)送緩沖區(qū)中的數(shù)據(jù)數(shù)目為空");
 break;
 }
 if(dwError=ERROR_IO_INCOMPLETE)
 continue;          //未完全讀完時的正常返回結(jié)果
 else
 {
 //    發(fā)生錯誤,嘗試恢復!
 ClearCommError(hComm,&dwError,&comstat);
 break;
 }
 }
 }
 }
 FlushFileBuffers(hComm);
 PurgeComm(hComm,PURGE_TXCLEAR);
 bWrite=0;
 return 1;
 }
 
 四、調(diào)用方法很簡單,只需要將你的串口參數(shù)進行簡單的設(shè)置就可以了。比如:
 BOOL Main_OpenCom()//設(shè)置COM
 {
 int Boundrate=9600;//波特率
 CString StopBits="1";//停止位
 int DataBits=8;//數(shù)據(jù)位
 CString Parity="ODD";//奇偶校驗
 CString m_Port="COM1";
 return SetCom(m_hCom1,m_Port,Boundrate,DataBits,Parity,StopBits);
 }
 
 void Main()
 {
 int SIZE;
 DWORD BytestoRead=52*Count+6;//要11個字節(jié)
 int  BWRITE[2];
 int ReadTime=2000;
 BYTE Outbuff[12]={0xff,0x00,0xea,0xff,0xea,0xff,0,0,0,0,0,0};
 SIZE=sizeof(Outbuff);
 WriteCom(m_hCom,Outbuff,SIZE,BWRITE);
 ReadCom(m_hCom,m_Inbuff,BytestoRead,ReadTime);
 //進行湘陰的解包處理
 }
 
 |