串口初始化
串口创建之后,必须初始化,初始化包括:波特率,DCB,Timeout,Mask。
其中Mask是非常重要的一环,必须设定,否则在Windows中,很可能异步操作模式收不到事件回调。
例如EV_RXCHAR设定之后,一旦串口收到EV_RXCHAR,就会在重叠I/O上触发一个事件,这样就可以在Event中产生一个wrSignaled信号,提醒程序读取数据了。
procedure InitCom(sCom: PChar; hCom: THandle);
var
dcb: TDCB;
ComStat: TComStat;
Errors: DWORD;
ctr: _COMMTIMEOUTS;
begin
if hCom = INVALID_HANDLE_VALUE then Exit;
PurgeComm(hCom, PURGE_TXCLEAR or PURGE_RXCLEAR or PURGE_RXABORT or PURGE_TXABORT);
if not SetupComm(hCom, 1, 1) then
begin
FillChar(ComStat, SizeOf(ComStat), 0);
ClearCommError(hCom, Errors, @ComStat);
end;
GetCommState(hCom, dcb);
with dcb do
begin
BaudRate := CBR_115200;
Parity := NOPARITY;
StopBits := ONESTOPBIT;
ByteSize := 8;
XonChar := #17;
XoffChar := #19;
ErrorChar := #0;
EofChar := #0;
EvtChar := #0;
XonLim := 10;
XoffLim := 10;
Flags := 1 or DTR_CONTROL_ENABLE or $80 or RTS_CONTROL_ENABLE or $00004000;
end;
SetCommState(hCom, dcb);
FillChar(ctr, SizeOf(ctr), 0);
ctr.ReadIntervalTimeout := MAXDWORD;
SetCommTimeouts(hCom, ctr);
SetCommMask(hCom, EV_RXCHAR or EV_RXFLAG or EV_TXEMPTY or EV_CTS or EV_DSR or EV_RLSD or EV_ERR or EV_RING);
end;
// 读取窗口,异步模式,超时等待,只要在Timeeout时间内有数据读取即返回
function ReadCom(hCom: THandle; const Timeout: Integer = 200): string;
var
FRet: array[0..1023] of char;
R : DWORD;
ol: TOverlapped;
E : TEvent;
idx : DWORD;
wr: TWaitResult;
begin
Result := '';
FillChar(FRet, SizeOf(FRet), 0);
E := TEvent.Create(nil, True, False, '');
ol.hEvent := E.Handle;
R := 0;
idx := 0;
if not ReadFile(hCom, FRet[0], SizeOf(FRet), idx, @ol) then
begin
if GetLastError = ERROR_IO_PENDING then
begin
wr := E.WaitFor(Timeout);
case wr of
wrSignaled:
repeat // 不断循环读取直到读取完成为止
// 必须设定bWait为False,否则会阻塞
GetOverlappedResult(hCom, ol, R, False);
Inc(idx, R);
if R = 0 then Break;
ReadFile(hCom, FRet[idx], SizeOf(FRet), R, @ol);
Sleep(500);
until False;
wrTimeout, wrAbandoned, wrError:
begin
// 必须设定bWait为False,否则会阻塞
GetOverlappedResult(hCom, ol, R, False);
Inc(idx, R);
ReadFile(hCom, FRet[idx], SizeOf(FRet), R, @ol);
end
else
//
end;
end;
end;
SetString(Result, FRet, idx);
end;
// 写串口,重叠IO,异步IO模式
function WriteCom(hCom: THandle; Data: string; const Timeout: Integer = 100): Boolean;
var
R: DWORD;
ol: TOverlapped;
E : TEvent;
wr: TWaitResult;
begin
FillChar(ol, SizeOf(ol), 0);
E := TEvent.Create(nil, True, False, '');
ol.hEvent := E.Handle;
PurgeComm(hCom, PURGE_TXCLEAR or PURGE_RXCLEAR or PURGE_RXABORT or PURGE_TXABORT);
if not WriteFile(hCom, PChar(Data)^, Length(Data), R, @ol) then
begin
if GetLastError = ERROR_IO_PENDING then
begin
wr := E.WaitFor(Timeout);
case wr of
wrSignaled: GetOverlappedResult(hCom, ol, R, True);
wrTimeout: ;
wrAbandoned: ;
wrError: ;
end;
end;
end;
Result := DWORD(Length(Data)) = R;
end;