VC 串口通信类
为了节省时间,我就贴出来吧
头文件 SerialPort.h
1 /*************************************************************************************************** 2 * SerialPort.h 3 * 4 * 功 能:串口通讯类 5 * 类 名:CSerialPort 6 * 7 * Ver 变更日期 负责人 变更内容 8 * ───────────────────────────────────────────────────── 9 * V1.0.0.0 2015年8月27日 金胖胖 新建 10 * 11 *****************************************************************************************************/ 12 13 #pragma once 14 #include "StdAfx.h" 15 16 #define FC_DTRDSR 0x01 17 #define FC_RTSCTS 0x02 18 #define FC_XONXOFF 0x04 19 #define ASCII_BEL 0x07 20 #define ASCII_BS 0x08 21 #define ASCII_LF 0x0A 22 #define ASCII_CR 0x0D 23 #define ASCII_XON 0x11 24 #define ASCII_XOFF 0x13 25 26 class CSerial 27 { 28 public: 29 CSerial(); 30 ~CSerial(); 31 32 // 打开串口 33 BOOL Open( int nPort = 2, int nBaud = 9600 ); 34 35 // 关闭串口 36 BOOL Close( void ); 37 38 // 读取数据 39 int ReadData( void *, int ); 40 41 //发送数据 42 int SendData( const char *, int ); 43 44 // 45 int ReadDataWaiting( void ); 46 47 // 是否打开串口 48 BOOL IsOpened( void ); 49 50 // 清空缓冲区 51 void ClearBuffer(void); 52 53 // 获取计算机中的所有串口号 54 vector<string> GetPortNames(); 55 56 // 十六进制数据 转换到 字符串 57 CString HexToStr(unsigned char *lpDataBuffer,int Total); 58 protected: 59 60 BOOL WriteCommByte( unsigned char ); 61 HANDLE m_hIDComDev; // 串口文件句柄 62 OVERLAPPED m_OverlappedRead; 63 OVERLAPPED m_OverlappedWrite; 64 BOOL m_bOpened; // 是否打开标识 65 };
实现文件 SerialPort.cpp
1 /*************************************************************************************************** 2 * Serial.cpp 3 * 4 * 功 能:串口通讯类 5 * 类 名:CSerial 6 * 参考文献:http://blog.csdn.net/zw0558/article/details/4465835 7 * 参考文献:http://blog.csdn.net/cp1300/article/details/40591699 8 * 参考文献:http://dev.21tx.com/2001/08/01/10054.shtml 9 * Ver 变更日期 负责人 变更内容 10 * ───────────────────────────────────────────────────── 11 * V1.0.0.0 2015年8月27日 金胖胖 新建 12 * 13 *****************************************************************************************************/ 14 #pragma region Include 15 16 #include "stdafx.h" 17 #include "Serial.h" 18 CRITICAL_SECTION sec; 19 20 #pragma endregion Include 21 22 #pragma region 构造 析构函数 23 24 CSerial::CSerial() 25 { 26 27 memset( &this->m_OverlappedRead, 0, sizeof( OVERLAPPED ) ); 28 memset( &this->m_OverlappedWrite, 0, sizeof( OVERLAPPED ) ); 29 this->m_hIDComDev = NULL; 30 this->m_bOpened = FALSE; 31 32 } 33 34 35 CSerial::~CSerial() 36 { 37 this->Close(); 38 } 39 40 #pragma endregion 构造 析构函数 41 42 /***************************************************/ 43 /* 函数: 获取计算机中的所有串口号 44 /* 返回: vector<string> 45 /* 创建人: 日期 内容 46 /* 金胖胖 2015年8月27日 新建 47 /***************************************************/ 48 vector<string> CSerial::GetPortNames() 49 { 50 vector<string> vecArr; 51 52 int i = 0; 53 CHAR Name[25]; 54 UCHAR szPortName[25]; 55 LONG Status; 56 DWORD dwIndex = 0; 57 DWORD dwName; 58 DWORD dwSizeofPortName; 59 DWORD Type; 60 HKEY hKey; 61 CString strSerialList[256]; // 临时定义 256 个字符串组,因为系统最多也就 256 个 62 LPCTSTR data_Set="HARDWARE\\DEVICEMAP\\SERIALCOMM\\"; 63 dwName = sizeof(Name); 64 dwSizeofPortName = sizeof(szPortName); 65 long ret0 = RegOpenKeyEx(HKEY_LOCAL_MACHINE, data_Set, 0, KEY_READ, &hKey); //打开一个制定的注册表键,成功返回ERROR_SUCCESS即“0”值 66 if(ret0 == ERROR_SUCCESS) 67 { 68 do 69 { 70 Status = RegEnumValue(hKey, dwIndex++, Name, &dwName, NULL, &Type, szPortName, &dwSizeofPortName);//读取键值 71 if((Status == ERROR_SUCCESS)||(Status == ERROR_MORE_DATA)) 72 { 73 strSerialList[i] = CString(szPortName); // 串口字符串保存 74 vecArr.push_back(strSerialList[i].GetBuffer(0)); 75 i++;// 串口计数 76 } 77 //每读取一次dwName和dwSizeofPortName都会被修改 78 //注意一定要重置,否则会出现很离奇的错误,本人就试过因没有重置,出现先插入串口号大的(如COM4),再插入串口号小的(如COM3),此时虽能发现两个串口,但都是同一串口号(COM4)的问题,同时也读不了COM大于10以上的串口 79 dwName = sizeof(Name); 80 dwSizeofPortName = sizeof(szPortName); 81 } while((Status == ERROR_SUCCESS)||(Status == ERROR_MORE_DATA)); 82 RegCloseKey(hKey); 83 } 84 return vecArr ; 85 } 86 87 /***************************************************/ 88 /* 函数: 打开串口 89 /* 参数: int 串口号 90 /* 参数: int 波特率 91 /* 返回: BOOL 是否成功 92 /* 创建人: 日期 内容 93 /* 金胖胖 2015年8月31日 新建 94 /***************************************************/ 95 BOOL CSerial::Open( int nPort, int nBaud ) 96 { 97 98 DWORD dwErrorFlags; 99 COMSTAT ComStat; 100 101 ::ClearCommError( this->m_hIDComDev, &dwErrorFlags, &ComStat ); 102 103 if( this->m_bOpened ) return( TRUE ); 104 105 char szPort[15]; 106 char szComParams[50]; 107 DCB dcb; 108 109 wsprintf( szPort, "COM%d", nPort ); 110 this->m_hIDComDev = ::CreateFile( szPort, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL ); 111 if( this->m_hIDComDev == NULL ) return( FALSE ); 112 113 memset( &this->m_OverlappedRead, 0, sizeof( OVERLAPPED ) ); 114 memset( &this->m_OverlappedWrite, 0, sizeof( OVERLAPPED ) ); 115 116 COMMTIMEOUTS CommTimeOuts; 117 CommTimeOuts.ReadIntervalTimeout = 0xFFFFFFFF; 118 CommTimeOuts.ReadTotalTimeoutMultiplier = 0; 119 CommTimeOuts.ReadTotalTimeoutConstant = 0; 120 CommTimeOuts.WriteTotalTimeoutMultiplier = 0; 121 CommTimeOuts.WriteTotalTimeoutConstant = 5000; 122 ::SetCommTimeouts( this->m_hIDComDev, &CommTimeOuts ); 123 124 wsprintf( szComParams, "COM%d:%d,n,8,1", nPort, nBaud ); 125 126 this->m_OverlappedRead.hEvent = ::CreateEvent( NULL, TRUE, FALSE, NULL ); 127 this->m_OverlappedWrite.hEvent = ::CreateEvent( NULL, TRUE, FALSE, NULL ); 128 129 dcb.DCBlength = sizeof( DCB ); 130 ::GetCommState( m_hIDComDev, &dcb ); 131 dcb.BaudRate = nBaud; 132 dcb.ByteSize = 8; 133 unsigned char ucSet; 134 ucSet = (unsigned char) ( ( FC_RTSCTS & FC_DTRDSR ) != 0 ); 135 ucSet = (unsigned char) ( ( FC_RTSCTS & FC_RTSCTS ) != 0 ); 136 ucSet = (unsigned char) ( ( FC_RTSCTS & FC_XONXOFF ) != 0 ); 137 if( !::SetCommState( this->m_hIDComDev, &dcb ) ||!::SetupComm( this->m_hIDComDev, 10000, 10000 ) ||this->m_OverlappedRead.hEvent == NULL ||this->m_OverlappedWrite.hEvent == NULL ) 138 { 139 DWORD dwError = GetLastError(); 140 if( this->m_OverlappedRead.hEvent != NULL ) ::CloseHandle( this->m_OverlappedRead.hEvent ); 141 if( this->m_OverlappedWrite.hEvent != NULL ) ::CloseHandle( this->m_OverlappedWrite.hEvent ); 142 ::CloseHandle( this->m_hIDComDev ); 143 return( FALSE ); 144 } 145 146 this->m_bOpened = TRUE; 147 return( this->m_bOpened ); 148 149 } 150 151 /***************************************************/ 152 /* 函数: 关闭函数 153 /* 返回: BOOL 是否成功 154 /* 创建人: 日期 内容 155 /* 金胖胖 2015年8月31日 新建 156 /***************************************************/ 157 BOOL CSerial::Close( void ) 158 { 159 160 if( !this->m_bOpened || this->m_hIDComDev == NULL ) return( TRUE ); 161 162 if( this->m_OverlappedRead.hEvent != NULL ) ::CloseHandle( this->m_OverlappedRead.hEvent ); 163 if( this->m_OverlappedWrite.hEvent != NULL ) ::CloseHandle( this->m_OverlappedWrite.hEvent ); 164 ::CloseHandle( this->m_hIDComDev ); 165 this->m_bOpened = FALSE; 166 this->m_hIDComDev = NULL; 167 return( TRUE ); 168 169 } 170 171 /***************************************************/ 172 /* 函数: 写串口数据 字节 173 /* 参数: unsigned char 字节 174 /* 返回: BOOL 是否成功 175 /* 创建人: 日期 内容 176 /* 金胖胖 2015年8月31日 新建 177 /***************************************************/ 178 BOOL CSerial::WriteCommByte( unsigned char ucByte ) 179 { 180 BOOL bWriteStat; 181 DWORD dwBytesWritten; 182 183 bWriteStat = ::WriteFile( this->m_hIDComDev, (LPSTR) &ucByte, 1, &dwBytesWritten, &m_OverlappedWrite ); 184 if( !bWriteStat && ( GetLastError() == ERROR_IO_PENDING ) ){ 185 if( ::WaitForSingleObject( this->m_OverlappedWrite.hEvent, 1000 ) ) dwBytesWritten = 0; 186 else{ 187 ::GetOverlappedResult( this->m_hIDComDev, &this->m_OverlappedWrite, &dwBytesWritten, FALSE ); 188 this->m_OverlappedWrite.Offset += dwBytesWritten; 189 } 190 } 191 192 return( TRUE ); 193 194 } 195 196 /***************************************************/ 197 /* 函数: 发送数据 198 /* 参数: const char 缓冲区 199 /* 参数: int 长度 200 /* 返回: int 发送的成功的长度 201 /* 创建人: 日期 内容 202 /* 金胖胖 2015年8月31日 新建 203 /***************************************************/ 204 int CSerial::SendData( const char *buffer, int size ) 205 { 206 207 if( !this->m_bOpened || this->m_hIDComDev == NULL ) return( 0 ); 208 209 DWORD dwBytesWritten = 0; 210 int i; 211 for( i=0; i<size; i++ ){ 212 this->WriteCommByte( buffer[i] ); 213 dwBytesWritten++; 214 } 215 return( (int) dwBytesWritten ); 216 } 217 218 /***************************************************/ 219 /* 函数: 清除错误信息 获取通讯状态 220 /* 返回: int 通讯状态 221 /* 创建人: 日期 内容 222 /* 金胖胖 2015年8月31日 新建 223 /***************************************************/ 224 int CSerial::ReadDataWaiting( void ) 225 { 226 227 if( !this->m_bOpened || this->m_hIDComDev == NULL ) return( 0 ); 228 229 DWORD dwErrorFlags; 230 COMSTAT ComStat; 231 232 ::ClearCommError( this->m_hIDComDev, &dwErrorFlags, &ComStat ); 233 234 return( (int) ComStat.cbInQue ); 235 236 } 237 238 /***************************************************/ 239 /* 函数: 读取数据 240 /* 参数: void * 缓冲区 241 /* 参数: int 缓冲区长度 242 /* 返回: int 读到的字节数 243 /* 创建人: 日期 内容 244 /* 金胖胖 2015年8月31日 新建 245 /***************************************************/ 246 int CSerial::ReadData( void *buffer, int limit ) 247 { 248 249 if( !this->m_bOpened || this->m_hIDComDev == NULL ) 250 return( 0 ); 251 252 BOOL bReadStatus; 253 DWORD dwBytesRead, dwErrorFlags; 254 COMSTAT ComStat; 255 256 ::ClearCommError( this->m_hIDComDev, &dwErrorFlags, &ComStat );//清空错误信息 257 if( !ComStat.cbInQue ) 258 return( 0 ); 259 260 dwBytesRead = (DWORD) ComStat.cbInQue; 261 if( limit < (int) dwBytesRead ) 262 dwBytesRead = (DWORD) limit; 263 264 bReadStatus = ::ReadFile( this->m_hIDComDev, buffer, dwBytesRead, &dwBytesRead, &m_OverlappedRead ); 265 if( !bReadStatus ) 266 { 267 if( GetLastError() == ERROR_IO_PENDING ) 268 { 269 ::WaitForSingleObject( this->m_OverlappedRead.hEvent, 2000 ); 270 return( (int) dwBytesRead ); 271 } 272 return( 0 ); 273 } 274 275 return( (int) dwBytesRead ); 276 } 277 278 /***************************************************/ 279 /* 函数: 清空缓冲区 280 /* 返回: void 281 /* 创建人: 日期 内容 282 /* 金胖胖 2015年8月31日 新建 283 /***************************************************/ 284 void CSerial::ClearBuffer() 285 { 286 ::PurgeComm(this->m_hIDComDev,PURGE_RXABORT | PURGE_RXCLEAR );//| PURGE_TXABORT | PURGE_TXCLEAR 287 } 288 289 /***************************************************/ 290 /* 函数: 串口是否打开 291 /* 返回: BOOL 是否打开 292 /* 创建人: 日期 内容 293 /* 金胖胖 2015年8月31日 新建 294 /***************************************************/ 295 BOOL CSerial::IsOpened( void ) 296 { 297 return( this->m_bOpened ); 298 } 299 300 /***************************************************/ 301 /* 函数: 十六进制数据 转换到 字符串 302 /* 参数: unsigned char * 缓冲区 303 /* 参数: int 长度 304 /* 返回: CString 转换成功的字符串 305 /* 创建人: 日期 内容 306 /* 金胖胖 2015年8月31日 新建 307 /***************************************************/ 308 CString CSerial::HexToStr(unsigned char *lpDataBuffer,int Total) 309 { 310 CString ReturnStr; 311 char OneNumber[5]; 312 313 ReturnStr.Empty(); 314 memset(OneNumber,0,5); 315 316 for(int i=0;i<Total;i++) 317 { 318 itoa(lpDataBuffer[i],OneNumber,16); 319 320 if(strlen(OneNumber) < 2) 321 { 322 OneNumber[2] = OneNumber[1]; 323 OneNumber[1] = OneNumber[0]; 324 OneNumber[0] = '0'; 325 } 326 ReturnStr+=OneNumber; 327 ReturnStr+=","; 328 memset(OneNumber,0,5); 329 } 330 331 return ReturnStr; 332 }