谢谢支持!
修改一下更好用
-------------------------------------------------------------------------------------------------------
//**********************************************************************************// /** File Name(文件名): SaimIO.h: interface for the CSaimIO class. Author(作者): Wenjin Hu 胡文晋 (eg. Saimen Hu) Version(版本): 1.0 Date(完成日期): 2000.10.10 Description(介绍): 用于 COM 口的读写类,完成对COM 口的选取,COM口的初始化。 对COM口的读写操作。
typedef struct tagIOINFO { HANDLE idComDev; BYTE bPort; BOOL fConnected,fXonXoff; BYTE bByteSize,bFlowCtrl,bParity,bStopBits; DWORD dwBaudRate; OVERLAPPED osWrite,osRead; }IOINFO;
配置串口通信的数据结构
HANDLE idComDev 为串口句柄 BYTE bPort 为串口号 BOOL fConnected 为是否连接 BYTE bByteSize 为字节数 BYTE bFlowCtrl 流量控制 BYTE bParity 校检类型 BYTE bStopBits 停止位 DWORD dwBaudRate 波特率 OVERLAPPED osWrite,osRead 读写事件及时限 **/ //***********************************************************************************//
// Flow control flags 流量控制类型 //
#define FC_DTRDSR 0x01 #define FC_RTSCTS 0x02 #define FC_XONXOFF 0x04
// ascii definitions 流量控制字符 // #define ASCII_XON 0x11 #define ASCII_XOFF 0x13
typedef struct tagIOINFO { HANDLE idComDev; BYTE bPort; BOOL fConnected,fXonXoff; BYTE bByteSize,bFlowCtrl,bParity,bStopBits; DWORD dwBaudRate; OVERLAPPED osWrite,osRead; }IOINFO;
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_SAIMIO_H__A2648CC2_9DBF_11D4_96BD_E54AFA740DAA__INCLUDED_) #define AFX_SAIMIO_H__A2648CC2_9DBF_11D4_96BD_E54AFA740DAA__INCLUDED_
#if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000
#define MSG_NEW_IODATA WM_USER+100
class CSaimIO : public CFile { public: CSaimIO(); virtual ~CSaimIO(); public: void ResumeThread(); void SuspandThread(); BOOL ConnectCom(LPTSTR initStr); BOOL EndListern(); BOOL BeginListen(); void ClearIObuffer(); CString HexToStr(unsigned char *lpDataBuffer,int Total); void StrToHex(unsigned char *lpBuffer,int *Total); void InitaiseIO(); void SetIO(IOINFO SetIoInfo); BOOL DisConnect(); DWORD GetData(unsigned char *DataBuffer,DWORD DataLength); BOOL SendData(unsigned char *lpCommand,DWORD CmdLength); BOOL Connect();
IOINFO IoInfoData;
protected:
// 监听线程数据 private: BOOL ThreadIsRun(); HANDLE hListenThread; DWORD dwThreadID; // DWORD WINAPI ListenThread(LPVOID lpParameter); };
// 监听线程 DWORD WINAPI ListenThread(LPVOID lpParameter);
#endif // !defined(AFX_SAIMIO_H__A2648CC2_9DBF_11D4_96BD_E54AFA740DAA__INCLUDED_)
---------------------------------------------------------------------------------------------------
//**********************************************************************************// /** File Name(文件名): SaimIO.cpp: implementation of the CSaimIO class. Author(作者): Wenjin Hu 胡文晋 (eg. Saimen Hu) Version(版本): 1.0 Date(完成日期): 2000.10.10 Description(介绍): 用于 COM 口的读写类,完成对COM 口的选取,COM口的初始化。 对COM口的读写操作。
Other(其它备注): 完成对串口的读写有两种情况:1.计算机之间通信 2.计算机和其它设备通信 对于这两种情况要注意在初始化COM的DCB结构时,成员不同的值对通信产后不 同的效果,也许是非常严重的。例下面:
如果把下面两个成员的值赋为以下情况
dcb.fDtrControl = DTR_CONTROL_ENABLE ;
dcb.fRtsControl = RTS_CONTROL_ENABLE ;
此时不能完成计算机和其它设备之间通信。
改为以下值就可以完成和其它设备能信。
dcb.fDtrControl = DTR_CONTROL_DISABLE ; dcb.fRtsControl = RTS_CONTROL_ENABLE ;
Funtion List(主要函数): 1. void InitaiseIO() 用来对串口IOINFO 数据结构初始化为默认值 2. void SetIO(IOINFO SetIoInfo) 调用该函数用来修改IOINFO数据结构,配置串口 说明:该函数在 CONNECT 之前调用。 3. BOOL Connect() 用来连接串口,使用IOINFO中的数据结构,如果成功返回 TRUE; 不成功返回 FALSE; 4. BOOL DisConnect() 关闭对串口的连接,成功返回: TRUE 否则返回:FALSE 5. BOOL SendData(unsigned char *lpCommand,DWORD CmdLength) 向串口发送数据,数据长度为 CmdLength,lpCommand 为指向该命令的指针。 6. BOOL GetData(unsigned char *Databuffer,int DataLength) 读取串口缓冲中的数据。
History(修改记录): 1.Date: 2000.10.11 Author: 胡文晋 (EG. Saim Hu) Modification: 添加函数: CString CSaimIO::HexToStr(unsigned char *lpDataBuffer) 功 能: 将入口参数unsigned char * DataBuffer 转换为CString 字符串
2.Date: 2000.11.10 Author: 胡文晋 (EG. Saim Hu) Modifcation:
**/ //*******************************************************************************// ///////////////////////////////////////////////////////////////////////////////////
#include "stdafx.h" #include "SaimIO.h"
#ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[]=__FILE__; #define new DEBUG_NEW #endif
extern BOOL KillListenThread ;
////////////////////////////////////////////////////////////////////// // Construction/Destruction //////////////////////////////////////////////////////////////////////
CSaimIO::CSaimIO() { InitaiseIO(); hListenThread = NULL; }
CSaimIO::~CSaimIO() {
} // 以默认方式初始化串口 void CSaimIO::InitaiseIO() { IoInfoData.idComDev = 0 ; IoInfoData.bByteSize = 8 ; IoInfoData.fConnected = FALSE; IoInfoData.bPort = 1 ; IoInfoData.dwBaudRate = CBR_4800; IoInfoData.bFlowCtrl = FALSE; //FC_XONXOFF; // FC_RTSCTS; //FC_XONXOFF; IoInfoData.bParity = EVENPARITY ; //MARKPARITY ; SPACEPARITY; ODDPARITY; IoInfoData.bStopBits = ONESTOPBIT; //ONE5STOPBITS; TWOSTOPBITS IoInfoData.osWrite.Offset = 0; IoInfoData.osWrite.OffsetHigh = 1024; IoInfoData.osRead.Offset = 0; IoInfoData.osRead.OffsetHigh = 1024; IoInfoData.osRead.hEvent = NULL; IoInfoData.osWrite.hEvent = NULL; }
// 修改串口数据结构 void CSaimIO::SetIO(IOINFO SetIoInfo) { IoInfoData.idComDev = SetIoInfo.idComDev ; IoInfoData.bByteSize = SetIoInfo.bByteSize ; IoInfoData.fConnected = SetIoInfo.fConnected; IoInfoData.bPort = SetIoInfo.bPort ; IoInfoData.dwBaudRate = SetIoInfo.dwBaudRate; IoInfoData.bFlowCtrl = SetIoInfo.bFlowCtrl; IoInfoData.bParity = SetIoInfo.bParity; IoInfoData.bStopBits = SetIoInfo.bStopBits; IoInfoData.osWrite.Offset = SetIoInfo.osWrite.Offset; IoInfoData.osWrite.OffsetHigh = SetIoInfo.osWrite.OffsetHigh; IoInfoData.osRead.Offset = SetIoInfo.osRead.Offset; IoInfoData.osRead.OffsetHigh = SetIoInfo.osRead.OffsetHigh; }
// Connect IO before use it. // 打开串开 BOOL CSaimIO::Connect() { BOOL fRetVal ; BYTE bSet ; DCB dcb ; char szPort[10];
memset(szPort,0,10);
wsprintf(szPort,"COM%d:",IoInfoData.bPort);
IoInfoData.idComDev = CreateFile(szPort,GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, NULL);
if( !IoInfoData.idComDev ) return FALSE;
if(!SetCommMask(IoInfoData.idComDev,EV_RXFLAG)) // EV_RXCHAR)) return FALSE;
// Alloc the buffer for Read and Write. if( SetupComm(IoInfoData.idComDev,4096,4096) == 0 ) return FALSE;
//Setup for overlapped I/O COMMTIMEOUTS CommTimesOuts;
CommTimesOuts.ReadIntervalTimeout = 100; CommTimesOuts.ReadTotalTimeoutMultiplier = 20; CommTimesOuts.ReadTotalTimeoutConstant = 1000 ;
CommTimesOuts.WriteTotalTimeoutMultiplier = 2*CBR_9600 / IoInfoData.dwBaudRate ; CommTimesOuts.WriteTotalTimeoutConstant = 1000;
SetCommTimeouts(IoInfoData.idComDev,&CommTimesOuts);
// Initise the com port. dcb.DCBlength = sizeof( DCB ) ;
GetCommState( IoInfoData.idComDev, &dcb ) ;
dcb.BaudRate = IoInfoData.dwBaudRate ; dcb.ByteSize = IoInfoData.bByteSize ; dcb.Parity = IoInfoData.bParity ; dcb.StopBits = IoInfoData.bStopBits ;
// setup hardware flow control
bSet = (BYTE) ((FC_RTSCTS & FC_DTRDSR) != 0) ; dcb.fOutxDsrFlow = bSet ;
dcb.fDtrControl = DTR_CONTROL_DISABLE ; //给予提供电源 , 新的 485 就不需要提供 dcb.fRtsControl = RTS_CONTROL_ENABLE ;
bSet = (BYTE) FC_RTSCTS ; dcb.fOutxCtsFlow = bSet ;
// setup software flow control
bSet = (BYTE) FC_XONXOFF ;
dcb.fInX = dcb.fOutX = bSet ; dcb.XonChar = ASCII_XON ; dcb.XoffChar = ASCII_XOFF ; dcb.XonLim = 100 ; dcb.XoffLim = 100 ;
// other various settings
dcb.fBinary = TRUE ; dcb.fParity = 1 ; // Enalble Parity
fRetVal = SetCommState( IoInfoData.idComDev, &dcb ) ;
if( fRetVal != FALSE ) IoInfoData.fConnected = TRUE; else return fRetVal;
//Ceate I/O event used for overlapped reads / writes IoInfoData.osRead.hEvent = CreateEvent( NULL , //no security TRUE , //explicit reset req FALSE , //initial event reset NULL); //no name
if( IoInfoData.osRead.hEvent == NULL ) { return FALSE; }
IoInfoData.osWrite.hEvent = CreateEvent( NULL , //no security TRUE , //explicit reset req FALSE , //initial event reset NULL); //no name if( IoInfoData.osWrite.hEvent == NULL ) { CloseHandle( IoInfoData.osRead.hEvent ); return FALSE; }
// Clear Read and Send IO buffer
if(PurgeComm(IoInfoData.idComDev,PURGE_RXCLEAR)== 0) return FALSE; if(PurgeComm(IoInfoData.idComDev,PURGE_TXCLEAR)== 0) return FALSE;
// Set The DataSet is ready TO Get Data EscapeCommFunction(IoInfoData.idComDev,SETDTR|SETRTS);
// set connected flag to TRUE
IoInfoData.fConnected = TRUE ;
return ( TRUE ) ; }
// Close IO when exit the program. // 关闭串口 BOOL CSaimIO::DisConnect() { if(IoInfoData.fConnected == FALSE ) return TRUE;
// Stop the Listen Thread EndListern();
// set connected flag to FALSE IoInfoData.fConnected = FALSE ;
// disable event notification and wait for thread // to halt SetCommMask( IoInfoData.idComDev , 0 ) ;
// drop DTR EscapeCommFunction( IoInfoData.idComDev, CLRDTR | CLRRTS) ;
// purge any outstanding reads/writes and close device handle if(PurgeComm( IoInfoData.idComDev, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR ) == 0 ) return TRUE; CloseHandle(IoInfoData.osRead.hEvent); CloseHandle(IoInfoData.osWrite.hEvent); return CloseHandle( IoInfoData.idComDev ) ;
}
// Send the Datas. // 写数据到串口 BOOL CSaimIO::SendData(unsigned char *lpCommand, DWORD dwBytesToWrite) { BOOL fWriteStat ; DWORD dwBytesWritten ; DWORD dwErrorFlags; DWORD dwError; DWORD dwBytesSent=0; COMSTAT ComStat; char szError[ 128 ] ;
if (IoInfoData.fConnected == FALSE ) return ( FALSE ) ;
fWriteStat = WriteFile( IoInfoData.idComDev , lpCommand, dwBytesToWrite, &dwBytesWritten,NULL) ; // &IoInfoData.osWrite ) ;
if(dwBytesWritten != dwBytesToWrite) return FALSE;
if (!fWriteStat) { if(GetLastError() == ERROR_IO_PENDING) { while(!GetOverlappedResult( IoInfoData.idComDev , &IoInfoData.osWrite, &dwBytesWritten, TRUE )) { dwError = GetLastError(); if(dwError == ERROR_IO_INCOMPLETE) { // normal result if not finished dwBytesSent += dwBytesWritten; continue; } else { // an error occurred, try to recover wsprintf( szError, "向串口发送数据出错,错误代码: %u", dwError ) ;
MessageBox(NULL,szError,"发送数据出错",MB_ICONEXCLAMATION);
ClearCommError( IoInfoData.idComDev , &dwErrorFlags, &ComStat ) ; break; } } } else { // some other error occurred ClearCommError( IoInfoData.idComDev , &dwErrorFlags, &ComStat ) ;
if (dwErrorFlags > 0) { wsprintf( szError, "向串口发送数据出错,错误代码: %u", dwErrorFlags ) ;
MessageBox(NULL,szError,"发送数据出错",MB_ICONEXCLAMATION); }
return ( FALSE ); } } return ( TRUE ) ;
} // end of SendData()
// Read the Datas. // 从串口中读出数据 DWORD CSaimIO::GetData(unsigned char *DataBuffer, DWORD DataLength) { BOOL fReadStat ; COMSTAT ComStat ; DWORD dwErrorFlags; DWORD dwLength = DataLength; DWORD dwError; char szError[ 128 ] ; if (IoInfoData.fConnected == FALSE) return ( FALSE ) ;
// SetCommMask( IoInfoData.idComDev ,EV_RXCHAR) ; //设定为收到第一个字符时产生中断
// unsigned long dwFlg; // WaitCommEvent(IoInfoData.idComDev , &dwFlg, &IoInfoData.osRead); //等侍收到第一个字符事件发生 // if( (dwFlg & ( EV_RXFLAG | EV_RXCHAR )) == (EV_RXFLAG | EV_RXCHAR) ) { // only try to read number of bytes in queue ClearCommError( IoInfoData.idComDev, &dwErrorFlags, &ComStat ) ; dwLength = min( 128, ComStat.cbInQue ) ;
if (dwLength > 0) { fReadStat = ReadFile( IoInfoData.idComDev, DataBuffer, dwLength, &dwLength, &IoInfoData.osRead ); if (!fReadStat) { if (GetLastError() == ERROR_IO_PENDING) { // We have to wait for read to complete. // This function will timeout according to the // CommTimeOuts.ReadTotalTimeoutConstant variable // Every time it times out, check for port errors while(!GetOverlappedResult( IoInfoData.idComDev, &IoInfoData.osRead, &dwLength, TRUE )) { dwError = GetLastError(); if(dwError == ERROR_IO_INCOMPLETE) // normal result if not finished continue; else { // an error occurred, try to recover wsprintf( szError, "向串口发送数据出错,错误代码: %u", dwError ) ;
MessageBox(NULL,szError,"发送数据出错",MB_ICONEXCLAMATION);
ClearCommError( IoInfoData.idComDev, &dwErrorFlags, &ComStat ) ; if (dwErrorFlags > 0) { wsprintf( szError, "向串口发送数据出错,错误代码: %u", dwError ) ;
MessageBox(NULL,szError,"发送数据出错",MB_ICONEXCLAMATION); } break; } } } else { // some other error occurred dwLength = 0 ; ClearCommError( IoInfoData.idComDev, &dwErrorFlags, &ComStat ) ; if (dwErrorFlags > 0 ) { wsprintf( szError, "向串口发送数据出错,错误代码: %u", dwErrorFlags ) ;
MessageBox(NULL,szError,"发送数据出错",MB_ICONEXCLAMATION); } } } } }
return ( dwLength ) ; }
// 把字符串转换为十六进制数据 void CSaimIO::StrToHex(unsigned char *lpBuffer, int *Total) { if(((*Total) % 2) != 0) { strcat((char *)lpBuffer,"0"); (*Total) ++; }
unsigned char HexBuffer[1024];
memset(HexBuffer,'\0',1024);
int i ; for( i = 0 ; i < (*Total) ; i++) { if(lpBuffer[i] > 0x39) lpBuffer[i] -= 0x37 ; else lpBuffer[i] -= 0x30 ; }
for(i=0 ; i < (*Total) ; i+=2) { HexBuffer[i/2] = lpBuffer[i] ; HexBuffer[i/2] <<= 4;
HexBuffer[i/2] |= lpBuffer[i+1]; }
memcpy(lpBuffer,HexBuffer,(*Total)/2); }
// 把十六进制数据转换为字符串 CString CSaimIO::HexToStr(unsigned char *lpDataBuffer,int Total) { CString ReturnStr; char OneNumber[5];
ReturnStr.Empty(); memset(OneNumber,0,5);
for(int i=0;i<Total;i++) { itoa(lpDataBuffer[i],OneNumber,16);
if(strlen(OneNumber) < 2) { OneNumber[2] = OneNumber[1]; OneNumber[1] = OneNumber[0]; OneNumber[0] = '0'; } ReturnStr+=OneNumber; ReturnStr+=", "; memset(OneNumber,0,5); } return ReturnStr; } // 清空串口缓冲 void CSaimIO::ClearIObuffer() { if(PurgeComm(IoInfoData.idComDev,PURGE_RXCLEAR)== 0) return ; if(PurgeComm(IoInfoData.idComDev,PURGE_TXCLEAR)== 0) return ; }
// 开始对串口监听 BOOL CSaimIO::BeginListen() { if(IoInfoData.fConnected == FALSE) return FALSE; // 判断线程是还在否运行 if(ThreadIsRun()) return TRUE;
hListenThread = CreateThread((LPSECURITY_ATTRIBUTES)NULL, 0, (LPTHREAD_START_ROUTINE)ListenThread, (LPVOID)&IoInfoData, 0,&dwThreadID);
if( hListenThread == NULL) { DWORD dwError = GetLastError(); CString Msg; Msg.Format("Error code : %d",dwError); AfxMessageBox(Msg);
return FALSE; } else { return TRUE; } }
// 停止对串口监听 BOOL CSaimIO::EndListern() { if(IoInfoData.fConnected == FALSE) return TRUE;
if( hListenThread == NULL) return TRUE;
// 判断线程是还在否运行 if(!ThreadIsRun()) return TRUE;
KillListenThread = TRUE; Sleep(100);
// 如果线程还在运行异常终止监听线程 if(!TerminateThread( hListenThread,0)) { DWORD dwError = GetLastError(); CString Msg; Msg.Format("Error code : %d",dwError); AfxMessageBox(Msg);
return FALSE; } else return CloseHandle( hListenThread );
} // 打开串口,例如:Com1,9600,n,8,1 BOOL CSaimIO::ConnectCom(LPTSTR initStr) { char strTemp[10]; int i = 3; int j = 0;
// 读出串口号 while(initStr[i] != ',' && initStr[i] != '\0') { strTemp[j] = initStr[i]; i++; j++; if(j > 3) return FALSE; } strTemp[j] = '\0'; IoInfoData.bPort = atoi(strTemp);
// 读出波特率 i++; j=0; while(initStr[i]!=',' && initStr[i] != '\0') { strTemp[j] = initStr[i]; i++; j++; if(j > 6) return FALSE; } strTemp[j] = '\0';
if(strstr(strTemp,"256000") != NULL) { IoInfoData.dwBaudRate = CBR_256000; } else if(strstr(strTemp,"128000") != NULL) { IoInfoData.dwBaudRate = CBR_128000; } else if(strstr(strTemp,"115200") != NULL) { IoInfoData.dwBaudRate = CBR_115200; } else if(strstr(strTemp,"57600") != NULL) { IoInfoData.dwBaudRate = CBR_57600; } else if(strstr(strTemp,"56000") != NULL) { IoInfoData.dwBaudRate = CBR_56000; } else if(strstr(strTemp,"38400") != NULL) { IoInfoData.dwBaudRate = CBR_38400; } else if(strstr(strTemp,"19200") != NULL) { IoInfoData.dwBaudRate = CBR_19200; } else if(strstr(strTemp,"14400") != NULL) { IoInfoData.dwBaudRate = CBR_14400; } else if(strstr(strTemp,"9600") != NULL) { IoInfoData.dwBaudRate = CBR_9600; } else if(strstr(strTemp,"4800") != NULL) { IoInfoData.dwBaudRate = CBR_4800; } else if(strstr(strTemp,"2400") != NULL) { IoInfoData.dwBaudRate = CBR_2400; } else if(strstr(strTemp,"1200") != NULL) { IoInfoData.dwBaudRate = CBR_1200; } else if(strstr(strTemp,"600") != NULL) { IoInfoData.dwBaudRate = CBR_600; } else if(strstr(strTemp,"300") != NULL) { IoInfoData.dwBaudRate = CBR_300; } else if(strstr(strTemp,"110") != NULL) { IoInfoData.dwBaudRate = CBR_110; } else { IoInfoData.dwBaudRate = CBR_9600; }
//读出校验方式 i++; strTemp[0] = initStr[i]; strTemp[1] = '\0';
if(strstr(strTemp,"n")!=NULL) { IoInfoData.bParity = NOPARITY ; } else if(strstr(strTemp,"e")!=NULL) { IoInfoData.bParity = EVENPARITY ; } else if(strstr(strTemp,"o")!=NULL) { IoInfoData.bParity = ODDPARITY ; } else if(strstr(strTemp,"m")!=NULL) { IoInfoData.bParity = MARKPARITY ; } else if(strstr(strTemp,"s")!=NULL) { IoInfoData.bParity = SPACEPARITY ; } else { IoInfoData.bParity = NOPARITY ; } //读出数据位数 i++; i++; strTemp[0]=initStr[i]; IoInfoData.bByteSize = atoi(strTemp);
//读出停止位 i++; j = -1; do { i++; j++; strTemp[j] = initStr[i]; }while(initStr[i] == '\0');
if(strstr(strTemp,"1")!=NULL) { IoInfoData.bStopBits = ONESTOPBIT ; } else if(strstr(strTemp,"2")!=NULL) { IoInfoData.bStopBits = TWOSTOPBITS ; } else if(strstr(strTemp,"1.5")!=NULL) { IoInfoData.bStopBits = ONE5STOPBITS ; } else { IoInfoData.bStopBits = ONESTOPBIT ; }
return Connect(); }
// 判断线程是还在否运行 BOOL CSaimIO::ThreadIsRun() { DWORD lpExitCode; GetExitCodeThread(hListenThread,&lpExitCode); if(lpExitCode == STILL_ACTIVE) { return TRUE; } else { return FALSE; }
} //挂起线程 void CSaimIO::SuspandThread() { ::SuspendThread(hListenThread); } //唤醒线程 void CSaimIO::ResumeThread() { ::ResumeThread(hListenThread); }

|