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