cnComm.h
上传用户:hailongwei
上传日期:2020-11-29
资源大小:5839k
文件大小:12k
源码类别:

单片机开发

开发平台:

Visual C++

  1. /*
  2. 串口基础类库(WIN32) ver 0.2
  3. 编译器 : BC++ 5; C++ BUILDER 4, 5, 6, X; VC++ 5, 6; VC.NET;  GCC;
  4. 使用:
  5. 定义
  6. cnComm MyComm1(false, 0);//第1个参数为是否启动监视线程, 第2个参数为阻塞(0)/异步方式(默认)
  7. cnComm MyComm2;//默认启动监视线程, 异步
  8. cnComm MyComm3(true);//监视线程, 阻塞
  9. 打开
  10. MyComm1.Open(1);//1-1024  2k支持1024串口
  11. MyComm1.Open(1, 1200);
  12. MyComm1.Open(1, 9600);
  13. MyComm1.Open(1, "9600,8,n,1");//可使用标准的设置字符串
  14. MyComm1.SetBufferSize(1200, 4800)//设置缓冲区大小,可不用设置
  15. MyComm1.SetState("9600,8,n,1")//修改波特率等
  16. 读写
  17. MyComm1.Read(buf, 1000);
  18. MyComm1.Write(buf, 200);
  19. 窗口句柄
  20. MyComm1.SetWnd(hWnd);
  21. 线程控制下面都有注明就不说了
  22. copyright(c) 2004.8 llbird wushaojian@21cn.com
  23. */
  24. #ifndef _CN_COMM_H_
  25. #define _CN_COMM_H_
  26. #pragma warning(disable: 4530)
  27. #pragma warning(disable: 4786)
  28. #pragma warning(disable: 4800)
  29. #include <assert.h>
  30. #include <stdio.h>
  31. #include <windows.h>
  32. //当接受到数据送到窗口的消息
  33. #define ON_COM_RECEIVE WM_USER + 618  //  WPARAM 端口号
  34. class cnComm   
  35. {
  36. public:
  37. cnComm(bool fAutoBeginThread = true, DWORD dwIOMode = FILE_FLAG_OVERLAPPED)
  38. : _dwIOMode(dwIOMode), _fAutoBeginThread(fAutoBeginThread)
  39. {
  40. Init();
  41. }
  42. virtual ~cnComm()
  43. {
  44. Close();
  45. UnInit();
  46. }
  47. //打开串口 缺省 9600, 8, n, 1
  48. inline bool Open(DWORD dwPort)
  49. {
  50. return Open(dwPort, 9600);
  51. }
  52. //打开串口 缺省 baud_rate, 8, n, 1
  53. inline bool Open(DWORD dwPort, DWORD dwBaudRate)
  54. {
  55. if(dwPort < 1 || dwPort > 1024)
  56. return false;
  57. BindCommPort(dwPort);
  58. if(!OpenCommPort())
  59. return false;
  60. if(!SetupPort())
  61. return false;
  62. return SetState(dwBaudRate);
  63. }
  64. //打开串口, 使用类似"9600, 8, n, 1"的设置字符串设置串口
  65. inline bool Open(DWORD dwPort, char *szSetStr)
  66. {
  67. if(dwPort < 1 || dwPort > 1024)
  68. return false;
  69. BindCommPort(dwPort);
  70. if(!OpenCommPort())
  71. return false;
  72. if(!SetupPort())
  73. return false;
  74. return SetState(szSetStr);
  75. }
  76. //判断串口是或打开
  77. inline bool IsOpen()
  78. {
  79. return _hCommHandle != INVALID_HANDLE_VALUE;
  80. }
  81. //获得串口句炳
  82. inline HANDLE GetHandle()
  83. {
  84. return _hCommHandle;
  85. }
  86. //设置串口参数:波特率,停止位,等 支持设置字符串 "9600, 8, n, 1"
  87. bool SetState(char *szSetStr)
  88. {
  89. if(IsOpen())
  90. {
  91. if(!::GetCommState(_hCommHandle, &_DCB))
  92. return false;
  93. if(!::BuildCommDCB(szSetStr, &_DCB))
  94. return false;
  95. return ::SetCommState(_hCommHandle, &_DCB) == TRUE;
  96. }
  97. return false;
  98. }
  99. //设置串口参数:波特率,停止位
  100. bool SetState(DWORD dwBaudRate, DWORD dwByteSize = 8, DWORD dwParity = NOPARITY, DWORD dwStopBits = ONESTOPBIT)
  101. {
  102. if(IsOpen())
  103. {
  104. if(!::GetCommState(_hCommHandle, &_DCB))
  105. return false;
  106. _DCB.BaudRate = dwBaudRate;
  107.     _DCB.ByteSize = (unsigned char)dwByteSize;
  108.     _DCB.Parity   = (unsigned char)dwParity;
  109. _DCB.StopBits = (unsigned char)dwStopBits;
  110. return ::SetCommState(_hCommHandle, &_DCB) == TRUE;
  111. }
  112. return false;
  113. }
  114. //设置串口的I/O缓冲区大小
  115. bool SetBufferSize(DWORD dwInputSize, DWORD dwOutputSize)
  116. {
  117. if(IsOpen())
  118. return ::SetupComm(_hCommHandle, dwInputSize, dwOutputSize);
  119. return false;
  120. }
  121. //读取串口 dwBufferLength - 1 个字符到 szBuffer 返回实际读到的字符数
  122. DWORD Read(char *szBuffer, DWORD dwBufferLength, DWORD dwWaitTime = 20)
  123. {
  124. if(!IsOpen())
  125. return 0;
  126. szBuffer[0] = '';
  127. COMSTAT  Stat;
  128. DWORD dwError;
  129. if(::ClearCommError(_hCommHandle, &dwError, &Stat) && dwError > 0) //清除错误
  130. {
  131. ::PurgeComm(_hCommHandle, PURGE_RXABORT | PURGE_RXCLEAR); /*清除输入缓冲区*/
  132. return 0;
  133. }
  134. if(!Stat.cbInQue)// 缓冲区无数据
  135. return 0;
  136. unsigned long uReadLength = 0;
  137. dwBufferLength = dwBufferLength - 1 > Stat.cbInQue ? Stat.cbInQue : dwBufferLength - 1;
  138. if(!::ReadFile(_hCommHandle, szBuffer, dwBufferLength, &uReadLength, &_ReadOverlapped)) //2000 下 ReadFile 始终返回 True
  139. {
  140. if(::GetLastError() == ERROR_IO_PENDING) // 结束异步I/O
  141. {
  142. WaitForSingleObject(_ReadOverlapped.hEvent, dwWaitTime); //等待20ms
  143. if(!::GetOverlappedResult(_hCommHandle, &_ReadOverlapped, &uReadLength, false))
  144. {
  145. if(::GetLastError() != ERROR_IO_INCOMPLETE)//其他错误
  146. uReadLength = 0;
  147. }
  148. }
  149. else
  150. uReadLength = 0;
  151. }
  152. szBuffer[uReadLength] = '';
  153. return uReadLength;
  154. }
  155. //写串口 szBuffer
  156. DWORD Write(char *szBuffer, DWORD dwBufferLength)
  157. {
  158. if(!IsOpen())
  159. return 0;
  160. DWORD dwError;
  161. if(::ClearCommError(_hCommHandle, &dwError, NULL) && dwError > 0) //清除错误
  162. ::PurgeComm(_hCommHandle, PURGE_TXABORT | PURGE_TXCLEAR);
  163. unsigned long uWriteLength = 0;
  164. if(!::WriteFile(_hCommHandle, szBuffer, dwBufferLength, &uWriteLength, &_WriteOverlapped))
  165. if(::GetLastError() != ERROR_IO_PENDING)
  166. uWriteLength = 0;
  167. return uWriteLength;
  168. }
  169. //写串口 szBuffer
  170. inline DWORD Write(char *szBuffer)
  171. {
  172. assert(szBuffer);
  173. return Write(szBuffer, (DWORD)strlen(szBuffer));
  174. }
  175. //强制同步写
  176. //  inline DWORD WriteSync(char *szBuffer, DWORD dwBufferLength)
  177. //  {
  178. //  if(!IsOpen())
  179. //  return 0;
  180. // 
  181. //  DWORD dwError;
  182. // 
  183. //  if(::ClearCommError(_hCommHandle, &dwError, NULL) && dwError > 0) //清除错误
  184. //  ::PurgeComm(_hCommHandle, PURGE_TXABORT | PURGE_TXCLEAR);
  185. // 
  186. //  unsigned long uWriteLength = 0;
  187. // 
  188. //  if(!::WriteFile(_hCommHandle, szBuffer, dwBufferLength, &uWriteLength, NULL))
  189. //  if(::GetLastError() != ERROR_IO_PENDING)
  190. //  uWriteLength = 0;
  191. // 
  192. //  return uWriteLength;
  193. //  }
  194. //写串口 szBuffer 可以输出格式字符串
  195. //  DWORD Write(char *szBuffer, DWORD dwBufferLength, char * szFormat, ...)
  196. //  {
  197. //  if(!IsOpen())
  198. //  return 0;
  199. // 
  200. //  DWORD dwError;
  201. // 
  202. //  if(::ClearCommError(_hCommHandle, &dwError, NULL) && dwError > 0) //清除错误
  203. //  ::PurgeComm(_hCommHandle, PURGE_TXABORT | PURGE_TXCLEAR);
  204. // 
  205. //  va_list va;
  206. //  va_start(va, szFormat);
  207. //  _vsnprintf(szBuffer, dwBufferLength, szFormat, va);
  208. //  va_end(va);
  209. // 
  210. //  unsigned long uWriteLength = 0;
  211. // 
  212. //  if(!::WriteFile(_hCommHandle, szBuffer, dwBufferLength, &uWriteLength, &_WriteOverlapped))
  213. //  if(::GetLastError() != ERROR_IO_PENDING)
  214. //  uWriteLength = 0;
  215. // 
  216. //  return uWriteLength;
  217. //  }
  218. //关闭串口
  219. inline virtual void Close()
  220. {
  221. if(IsOpen())
  222. {
  223. EndThread();
  224. ::CloseHandle(_hCommHandle);
  225. _hCommHandle = INVALID_HANDLE_VALUE;
  226. }
  227. }
  228. //设定发送通知, 接受字符最小值
  229. inline void SetNotifyNum(int iNum)
  230. {
  231. _dwNotifyNum = iNum;
  232. }
  233. //送消息的窗口句柄
  234. inline void SetWnd(HWND hWnd)
  235. {
  236. _hNotifyWnd = hWnd;
  237. }
  238. //辅助线程控制 建监视线程
  239. bool BeginThread() 
  240. {
  241. if(!IsThreadRunning()) 
  242. {
  243. _fRunFlag = true;
  244. _hThreadHandle = NULL;
  245. DWORD id;
  246. _hThreadHandle = ::CreateThread(NULL, 0, CommThreadProc, this, 0, &id); //兼容98 故使用&ID
  247. return (_hThreadHandle != NULL); //辅助线程
  248. }
  249. return false;
  250. }
  251. //线程是否运行
  252. inline bool IsThreadRunning()
  253. {
  254. return _hThreadHandle != NULL;
  255. }
  256. //获得线程句柄
  257. inline HANDLE GetThread()
  258. {
  259. return _hThreadHandle;
  260. }
  261. //暂停监视线程
  262. inline bool SuspendThread()
  263. {
  264. return IsThreadRunning() ? ::SuspendThread(_hThreadHandle) != 0xFFFFFFFF : false;
  265. }
  266. //恢复监视线程
  267. inline bool ResumeThread()
  268. {
  269. return IsThreadRunning() ? ::ResumeThread(_hThreadHandle) != 0xFFFFFFFF : false;
  270. }
  271. //终止线程
  272. bool EndThread(DWORD dwWaitTime = 100)
  273. {
  274. if(IsThreadRunning()) 
  275. {
  276. _fRunFlag = false;
  277. ::SetCommMask(_hCommHandle, 0);
  278. ::SetEvent(_WaitOverlapped.hEvent);
  279. if(::WaitForSingleObject(_hThreadHandle, dwWaitTime) != WAIT_OBJECT_0)
  280. if(!::TerminateThread(_hThreadHandle, 0))
  281. return false;
  282. ::CloseHandle(_hThreadHandle);
  283. ::ResetEvent(_WaitOverlapped.hEvent);
  284. _hThreadHandle = NULL;
  285. return true;
  286. }
  287. return false;
  288. }
  289. protected:
  290. volatile DWORD _dwPort;  //串口号
  291. volatile HANDLE _hCommHandle;//串口句柄
  292. char _szCommStr[20];
  293. DCB _DCB;   //波特率,停止位,等
  294. COMMTIMEOUTS _CO;     //超时结构
  295. DWORD _dwIOMode; // 0 同步  默认 FILE_FLAG_OVERLAPPED 重叠I/O 异步
  296. OVERLAPPED _ReadOverlapped, _WriteOverlapped; // 重叠I/O
  297. //线程用
  298. volatile HANDLE _hThreadHandle; //辅助线程
  299. volatile HWND _hNotifyWnd; // 通知窗口
  300. volatile DWORD _dwNotifyNum;//接受多少字节(>_dwNotifyNum)发送通知消息
  301. volatile bool _fRunFlag; //线程运行循环标志
  302. bool _fAutoBeginThread;//Open() 自动 BeginThread();
  303. OVERLAPPED _WaitOverlapped; //WaitCommEvent use
  304. //线程收到消息自动调用, 如窗口句柄有效, 送出消息, 包含窗口编号
  305. virtual void OnReceive()
  306. {
  307. if(_hNotifyWnd)
  308. ::PostMessage(_hNotifyWnd, ON_COM_RECEIVE, WPARAM(_dwPort), LPARAM(0));
  309. }
  310. void Init() //初始化
  311. {
  312. memset(_szCommStr, 0, 20);
  313. memset(&_DCB, 0, sizeof(_DCB));
  314. _DCB.DCBlength = sizeof(_DCB);
  315. _hCommHandle = INVALID_HANDLE_VALUE;
  316. memset(&_ReadOverlapped, 0, sizeof(_ReadOverlapped));
  317. memset(&_WriteOverlapped, 0, sizeof(_WriteOverlapped));
  318. _ReadOverlapped.hEvent = ::CreateEvent(NULL, true, false, NULL);
  319. assert(_ReadOverlapped.hEvent != INVALID_HANDLE_VALUE); 
  320. _WriteOverlapped.hEvent = ::CreateEvent(NULL, true, false, NULL);
  321. assert(_WriteOverlapped.hEvent != INVALID_HANDLE_VALUE);
  322. _dwNotifyNum = 0;
  323. _hNotifyWnd = NULL;
  324. _hThreadHandle = NULL;
  325. memset(&_WaitOverlapped, 0, sizeof(_WaitOverlapped));
  326. _WaitOverlapped.hEvent = ::CreateEvent(NULL, true, false, NULL);
  327. assert(_WaitOverlapped.hEvent != INVALID_HANDLE_VALUE);
  328. }
  329. void UnInit()
  330. {
  331. if(_ReadOverlapped.hEvent != INVALID_HANDLE_VALUE)
  332. CloseHandle(_ReadOverlapped.hEvent);
  333. if(_WriteOverlapped.hEvent != INVALID_HANDLE_VALUE)
  334. CloseHandle(_WriteOverlapped.hEvent);
  335. if(_WaitOverlapped.hEvent != INVALID_HANDLE_VALUE)
  336. CloseHandle(_WaitOverlapped.hEvent);
  337. }
  338. //绑定串口
  339. inline void BindCommPort(DWORD dwPort)
  340. {
  341. assert(dwPort >= 1 && dwPort <= 1024);
  342. char p[5];
  343. _dwPort = dwPort;
  344. strcpy(_szCommStr, "\\.\COM");
  345. ltoa(_dwPort, p, 10);
  346. strcat(_szCommStr, p);
  347. }
  348. //打开串口
  349. virtual bool OpenCommPort()
  350. {
  351. if(IsOpen())
  352. Close();
  353. _hCommHandle = ::CreateFile(
  354. _szCommStr,
  355. GENERIC_READ | GENERIC_WRITE,
  356. 0,
  357. NULL,
  358. OPEN_EXISTING,
  359. FILE_ATTRIBUTE_NORMAL | _dwIOMode,
  360. NULL
  361. );
  362. if(_fAutoBeginThread)
  363. {
  364. if(IsOpen() && BeginThread())
  365. return true;
  366. else
  367. {
  368. Close(); //创建线程失败
  369. return false;
  370. }
  371. }
  372. return IsOpen();//检测串口是否成功打开
  373. }
  374. //设置串口
  375. virtual bool SetupPort()
  376. {
  377. if(!IsOpen())
  378. return false;
  379. //设置推荐缓冲区
  380. if(!::SetupComm(_hCommHandle, 4096, 4096))
  381. return false;
  382. //设置超时时间
  383. if(!::GetCommTimeouts(_hCommHandle, &_CO))
  384. return false;
  385. _CO.ReadIntervalTimeout = 0xFFFFFFFF;
  386. _CO.ReadTotalTimeoutMultiplier = 0;
  387. _CO.ReadTotalTimeoutConstant = 0;
  388. _CO.WriteTotalTimeoutMultiplier = 0;
  389. _CO.WriteTotalTimeoutConstant = 2000;
  390. if(!::SetCommTimeouts(_hCommHandle, &_CO))
  391. return false;
  392. //清空串口缓冲区
  393. if(!::PurgeComm(_hCommHandle, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR ))
  394. return false;
  395. return true;
  396. }
  397. private:
  398. //监视线程
  399. static DWORD WINAPI CommThreadProc(LPVOID lpPara)
  400. {
  401. cnComm *pComm = (cnComm *)lpPara;
  402.         if(!::SetCommMask(pComm->_hCommHandle, EV_RXCHAR | EV_ERR))
  403. return 1;
  404. COMSTAT Stat;
  405. DWORD dwError;
  406. for(DWORD dwLength, dwMask = 0; pComm->_fRunFlag && pComm->IsOpen(); dwMask = 0)
  407. {
  408. if(!::WaitCommEvent(pComm->_hCommHandle, &dwMask, &pComm->_WaitOverlapped))
  409. {
  410. if(::GetLastError() == ERROR_IO_PENDING)
  411. {
  412. ::GetOverlappedResult(pComm->_hCommHandle, &pComm->_WaitOverlapped, &dwLength, TRUE);
  413. }
  414. }
  415. if(dwMask & EV_ERR) // == EV_ERR
  416. ::ClearCommError(pComm->_hCommHandle, &dwError, &Stat);
  417. if(dwMask & EV_RXCHAR) // == EV_RXCHAR
  418. {
  419. ::ClearCommError(pComm->_hCommHandle, &dwError, &Stat);
  420. if(Stat.cbInQue > pComm->_dwNotifyNum)
  421. pComm->OnReceive();
  422. }
  423.         }
  424. return 0;
  425. }
  426. };
  427. #endif //_CN_COMM_H_