串口类的编写

CSerial类只有2个文件,分别是CSerial.cpp和CSerial.h。

 

CSerial.h内容如下:

 

1 /***************************************************
2 *作 者:温子祺
3 *联系方式:wenziqi@hotmail.com
4 *说 明:CSerial.h
5 提供外部调用的函数
6 Open(),Close(),Send()
7 接收数据时通过消息来实现
8 ***************************************************/
9 #ifndef __CSERIAL_H__
10  #define __CSERIAL_H__
11  #pragma once
12
13  class CSerial
14 {
15  public:
16 CSerial(void);
17 virtual~CSerial(void);
18
19 BOOL Open(CWnd *pPortOwner,
20 UINT portnr,
21 UINT baud,
22 UINT parity,
23 UINT databits,
24 UINT stopbits,
25 UINT rxdmsg);
26
27 BOOL Close(void);
28
29 UINT Send(UCHAR *pbuf,UINT len);
30
31  protected:
32
33 BOOL Ready(void) const;
34 BOOL CreateThreadAndEvent(void);
35  static
36 DWORD RecvThread(LPVOID lpArg);
37
38 private:
39 CWnd * m_pOwner;
40 BOOL m_bInit;
41
42 HANDLE m_hSerial;
43 HANDLE m_hRecvEvent;
44 HANDLE m_hRecvExitEvent;
45
46 UINT m_unRxdMsg;
47 };
48 #endif

 

CSerial.cpp代码如下:

 

1 /***************************************************
2 *作 者:温子祺
3 *联系方式:wenziqi@hotmail.com
4 *说 明:CSerial.cpp
5 提供外部调用的函数
6 Open(),Close(),Send()
7 接收数据时通过消息来实现
8 ***************************************************/
9 #include "StdAfx.h"
10 #include "CSerial.h"
11 #include <assert.h> //使用断言
12
13 CSerial::CSerial(void)
14 {
15 m_pOwner=NULL;
16 m_bInit=FALSE;
17 m_hRecvEvent=NULL;
18 m_hRecvExitEvent=NULL;
19 m_hSerial=NULL;
20 m_bInit=FALSE;
21 }
22
23 CSerial::~CSerial(void)
24 {
25 Close();
26 }
27
28 BOOL CSerial::Ready(void)const
29 {
30 return m_bInit;
31 }
32
33 BOOL CSerial::Close(void)
34 {
35
36 if (m_hSerial)
37 {
38 CloseHandle(m_hSerial);
39 m_hSerial=NULL;
40 }
41
42 if (m_hRecvEvent)
43 {
44 CloseHandle(m_hRecvEvent);
45 m_hRecvEvent=NULL;
46 }
47
48 if (m_hRecvExitEvent)
49 {
50 SetEvent(m_hRecvExitEvent); //退出线程
51 Sleep(10);
52 CloseHandle(m_hRecvExitEvent);
53 m_hRecvExitEvent=NULL;
54 }
55
56 if (m_bInit)
57 {
58 m_bInit=FALSE;
59 }
60
61 if (m_pOwner)
62 {
63 m_pOwner=NULL;
64 }
65
66 return TRUE;
67 }
68
69 BOOL CSerial::Open(CWnd *pPortOwner,
70 UINT portnr,
71 UINT baud,
72 UINT parity,
73 UINT databits,
74 UINT stopbits,
75 UINT rxdmsg)
76 {
77 assert(NULL != pPortOwner);
78
79 m_pOwner = pPortOwner;
80
81 if (Ready())
82 {
83 Close();
84 }
85
86 COMMTIMEOUTS CommTimeOuts;
87 DCB dcb;
88
89 LPSTR sz= new CHAR[64];
90 LPWSTR wsz= new WCHAR[64];
91
92 // 打开串口
93 //wprintf_s(wsz,64,"COM%d",portnr);//用wprintf无效
94 sprintf_s(sz,64,"COM%d",portnr);
95 MultiByteToWideChar(CP_ACP,
96 0,
97 sz,
98 64,
99 wsz,
100 64);
101
102 m_hSerial = CreateFile(wsz,
103 GENERIC_READ | GENERIC_WRITE,
104 0,
105 0,
106 OPEN_EXISTING,
107 0,
108 0);
109
110 delete []sz;
111 delete []wsz;
112
113 if(m_hSerial == INVALID_HANDLE_VALUE)
114 {
115 return FALSE;
116 }
117
118 GetCommState(m_hSerial, &dcb); /* 读取串口的DCB */
119 dcb.BaudRate = baud; //波特率
120 dcb.ByteSize = databits; //数据位
121 dcb.Parity = parity; //校验位
122 dcb.StopBits = stopbits; //停止位
123
124 dcb.fParity = FALSE; /* 禁止奇偶校验 */
125 dcb.fBinary = TRUE;
126 dcb.fDtrControl = 0; /* 禁止流量控制 */
127 dcb.fRtsControl = 0;
128 dcb.fOutX = 0;
129 dcb.fInX = 0;
130 dcb.fTXContinueOnXoff = 0;
131 dcb.EvtChar='q'; // 这个一定要,否则大于127的数值会接收不了啊
132
133 //设置状态参数
134 SetCommMask(m_hSerial, EV_RXFLAG|EV_RXCHAR); /* 串口事件:接收到一个字符 */
135 SetupComm(m_hSerial, 1024, 1024); /* 设置接收与发送的缓冲区大小 */
136
137 if(!SetCommState(m_hSerial, &dcb)) /* 设置串口的DCB */
138 {
139 return FALSE;
140 }
141
142 //设置超时参数
143 GetCommTimeouts(m_hSerial, &CommTimeOuts);
144 CommTimeOuts.ReadIntervalTimeout = 100; /* 接收字符间最大时间间隔 */
145 CommTimeOuts.ReadTotalTimeoutMultiplier = 1;
146 CommTimeOuts.ReadTotalTimeoutConstant = 100; /* 读数据总超时常量 */
147 CommTimeOuts.WriteTotalTimeoutMultiplier = 0;
148 CommTimeOuts.WriteTotalTimeoutConstant = 0;
149
150 if(!SetCommTimeouts(m_hSerial, &CommTimeOuts))
151 {
152 return FALSE;
153 }
154
155 PurgeComm(m_hSerial, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT); /* 清除收/发缓冲区 */
156
157 if (!CreateThreadAndEvent())
158 {
159 return FALSE;
160 }
161
162 m_unRxdMsg=rxdmsg;
163
164 m_bInit = TRUE;
165
166 return TRUE;
167 }
168 BOOL CSerial::CreateThreadAndEvent(void)
169 {
170 m_hRecvExitEvent = CreateEvent(NULL, TRUE, FALSE, NULL); /* 创建串口接收线程退出事件*/
171
172 if (NULL==m_hRecvExitEvent)
173 {
174 return FALSE;
175 }
176
177 ResetEvent(m_hRecvExitEvent); //设置线程没有退出
178
179 HANDLE hRecvThread=NULL;
180 DWORD dwThreadID =0;
181
182 // 创建串口接收线程
183 hRecvThread=CreateThread(0,
184 0,
185 (LPTHREAD_START_ROUTINE)RecvThread,
186 this,
187 0,
188 &dwThreadID);
189
190 if (NULL==hRecvThread)
191 {
192 return FALSE;
193 }
194
195 CloseHandle(hRecvThread);
196 hRecvThread=NULL;
197
198 return TRUE;
199 }
200
201 UINT CSerial::Send(UCHAR *pbuf,UINT len)
202 {
203 if (!Ready())
204 {
205 //AfxMessageBox(_T("请确保串口已正常打开"));
206 return 0;
207 }
208
209 BOOL rt=FALSE;
210
211 DWORD dwBytesSend=0,dwCnt=0;
212
213 while (len>dwCnt)
214 {
215 rt=WriteFile(m_hSerial,pbuf+dwCnt,len-dwCnt,&dwBytesSend,NULL);
216
217 if (!rt)
218 {
219 return FALSE;
220 }
221
222 dwCnt+=dwBytesSend;
223
224 if (len > dwCnt)
225 {
226 Sleep(100); //有可能I/O挂起
227 }
228 }
229
230 return (UINT)dwCnt;
231 }
232
233 DWORD CSerial::RecvThread(LPVOID lpArg)
234 {
235
236 assert(NULL != lpArg);
237
238 CSerial *pArg=(CSerial *)lpArg;
239
240 assert(NULL != pArg);
241
242 DWORD dwBytesRecv=0;
243 DWORD dwError=0;
244 UCHAR ucDat=0;
245 COMSTAT ComStat;
246
247 memset(&ComStat,0,sizeof(ComStat));
248
249 while (1)
250 {
251 if (WaitForSingleObject(pArg->m_hRecvExitEvent,0)==WAIT_OBJECT_0)
252 {
253 break; //线程退出
254 }
255
256 if (pArg->Ready())
257 {
258 ClearCommError(pArg->m_hSerial,&dwError,&ComStat);
259
260 if (0 == ComStat.cbInQue)
261 {
262 Sleep(1);
263 continue;
264 }
265
266 if (ReadFile(pArg->m_hSerial,&ucDat,1,&dwBytesRecv,NULL))
267 {
268 if (dwBytesRecv)
269 {
270 ::SendMessage((pArg->m_pOwner)->m_hWnd,
271 pArg->m_unRxdMsg,
272 (WPARAM)ucDat,
273 NULL);
274 }
275 }
276 }
277
278 Sleep(1);
279
280 }
281
282 Sleep(10); //让线程安全退出
283
284 return 0;
285 }
286

 

 

posted @ 2010-07-01 14:57  温子祺  阅读(3059)  评论(1编辑  收藏  举报