提交 | 用户 | age
|
4b03ae
|
1 |
#pragma once
|
Q |
2 |
/*
|
|
3 |
*
|
|
4 |
* 串口通讯头文件
|
|
5 |
*
|
|
6 |
* Version: V1.01
|
|
7 |
* Date: 2015-06-30
|
|
8 |
* Description:
|
|
9 |
* 2015-07-10 Add Speed Function;
|
|
10 |
* 2015-07-24 优化速度计算,每1秒一次改为每半秒一次
|
|
11 |
*/
|
|
12 |
inline double GetTimeMs()
|
|
13 |
{
|
|
14 |
LARGE_INTEGER perfreq;
|
|
15 |
LARGE_INTEGER percounter1;
|
|
16 |
QueryPerformanceFrequency(&perfreq);
|
|
17 |
QueryPerformanceCounter(&percounter1);
|
|
18 |
|
|
19 |
double time1=(double)percounter1.QuadPart/perfreq.QuadPart;
|
|
20 |
return (time1*1000);
|
|
21 |
};
|
|
22 |
|
|
23 |
class CSerialCom
|
|
24 |
{
|
|
25 |
public:
|
|
26 |
enum Results {
|
|
27 |
R_OK,
|
|
28 |
R_ERR,
|
|
29 |
};
|
|
30 |
HANDLE hCom1;
|
|
31 |
int IsOpened;
|
|
32 |
|
|
33 |
int Port;
|
|
34 |
int BaudRate;
|
|
35 |
CString Settings;
|
|
36 |
|
|
37 |
DWORD dwError;
|
|
38 |
CString strResult;
|
|
39 |
int m_nCountToTry = 2;
|
|
40 |
int m_nCountToWait = 0;
|
|
41 |
|
|
42 |
volatile DWORD TotalSendBytes,TotalRecvBytes;
|
|
43 |
volatile DWORD SendBytes,RecvBytes;
|
|
44 |
volatile DWORD LastSendBytes,LastRecvBytes;
|
|
45 |
volatile DWORD SendSpeed,RecvSpeed;
|
|
46 |
volatile double LastTime;
|
|
47 |
CSerialCom(void)
|
|
48 |
{
|
|
49 |
this->hCom1=INVALID_HANDLE_VALUE;
|
|
50 |
this->IsOpened=0;
|
|
51 |
|
|
52 |
this->Port=0;
|
|
53 |
this->BaudRate=0;
|
|
54 |
this->Settings.Empty();
|
|
55 |
|
|
56 |
this->dwError=0;
|
|
57 |
};
|
|
58 |
~CSerialCom(void)
|
|
59 |
{
|
|
60 |
if (this->IsOpened) {this->Close();}
|
|
61 |
this->hCom1=INVALID_HANDLE_VALUE;
|
|
62 |
};
|
|
63 |
|
|
64 |
int Open()
|
|
65 |
{
|
|
66 |
int j;
|
|
67 |
CString s1,s2;
|
|
68 |
CString ComPortName;
|
|
69 |
if (this->Port==0) {return 0;}
|
|
70 |
if (this->IsOpened) {return -1;}
|
|
71 |
ComPortName.Format(_T("\\\\.\\COM%d"),this->Port);
|
|
72 |
hCom1=CreateFile(ComPortName,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);//FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED
|
|
73 |
if (hCom1==INVALID_HANDLE_VALUE)
|
|
74 |
{
|
|
75 |
dwError=GetLastError();
|
|
76 |
IsOpened=false;
|
|
77 |
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,0,dwError,0,s1.GetBuffer(2048),2048,NULL);
|
|
78 |
s1.ReleaseBuffer();
|
|
79 |
|
|
80 |
strResult.Format(_T("Open COM%d Err %d ,%s "),this->Port,this->dwError,s1);
|
|
81 |
return 0;
|
|
82 |
}
|
|
83 |
else
|
|
84 |
{
|
|
85 |
dwError=GetLastError();
|
|
86 |
|
|
87 |
strResult.Format(_T("COM%d OK."),this->Port);
|
|
88 |
LastTime = GetTimeMs();
|
|
89 |
TotalSendBytes = 0; TotalRecvBytes = 0;
|
|
90 |
LastSendBytes = 0; SendBytes = 0; RecvBytes = 0;
|
|
91 |
LastRecvBytes = 0; SendSpeed = 0; RecvSpeed = 0;
|
|
92 |
}
|
|
93 |
|
|
94 |
j=SetupComm(hCom1,256,256);
|
|
95 |
|
|
96 |
DCB dcb1;
|
|
97 |
j=GetCommState(hCom1,&dcb1);
|
|
98 |
BuildCommDCB(Settings,&dcb1);
|
|
99 |
|
|
100 |
dcb1.BaudRate=BaudRate;
|
|
101 |
|
|
102 |
if (Settings.Find(_T("8")) != -1) { dcb1.ByteSize = 8; }
|
|
103 |
else if (Settings.Find(_T("7")) != -1) { dcb1.ByteSize = 8; }
|
|
104 |
else if (Settings.Find(_T("6")) != -1) { dcb1.ByteSize = 8; }
|
|
105 |
else if (Settings.Find(_T("5")) != -1) { dcb1.ByteSize = 8; }
|
|
106 |
|
|
107 |
if (Settings.Find(_T("N")) != -1) { dcb1.fParity = FALSE; dcb1.Parity = NOPARITY;}
|
|
108 |
else if (Settings.Find(_T("O")) != -1) { dcb1.fParity = TRUE; dcb1.Parity = ODDPARITY;}
|
|
109 |
else if (Settings.Find(_T("E")) != -1) { dcb1.fParity = TRUE; dcb1.Parity = EVENPARITY;}
|
|
110 |
else if (Settings.Find(_T("M")) != -1) { dcb1.fParity = TRUE; dcb1.Parity = MARKPARITY;}
|
|
111 |
else if (Settings.Find(_T("S")) != -1) { dcb1.fParity = TRUE; dcb1.Parity = SPACEPARITY;}
|
|
112 |
|
|
113 |
if (Settings.Find(_T("1.5")) != -1) { dcb1.StopBits = ONE5STOPBITS;}
|
|
114 |
else if (Settings.Find(_T("1")) != -1) { dcb1.StopBits = ONESTOPBIT; }
|
|
115 |
else if (Settings.Find(_T("2")) != -1) { dcb1.StopBits = TWOSTOPBITS; }
|
|
116 |
|
|
117 |
dcb1.fDtrControl=0;
|
|
118 |
dcb1.fDsrSensitivity=false;
|
|
119 |
dcb1.fBinary=1;
|
|
120 |
dcb1.fOutxCtsFlow=false;
|
|
121 |
dcb1.fOutxDsrFlow=false;
|
|
122 |
dcb1.fRtsControl=RTS_CONTROL_DISABLE;
|
|
123 |
|
|
124 |
j=SetCommState(hCom1,&dcb1);
|
|
125 |
if (j == 0)
|
|
126 |
{
|
|
127 |
strResult.Format(_T("SetCommState Fail %d %s \r\n"),BaudRate,Settings);
|
|
128 |
CloseHandle(hCom1);
|
|
129 |
IsOpened = false;
|
|
130 |
return 0;
|
|
131 |
}
|
|
132 |
j=GetCommState(hCom1,&dcb1);
|
|
133 |
|
|
134 |
CString strParity;
|
|
135 |
CString strStopBit;
|
|
136 |
|
|
137 |
if (dcb1.Parity == NOPARITY) { strParity = _T("N"); }
|
|
138 |
else if (dcb1.Parity == EVENPARITY) { strParity = _T("E"); }
|
|
139 |
else if (dcb1.Parity == ODDPARITY) { strParity = _T("O"); }
|
|
140 |
else if (dcb1.Parity == MARKPARITY) { strParity = _T("M"); }
|
|
141 |
else if (dcb1.Parity == SPACEPARITY) { strParity = _T("S"); }
|
|
142 |
else { strParity = _T("X"); }
|
|
143 |
|
|
144 |
if (dcb1.StopBits == ONESTOPBIT) { strStopBit = _T("1"); }
|
|
145 |
else if (dcb1.StopBits == ONE5STOPBITS) { strStopBit = _T("1.5"); }
|
|
146 |
else if (dcb1.StopBits == TWOSTOPBITS) { strStopBit = _T("2"); }
|
|
147 |
else { strStopBit = _T("3"); }
|
|
148 |
|
|
149 |
s1.Format(_T("%d %d-%s-%s"), dcb1.BaudRate,dcb1.ByteSize, strParity, strStopBit);
|
|
150 |
strResult += s1;
|
|
151 |
|
|
152 |
COMMTIMEOUTS comtimeout1;
|
|
153 |
COMSTAT comstat1;
|
|
154 |
GetCommTimeouts(hCom1,&comtimeout1);
|
|
155 |
|
|
156 |
comtimeout1.ReadIntervalTimeout=1; //两个字符之间的时间
|
|
157 |
comtimeout1.ReadTotalTimeoutMultiplier=0; //每个字符等待的时间,读多个字符则等待时间为单个时间乘以字符个数
|
|
158 |
comtimeout1.ReadTotalTimeoutConstant=1; //读取时,再另外多等待的时间。
|
|
159 |
comtimeout1.WriteTotalTimeoutMultiplier=0; //写入时,每个字符等待的时间,写入多个字符则等待时间为单个时间乘以字符个数。
|
|
160 |
comtimeout1.WriteTotalTimeoutConstant=0; //写入时,再另外多等待的时间。
|
|
161 |
|
|
162 |
SetCommTimeouts(hCom1,&comtimeout1);
|
|
163 |
j=ClearCommError(hCom1,&dwError,&comstat1);
|
|
164 |
s1.Format(_T("ClearCommError j %d errors %d "),j,dwError);
|
|
165 |
s2=s1;
|
|
166 |
s1.Format(_T("cbInQue %d "),comstat1.cbInQue);
|
|
167 |
s2+=s1;
|
|
168 |
s1.Format(_T("cbOutQue %d "),comstat1.cbOutQue );
|
|
169 |
s2+=s1;
|
|
170 |
|
|
171 |
PurgeComm(hCom1,PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_TXCLEAR);
|
|
172 |
|
|
173 |
IsOpened = true;
|
|
174 |
return 1;
|
|
175 |
};
|
|
176 |
int Purge()
|
|
177 |
{
|
|
178 |
return PurgeComm(hCom1,PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_TXCLEAR);
|
|
179 |
}
|
|
180 |
void Close()
|
|
181 |
{
|
|
182 |
LastSendBytes=0;
|
|
183 |
LastRecvBytes=0;
|
|
184 |
SendBytes=0;
|
|
185 |
RecvBytes=0;
|
|
186 |
SendSpeed=0;
|
|
187 |
RecvSpeed=0;
|
|
188 |
|
|
189 |
if (IsOpened)
|
|
190 |
{
|
|
191 |
IsOpened=false;
|
|
192 |
CString s1;
|
|
193 |
strResult.Format(_T("Close COM %d "),this->Port);
|
|
194 |
CloseHandle(hCom1);
|
|
195 |
}
|
|
196 |
};
|
|
197 |
int CSerialCom::CalSpeed()
|
|
198 |
{
|
|
199 |
double thistime = GetTimeMs();
|
|
200 |
double diftime = thistime - LastTime;
|
|
201 |
if (diftime >= 500)
|
|
202 |
{
|
|
203 |
SendSpeed = (DWORD)(SendBytes * 1000 / diftime);
|
|
204 |
RecvSpeed = static_cast<DWORD> (RecvBytes * 1000 / diftime);
|
|
205 |
LastSendBytes = SendBytes; SendBytes = 0;
|
|
206 |
LastRecvBytes = RecvBytes; RecvBytes = 0;
|
|
207 |
LastTime = thistime;
|
|
208 |
}
|
|
209 |
return 0;
|
|
210 |
}
|
|
211 |
int CSerialCom::Send(const char * buffer, int n)
|
|
212 |
{
|
|
213 |
CString s1;
|
|
214 |
int i,j;
|
|
215 |
DWORD numsent;
|
|
216 |
|
|
217 |
if (!IsOpened) {return 0;}
|
|
218 |
|
|
219 |
j=WriteFile(hCom1,buffer,n,&numsent,NULL);
|
|
220 |
|
|
221 |
if (j!=0)
|
|
222 |
{
|
|
223 |
strResult.Format(_T("Send To COM%d OK %dB : "),this->Port,numsent);
|
|
224 |
for (i=0;(unsigned )i<numsent;i++)
|
|
225 |
{
|
|
226 |
strResult.AppendFormat(_T("%c"),buffer[i]);
|
|
227 |
}
|
|
228 |
strResult.AppendFormat(_T("\r\n"));
|
|
229 |
}
|
|
230 |
else
|
|
231 |
{
|
|
232 |
dwError=GetLastError();
|
|
233 |
strResult.Format(_T("Send To COM%d fail. Error:%d SentBytes:%d "),this->Port,dwError,numsent);
|
|
234 |
}
|
|
235 |
SendBytes+=numsent;
|
|
236 |
TotalSendBytes+=numsent;
|
|
237 |
return numsent;
|
|
238 |
};
|
|
239 |
int CSerialCom::Read(char * buffer, int numToRead)
|
|
240 |
{
|
|
241 |
CString s1;
|
|
242 |
int i,j;
|
|
243 |
DWORD numreaded;
|
|
244 |
if (!IsOpened) {return 0;}
|
|
245 |
int len2=0;
|
|
246 |
//Sleep(n/10);
|
|
247 |
int nTryCount2 = 0;
|
|
248 |
for (int i = 0; i < m_nCountToTry; i++)
|
|
249 |
{
|
|
250 |
j = ReadFile(hCom1, buffer+len2, numToRead-len2, &numreaded, NULL);
|
|
251 |
if (j != 0){
|
|
252 |
len2 += numreaded;
|
|
253 |
buffer[len2] = 0;
|
|
254 |
if (len2 >= numToRead) break;
|
|
255 |
nTryCount2 = 0;
|
|
256 |
}
|
|
257 |
else{
|
|
258 |
if (len2 > 0) {
|
|
259 |
nTryCount2++;
|
|
260 |
if (nTryCount2 >= m_nCountToWait) break;
|
|
261 |
}
|
|
262 |
}
|
|
263 |
if (len2 > 0 && nTryCount2 >= m_nCountToWait) break;
|
|
264 |
}
|
|
265 |
numreaded = len2;
|
|
266 |
if (numreaded > 0){
|
|
267 |
strResult.Format(_T("Read From COM%d OK %dB "), this->Port, numreaded);
|
|
268 |
for (i = 0; (unsigned)i < numreaded; i++)
|
|
269 |
{
|
|
270 |
strResult.AppendFormat(_T("%c"), buffer[i]);
|
|
271 |
}
|
|
272 |
strResult.AppendFormat(_T("\r\n"));
|
|
273 |
}
|
|
274 |
else{
|
|
275 |
strResult.Format(_T("Read From COM failed \r\n"));
|
|
276 |
}
|
|
277 |
|
|
278 |
RecvBytes+=numreaded;
|
|
279 |
TotalRecvBytes+=numreaded;
|
|
280 |
|
|
281 |
return numreaded;
|
|
282 |
};
|
|
283 |
};
|
|
284 |
/*
|
|
285 |
与以往DOS下串行通信程序不同的是,Windows不提倡应用程序直接控制硬件,而是通过Windows操作系统提供的设备驱动程序来进行数据传递。
|
|
286 |
串行口在Win 32中是作为文件来进行处理的,而不是直接对端口进行操作,对于串行通信,Win 32 提供了相应的文件I/O函数与通信函数,
|
|
287 |
通过了解这些函数的使用,可以编制出符合不同需要的通信程序。
|
|
288 |
与通信设备相关的结构有COMMCONFIG ,COMMPROP,COMMTIMEOUTS,COMSTAT,DCB,MODEMDEVCAPS,MODEMSETTINGS共7个,
|
|
289 |
与通信有关的Windows API函数共有26个,详细说明可参考MSDN帮助文件。以下将结合实例,给出实现串行通信的三种方法。
|
|
290 |
|
|
291 |
*/
|
|
292 |
|